From 9b983441d71cadd9f85ebdcad7e5dd9bfde72443 Mon Sep 17 00:00:00 2001
From: t8y2 <1156263951@qq.com>
Date: Thu, 13 Aug 2026 18:24:10 +0000
Subject: [PATCH] fix(chromadb): honor cloud tenant and database
Closes #4486
---
.../src/components/layout/ContentArea.vue | 3 +-
.../src/components/vector/VectorBrowser.vue | 12 +-
.../vector/__tests__/VectorBrowser.spec.ts | 28 ++-
apps/desktop/src/stores/connectionStore.ts | 2 +-
crates/dbx-core/src/agent_tools.rs | 44 +++--
crates/dbx-core/src/db/vector_driver.rs | 184 ++++++++++++++----
src-tauri/src/commands/connection.rs | 6 +-
7 files changed, 217 insertions(+), 62 deletions(-)
diff --git a/apps/desktop/src/components/layout/ContentArea.vue b/apps/desktop/src/components/layout/ContentArea.vue
index 8d4396e336..3a331f26d1 100644
--- a/apps/desktop/src/components/layout/ContentArea.vue
+++ b/apps/desktop/src/components/layout/ContentArea.vue
@@ -292,6 +292,7 @@ const activeResultConnectionId = computed(() => activeResultExecutionTarget.valu
const activeResultDatabase = computed(() => activeResultExecutionTarget.value?.database ?? props.activeTab.database);
const activeResultSchema = computed(() => activeResultExecutionTarget.value?.schema ?? props.activeTab.schema);
const activeEffectiveDatabaseType = computed(() => effectiveDatabaseTypeForConnection(activeResultConnection.value));
+const activeVectorConnection = computed(() => connectionStore.getConfig(props.activeTab.connectionId) ?? props.activeConnection);
const activeDataTabExecutionDatabase = computed(() => dataTabExecutionDatabase(props.activeConnection, props.activeTab.database, activeDataTabTableMeta.value?.catalog));
const activeProductionContext = computed(() => productionContextForDatabase(props.activeConnection, props.activeTab.database));
const productionWatermarkText = computed(() => (locale.value.startsWith("zh") ? "生产环境" : "PROD"));
@@ -2071,7 +2072,7 @@ defineExpose({ focusSearch, refreshData, refreshQueryEditorCompletionCache, hand
-
+
diff --git a/apps/desktop/src/components/vector/VectorBrowser.vue b/apps/desktop/src/components/vector/VectorBrowser.vue
index aadd2286aa..e29ed8df9a 100644
--- a/apps/desktop/src/components/vector/VectorBrowser.vue
+++ b/apps/desktop/src/components/vector/VectorBrowser.vue
@@ -21,6 +21,7 @@ const props = defineProps<{
collectionLabel?: string;
databaseType?: DatabaseType;
dimension?: number;
+ tenant?: string;
}>();
const loading = ref(false);
@@ -248,16 +249,19 @@ function defaultRequestText(databaseType: DatabaseType | undefined, database: st
}
if (databaseType === "chromadb") {
const collectionId = collection || "collection-id";
+ const tenant = encodeURIComponent(props.tenant?.trim() || "default_tenant");
+ const chromaDatabase = encodeURIComponent(database.trim() || "default_database");
+ const collectionPath = `/api/v2/tenants/${tenant}/databases/${chromaDatabase}/collections/${encodeURIComponent(collectionId)}`;
if (mode === "delete") {
- return `POST /api/v2/tenants/default_tenant/databases/default_database/collections/${encodeURIComponent(collectionId)}/delete\n${JSON.stringify({ ids: ["id1"] }, null, 2)}`;
+ return `POST ${collectionPath}/delete\n${JSON.stringify({ ids: ["id1"] }, null, 2)}`;
}
if (mode === "upsert") {
- return `POST /api/v2/tenants/default_tenant/databases/default_database/collections/${encodeURIComponent(collectionId)}/upsert\n${JSON.stringify({ ids: ["id1"], embeddings: [sampleVector()], documents: ["sample document"], metadatas: [{}] }, null, 2)}`;
+ return `POST ${collectionPath}/upsert\n${JSON.stringify({ ids: ["id1"], embeddings: [sampleVector()], documents: ["sample document"], metadatas: [{}] }, null, 2)}`;
}
if (mode === "search") {
- return `POST /api/v2/tenants/default_tenant/databases/default_database/collections/${encodeURIComponent(collectionId)}/query\n${JSON.stringify({ query_embeddings: [tryParseVector(searchVector.value)], n_results: searchTopK.value, include: ["documents", "metadatas", "distances"] }, null, 2)}`;
+ return `POST ${collectionPath}/query\n${JSON.stringify({ query_embeddings: [tryParseVector(searchVector.value)], n_results: searchTopK.value, include: ["documents", "metadatas", "distances"] }, null, 2)}`;
}
- return `POST /api/v2/tenants/default_tenant/databases/default_database/collections/${encodeURIComponent(collectionId)}/get\n${JSON.stringify({ limit: 100, include: ["documents", "metadatas"] }, null, 2)}`;
+ return `POST ${collectionPath}/get\n${JSON.stringify({ limit: 100, include: ["documents", "metadatas"] }, null, 2)}`;
}
const collectionPath = pathSegment(collection);
if (mode === "delete") {
diff --git a/apps/desktop/src/components/vector/__tests__/VectorBrowser.spec.ts b/apps/desktop/src/components/vector/__tests__/VectorBrowser.spec.ts
index ed207c3ab7..ade0fd3b4b 100644
--- a/apps/desktop/src/components/vector/__tests__/VectorBrowser.spec.ts
+++ b/apps/desktop/src/components/vector/__tests__/VectorBrowser.spec.ts
@@ -100,7 +100,8 @@ describe("VectorBrowser default requests", () => {
["weaviate", "GET /v1/objects?class=demo&limit=100"],
["chromadb", "POST /api/v2/tenants/default_tenant/databases/default_database/collections/demo/get"],
] as const) {
- app = createApp(VectorBrowser, { connectionId: "vector-1", database: "default", collection: "demo", databaseType });
+ const database = databaseType === "chromadb" ? "default_database" : "default";
+ app = createApp(VectorBrowser, { connectionId: "vector-1", database, collection: "demo", databaseType });
app.mount(root!);
await flushUi();
expect(root!.querySelector("textarea")!.value).toContain(expected);
@@ -111,6 +112,31 @@ describe("VectorBrowser default requests", () => {
expect(backend.vectorGetCollectionDetail).not.toHaveBeenCalled();
});
+ it("uses the configured Chroma Cloud namespace in generated requests", async () => {
+ app = createApp(VectorBrowser, {
+ connectionId: "chroma-cloud-1",
+ database: "support/kb",
+ collection: "collection/id",
+ databaseType: "chromadb",
+ tenant: "tenant /eu",
+ });
+ app.mount(root!);
+ await flushUi();
+
+ const prefix = "/api/v2/tenants/tenant%20%2Feu/databases/support%2Fkb/collections/collection%2Fid";
+ expect(root!.querySelector("textarea")!.value).toContain(`POST ${prefix}/get`);
+
+ for (const [button, operation] of [
+ ["vector.search", "query"],
+ ["vector.upsert", "upsert"],
+ ["vector.delete", "delete"],
+ ] as const) {
+ buttonWithText(button).click();
+ await nextTick();
+ expect(root!.querySelector("textarea")!.value).toContain(`POST ${prefix}/${operation}`);
+ }
+ });
+
it("resolves the schema before executing a generated upsert request", async () => {
let resolveDetail: (value: CollectionInfo) => void;
backend.vectorGetCollectionDetail.mockReturnValue(
diff --git a/apps/desktop/src/stores/connectionStore.ts b/apps/desktop/src/stores/connectionStore.ts
index e06e06e411..2ba3eddb15 100644
--- a/apps/desktop/src/stores/connectionStore.ts
+++ b/apps/desktop/src/stores/connectionStore.ts
@@ -4161,7 +4161,7 @@ export const useConnectionStore = defineStore("connection", () => {
async function loadVectorCollections(connectionId: string, database?: string) {
const config = getConfig(connectionId);
const isMilvus = config?.db_type === "milvus";
- const effectiveDb = database || config?.database || "default";
+ const effectiveDb = database || config?.database || (config?.db_type === "chromadb" ? "default_database" : "default");
// Milvus groups collections under a per-database node; other vector stores stay flat under the connection.
const node = isMilvus && database ? findNode(treeNodes.value, `${connectionId}:${database}`) : findConnectionNode(connectionId);
if (!node) return;
diff --git a/crates/dbx-core/src/agent_tools.rs b/crates/dbx-core/src/agent_tools.rs
index 04318362f9..94d0d4e71d 100644
--- a/crates/dbx-core/src/agent_tools.rs
+++ b/crates/dbx-core/src/agent_tools.rs
@@ -1109,7 +1109,12 @@ async fn execute_browse_collection(
collection.to_string()
};
- let query = build_browse_query(db_type, &collection_id, database, limit)?;
+ let tenant = if *db_type == DatabaseType::ChromaDb {
+ state.configs.read().await.get(connection_id).map(|config| config.username.clone()).unwrap_or_default()
+ } else {
+ String::new()
+ };
+ let query = build_browse_query(db_type, &collection_id, database, &tenant, limit)?;
let options = QueryExecutionOptions { max_rows: Some(limit), timeout_secs: Some(30), ..Default::default() };
let result =
@@ -1125,6 +1130,7 @@ fn build_browse_query(
db_type: &DatabaseType,
collection: &str,
database: &str,
+ tenant: &str,
limit: usize,
) -> Result {
let collection = collection.trim();
@@ -1151,11 +1157,9 @@ fn build_browse_query(
DatabaseType::Weaviate => {
Ok(format!("GET /v1/objects?class={}&limit={}", vector_driver::query_value(collection), limit))
}
- // TODO: ChromaDB Cloud 支持自定义租户和数据库,当前只实现了本地部署
- // (固定 default_tenant / default_database),后续支持云服务时需改为可配置。
DatabaseType::ChromaDb => Ok(format!(
- "POST /api/v2/tenants/default_tenant/databases/default_database/collections/{}/get\n{}",
- collection,
+ "POST {}/get\n{}",
+ vector_driver::chroma_collection_path(tenant, database, collection, None),
serde_json::json!({ "limit": limit, "include": ["documents", "metadatas"] })
)),
_ => Err(format!("Unsupported database type: {:?}", db_type)),
@@ -1721,7 +1725,7 @@ for line in sys.stdin:
#[test]
fn build_browse_query_qdrant() {
- let q = build_browse_query(&DatabaseType::Qdrant, "articles", "", 10).unwrap();
+ let q = build_browse_query(&DatabaseType::Qdrant, "articles", "", "", 10).unwrap();
assert!(q.starts_with("POST /collections/articles/points/scroll"));
assert!(q.contains("\"limit\":10"));
assert!(q.contains("\"with_payload\":true"));
@@ -1729,13 +1733,13 @@ for line in sys.stdin:
#[test]
fn build_browse_query_qdrant_encodes_url_chars() {
- let q = build_browse_query(&DatabaseType::Qdrant, "my collection", "", 10).unwrap();
+ let q = build_browse_query(&DatabaseType::Qdrant, "my collection", "", "", 10).unwrap();
assert!(q.starts_with("POST /collections/my%20collection/points/scroll"));
}
#[test]
fn build_browse_query_milvus() {
- let q = build_browse_query(&DatabaseType::Milvus, "articles", "custom_db", 20).unwrap();
+ let q = build_browse_query(&DatabaseType::Milvus, "articles", "custom_db", "", 20).unwrap();
assert!(q.starts_with("POST /v2/vectordb/entities/query"));
assert!(q.contains("\"dbName\":\"custom_db\""));
assert!(q.contains("\"collectionName\":\"articles\""));
@@ -1745,40 +1749,46 @@ for line in sys.stdin:
#[test]
fn build_browse_query_milvus_default_db() {
- let q = build_browse_query(&DatabaseType::Milvus, "articles", "", 10).unwrap();
+ let q = build_browse_query(&DatabaseType::Milvus, "articles", "", "", 10).unwrap();
assert!(q.contains("\"dbName\":\"default\""));
}
#[test]
fn build_browse_query_weaviate() {
- let q = build_browse_query(&DatabaseType::Weaviate, "Articles", "", 5).unwrap();
+ let q = build_browse_query(&DatabaseType::Weaviate, "Articles", "", "", 5).unwrap();
assert_eq!(q, "GET /v1/objects?class=Articles&limit=5");
}
#[test]
fn build_browse_query_weaviate_encodes_query_param() {
- let q = build_browse_query(&DatabaseType::Weaviate, "A&B", "", 5).unwrap();
+ let q = build_browse_query(&DatabaseType::Weaviate, "A&B", "", "", 5).unwrap();
assert!(q.contains("class=A%26B"));
}
#[test]
fn build_browse_query_chromadb() {
- let q = build_browse_query(&DatabaseType::ChromaDb, "uuid-123", "", 15).unwrap();
- assert!(
- q.starts_with("POST /api/v2/tenants/default_tenant/databases/default_database/collections/uuid-123/get")
- );
+ let q = build_browse_query(&DatabaseType::ChromaDb, "uuid-123", "cloud/db", "tenant /eu", 15).unwrap();
+ assert!(q.starts_with("POST /api/v2/tenants/tenant%20%2Feu/databases/cloud%2Fdb/collections/uuid-123/get"));
assert!(q.contains("\"limit\":15"));
}
+ #[test]
+ fn build_browse_query_chromadb_keeps_local_defaults() {
+ let q = build_browse_query(&DatabaseType::ChromaDb, "uuid-123", "", "", 15).unwrap();
+ assert!(
+ q.starts_with("POST /api/v2/tenants/default_tenant/databases/default_database/collections/uuid-123/get")
+ );
+ }
+
#[test]
fn build_browse_query_rejects_empty_collection() {
- let result = build_browse_query(&DatabaseType::Qdrant, " ", "", 10);
+ let result = build_browse_query(&DatabaseType::Qdrant, " ", "", "", 10);
assert!(result.is_err());
}
#[test]
fn build_browse_query_rejects_unsupported_type() {
- let result = build_browse_query(&DatabaseType::Postgres, "articles", "", 10);
+ let result = build_browse_query(&DatabaseType::Postgres, "articles", "", "", 10);
assert!(result.is_err());
}
diff --git a/crates/dbx-core/src/db/vector_driver.rs b/crates/dbx-core/src/db/vector_driver.rs
index 9d1c3edff9..61b5804d75 100644
--- a/crates/dbx-core/src/db/vector_driver.rs
+++ b/crates/dbx-core/src/db/vector_driver.rs
@@ -89,6 +89,7 @@ pub struct VectorClient {
http: HttpClient,
base_url: String,
auth: Option,
+ tenant: Option,
database: Option,
}
@@ -111,9 +112,14 @@ impl VectorClient {
) -> Self {
let base_url = url.trim_end_matches('/').to_string();
let auth = vector_auth(kind, username, password);
+ let tenant = if kind == VectorDbKind::ChromaDb {
+ username.map(str::trim).filter(|tenant| !tenant.is_empty()).map(str::to_string)
+ } else {
+ None
+ };
let builder = http_client_builder(timeout).danger_accept_invalid_certs(accept_invalid_certs);
let http = builder.build().unwrap_or_else(|_| HttpClient::new());
- Self { kind, http, base_url, auth, database: None }
+ Self { kind, http, base_url, auth, tenant, database: None }
}
pub fn with_database(mut self, database: Option<&str>) -> Self {
@@ -125,6 +131,22 @@ impl VectorClient {
self.database.as_deref().unwrap_or("default")
}
+ fn chroma_tenant(&self) -> &str {
+ self.tenant.as_deref().unwrap_or("default_tenant")
+ }
+
+ fn chroma_database(&self) -> &str {
+ self.database.as_deref().unwrap_or("default_database")
+ }
+
+ fn chroma_collections_path(&self) -> String {
+ chroma_collections_path(self.chroma_tenant(), self.chroma_database())
+ }
+
+ fn chroma_collection_path(&self, collection: &str, operation: Option<&str>) -> String {
+ chroma_collection_path(self.chroma_tenant(), self.chroma_database(), collection, operation)
+ }
+
fn get(&self, path: &str) -> reqwest::RequestBuilder {
self.with_auth(self.http.get(format!("{}{}", self.base_url, path)))
}
@@ -153,17 +175,13 @@ impl VectorClient {
}
fn test_connection_request(client: &VectorClient) -> reqwest::RequestBuilder {
- let path = match client.kind {
- VectorDbKind::Qdrant => "/collections",
- VectorDbKind::Milvus => "/v2/vectordb/collections/list",
- VectorDbKind::Weaviate => "/v1/meta",
- VectorDbKind::ChromaDb => "/api/v2/heartbeat",
- };
match client.kind {
- VectorDbKind::Qdrant => client.get(path),
- VectorDbKind::Milvus => client.post(path).json(&serde_json::json!({ "dbName": client.database_or_default() })),
- VectorDbKind::Weaviate => client.get(path),
- VectorDbKind::ChromaDb => client.get(path),
+ VectorDbKind::Qdrant => client.get("/collections"),
+ VectorDbKind::Milvus => client
+ .post("/v2/vectordb/collections/list")
+ .json(&serde_json::json!({ "dbName": client.database_or_default() })),
+ VectorDbKind::Weaviate => client.get("/v1/meta"),
+ VectorDbKind::ChromaDb => client.get(&client.chroma_collections_path()),
}
}
@@ -310,9 +328,7 @@ async fn list_weaviate_collections(client: &VectorClient) -> Result Result, String> {
- let body =
- send_json(client.get("/api/v2/tenants/default_tenant/databases/default_database/collections"), client.kind)
- .await?;
+ let body = send_json(client.get(&client.chroma_collections_path()), client.kind).await?;
let mut infos: Vec = body
.as_array()
.into_iter()
@@ -473,14 +489,7 @@ async fn get_milvus_collection_detail(
}
async fn get_chroma_collection_detail(client: &VectorClient, collection: &str) -> Result {
- let body = send_json(
- client.get(&format!(
- "/api/v2/tenants/default_tenant/databases/default_database/collections/{}",
- path_segment(collection)
- )),
- client.kind,
- )
- .await?;
+ let body = send_json(client.get(&client.chroma_collection_path(collection, None)), client.kind).await?;
let name = body.get("name").and_then(Value::as_str).unwrap_or(collection);
let id = body.get("id").and_then(Value::as_str).unwrap_or(collection);
let dimension = body.get("dimension").and_then(|v| v.as_u64()).map(|d| d as u32);
@@ -577,13 +586,8 @@ pub async fn find_documents(
) -> Result {
if client.kind == VectorDbKind::ChromaDb {
let start = std::time::Instant::now();
- let url = format!(
- "{}/api/v2/tenants/default_tenant/databases/default_database/collections/{}/get",
- client.base_url,
- path_segment(collection),
- );
let resp = client
- .with_auth(client.http.post(&url))
+ .post(&client.chroma_collection_path(collection, Some("get")))
.json(&serde_json::json!({
"limit": limit.max(1) as u64,
"offset": skip,
@@ -753,10 +757,7 @@ fn default_collection_query(client: &VectorClient, collection: &str) -> Result Ok(client.get(&format!("/v1/objects?class={}&limit=100", query_value(collection)))),
VectorDbKind::ChromaDb => Ok(client
- .post(&format!(
- "/api/v2/tenants/default_tenant/databases/default_database/collections/{}/get",
- path_segment(collection)
- ))
+ .post(&client.chroma_collection_path(collection, Some("get")))
.json(&serde_json::json!({"limit": 100, "include": ["documents", "metadatas"]}))),
}
}
@@ -769,6 +770,30 @@ pub(crate) fn path_segment(value: &str) -> String {
utf8_percent_encode(value, PATH_SEGMENT_ENCODE_SET).to_string()
}
+pub(crate) fn chroma_collections_path(tenant: &str, database: &str) -> String {
+ let tenant = tenant.trim();
+ let database = database.trim();
+ format!(
+ "/api/v2/tenants/{}/databases/{}/collections",
+ path_segment(if tenant.is_empty() { "default_tenant" } else { tenant }),
+ path_segment(if database.is_empty() { "default_database" } else { database })
+ )
+}
+
+pub(crate) fn chroma_collection_path(
+ tenant: &str,
+ database: &str,
+ collection: &str,
+ operation: Option<&str>,
+) -> String {
+ let mut path = format!("{}/{}", chroma_collections_path(tenant, database), path_segment(collection));
+ if let Some(operation) = operation {
+ path.push('/');
+ path.push_str(&path_segment(operation));
+ }
+ path
+}
+
pub(crate) fn query_value(value: &str) -> String {
utf8_percent_encode(value, QUERY_VALUE_ENCODE_SET).to_string()
}
@@ -909,10 +934,10 @@ fn format_reqwest_error(err: &reqwest::Error) -> String {
#[cfg(test)]
mod tests {
use super::{
- chroma_get_response_to_rows, milvus_collection_schema, milvus_database_names, rest_query_result,
- starts_with_http_method, test_connection, test_connection_request, values_to_query_result, vector_auth,
- weaviate_collection_names_from_schema, weaviate_vector_dimension_from_graphql, CollectionInfo, VectorAuth,
- VectorClient, VectorDbKind,
+ chroma_get_response_to_rows, default_collection_query, milvus_collection_schema, milvus_database_names,
+ rest_query_result, starts_with_http_method, test_connection, test_connection_request, values_to_query_result,
+ vector_auth, weaviate_collection_names_from_schema, weaviate_vector_dimension_from_graphql, CollectionInfo,
+ VectorAuth, VectorClient, VectorDbKind,
};
use serde_json::{json, Value};
use std::time::{Duration, Instant};
@@ -939,6 +964,28 @@ mod tests {
(format!("http://{address}"), server)
}
+ async fn spawn_recording_json_response_server(
+ body: Value,
+ ) -> (String, tokio::sync::oneshot::Receiver, tokio::task::JoinHandle<()>) {
+ let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
+ let address = listener.local_addr().unwrap();
+ let body = body.to_string();
+ let (request_tx, request_rx) = tokio::sync::oneshot::channel();
+ let server = tokio::spawn(async move {
+ let (mut stream, _) = listener.accept().await.unwrap();
+ let mut request = [0_u8; 8192];
+ let read = stream.read(&mut request).await.unwrap();
+ request_tx.send(String::from_utf8_lossy(&request[..read]).into_owned()).unwrap();
+ let response = format!(
+ "HTTP/1.1 200 OK\r\ncontent-type: application/json\r\ncontent-length: {}\r\nconnection: close\r\n\r\n{}",
+ body.len(),
+ body
+ );
+ stream.write_all(response.as_bytes()).await.unwrap();
+ });
+ (format!("http://{address}"), request_rx, server)
+ }
+
#[test]
fn detects_rest_queries_case_insensitively() {
assert!(starts_with_http_method("post /collections/foo"));
@@ -1177,6 +1224,71 @@ mod tests {
assert_eq!(vector_auth(VectorDbKind::ChromaDb, None, None), None);
}
+ #[tokio::test]
+ async fn chroma_cloud_connection_test_uses_configured_namespace_and_token() {
+ let (url, request_rx, server) = spawn_recording_json_response_server(json!([])).await;
+ let client = VectorClient::new(
+ VectorDbKind::ChromaDb,
+ &url,
+ Some("tenant /eu"),
+ Some("cloud-api-key"),
+ false,
+ Duration::from_secs(1),
+ )
+ .with_database(Some("support/kb"));
+
+ test_connection(&client, Duration::from_secs(1)).await.unwrap();
+ let request = request_rx.await.unwrap();
+
+ assert!(
+ request.starts_with("GET /api/v2/tenants/tenant%20%2Feu/databases/support%2Fkb/collections HTTP/1.1\r\n")
+ );
+ assert!(request.to_ascii_lowercase().contains("\r\nx-chroma-token: cloud-api-key\r\n"));
+ server.await.unwrap();
+ }
+
+ #[test]
+ fn chroma_local_connection_test_keeps_default_namespace() {
+ let client = VectorClient::new(
+ VectorDbKind::ChromaDb,
+ "http://localhost:8000",
+ None,
+ None,
+ false,
+ Duration::from_secs(1),
+ );
+
+ let request = test_connection_request(&client).build().unwrap();
+
+ assert_eq!(
+ request.url().as_str(),
+ "http://localhost:8000/api/v2/tenants/default_tenant/databases/default_database/collections"
+ );
+ assert!(request.headers().get("x-chroma-token").is_none());
+ }
+
+ #[test]
+ fn chroma_collection_paths_encode_every_dynamic_segment() {
+ let client = VectorClient::new(
+ VectorDbKind::ChromaDb,
+ "https://api.trychroma.com",
+ Some("tenant /eu"),
+ None,
+ false,
+ Duration::from_secs(1),
+ )
+ .with_database(Some("support/kb"));
+
+ assert_eq!(
+ client.chroma_collection_path("collection/id", Some("get/by-id")),
+ "/api/v2/tenants/tenant%20%2Feu/databases/support%2Fkb/collections/collection%2Fid/get%2Fby-id"
+ );
+ assert_eq!(
+ default_collection_query(&client, "collection/id").unwrap().build().unwrap().url().path(),
+ "/api/v2/tenants/tenant%20%2Feu/databases/support%2Fkb/collections/collection%2Fid/get"
+ );
+ }
+
#[test]
fn parses_chroma_collection_list() {
let body = json!([
diff --git a/src-tauri/src/commands/connection.rs b/src-tauri/src/commands/connection.rs
index a54166385e..66ab8e81f9 100644
--- a/src-tauri/src/commands/connection.rs
+++ b/src-tauri/src/commands/connection.rs
@@ -1040,7 +1040,8 @@ async fn test_connection_with_info_inner(
Some(&config.password),
config.ssl,
connect_timeout,
- );
+ )
+ .with_database(config.database.as_deref());
db::vector_driver::test_connection(&client, connect_timeout)
.await
.map(|_| "Connection successful".to_string())
@@ -1420,7 +1421,8 @@ pub async fn connect_db(
Some(&db_config.password),
db_config.ssl,
connect_timeout,
- );
+ )
+ .with_database(db_config.database.as_deref());
db::vector_driver::test_connection(&client, connect_timeout).await?;
PoolKind::VectorDb(client)
}