feat(vector): add weaviate support

This commit is contained in:
t8y2 committed 2026-06-25 00:31:27 +08:00
1 parent 09cdf07aab
commit bf9ef4365b
31 files changed
+180 -28

No files matched your search

@@ -426,6 +426,7 @@ const driverProfiles: Record<
},
qdrant: { type: "qdrant", port: 6333, user: "", label: "Qdrant", icon: "qdrant" },
milvus: { type: "milvus", port: 19530, user: "root", label: "Milvus", icon: "milvus" },
weaviate: { type: "weaviate", port: 8080, user: "", label: "Weaviate", icon: "weaviate" },
mariadb: { type: "mysql", port: 3306, user: "root", label: "MariaDB", icon: "mariadb" },
tidb: { type: "mysql", port: 4000, user: "root", label: "TiDB", icon: "tidb" },
oceanbase: { type: "mysql", port: 2881, user: "root", label: "OceanBase", icon: "oceanbase" },
@@ -1006,6 +1007,7 @@ const iconTypeMap: Record<string, string> = {
elasticsearch: "elasticsearch",
qdrant: "qdrant",
milvus: "milvus",
weaviate: "weaviate",
mariadb: "mariadb",
tidb: "tidb",
oceanbase: "oceanbase",
@@ -1073,6 +1075,7 @@ const dbOptions: DbOption[] = [
{ value: "elasticsearch", label: "Elasticsearch" },
{ value: "qdrant", label: "Qdrant" },
{ value: "milvus", label: "Milvus" },
{ value: "weaviate", label: "Weaviate" },
{ value: "dm", label: "DM (Dameng)" },
{ value: "opengauss", label: "openGauss" },
{ value: "turso", label: "Turso" },
@@ -1178,7 +1181,7 @@ const sqliteExtensionPaths = computed({
form.value.url_params = setSqliteExtensionPaths(form.value.url_params, value);
},
});
const tlsCapableDatabaseTypes = new Set<DatabaseType>(["mysql", "postgres", "redshift", "gaussdb", "kwdb", "opengauss", "questdb", "redis", "etcd", "clickhouse", "elasticsearch", "qdrant", "milvus", "influxdb"]);
const tlsCapableDatabaseTypes = new Set<DatabaseType>(["mysql", "postgres", "redshift", "gaussdb", "kwdb", "opengauss", "questdb", "redis", "etcd", "clickhouse", "elasticsearch", "qdrant", "milvus", "weaviate", "influxdb"]);
const supportsTlsToggle = computed(() => tlsCapableDatabaseTypes.has(form.value.db_type));
const supportsCaCertificatePath = computed(() => form.value.db_type === "clickhouse");
const supportsGenericUrlParams = computed(() => form.value.db_type !== "manticoresearch");
@@ -114,7 +114,7 @@ const showModified = ref(true);
let syncPlanRequestId = 0;
const sqlConnections = computed(() => store.connections.filter((connection) => !["redis", "mongodb", "elasticsearch", "qdrant", "milvus", "etcd", "mq", "nacos"].includes(connection.db_type)));
const sqlConnections = computed(() => store.connections.filter((connection) => !["redis", "mongodb", "elasticsearch", "qdrant", "milvus", "weaviate", "etcd", "mq", "nacos"].includes(connection.db_type)));
const selectedSourceTableNames = computed(() => sourceTables.value.filter((table) => selectedSourceTables.value.has(table)));
const isBatchCompare = computed(() => selectedSourceTableNames.value.length > 1);
const filteredSourceTables = computed(() => {
@@ -65,7 +65,7 @@ const exportCancelled = ref(false);
const pendingPrefillTable = ref("");
const pendingPrefillTables = ref<string[]>([]);
const sqlConnections = computed(() => store.connections.filter((c) => !["redis", "mongodb", "elasticsearch", "qdrant", "milvus", "etcd", "mq", "nacos"].includes(c.db_type)));
const sqlConnections = computed(() => store.connections.filter((c) => !["redis", "mongodb", "elasticsearch", "qdrant", "milvus", "weaviate", "etcd", "mq", "nacos"].includes(c.db_type)));
const canExport = computed(() => connectionId.value && database.value && schema.value && !loadingTables.value && !tableError.value && (tables.value.length === 0 || selectedTables.value.length > 0) && (includeStructure.value || includeData.value || includeObjects.value) && !isExporting.value);
@@ -79,6 +79,7 @@ const assetIcons: Record<string, string> = {
etcd: "etcd",
qdrant: "qdrant",
milvus: "milvus.png",
weaviate: "weaviate.png",
mq: "pulsar",
pulsar: "pulsar",
nacos: "nacos.png",
@@ -61,7 +61,7 @@ const activeConnectionValue = computed(() => props.activeConnection?.id || "");
const activeSchemaValue = computed(() => props.activeTab.schema || "");
const supportsExplain = computed(() => {
const dbType = props.activeConnection?.db_type;
return dbType !== "redis" && dbType !== "mongodb" && dbType !== "elasticsearch" && dbType !== "qdrant" && dbType !== "milvus" && dbType !== "etcd" && dbType !== "mq" && dbType !== "nacos";
return dbType !== "redis" && dbType !== "mongodb" && dbType !== "elasticsearch" && dbType !== "qdrant" && dbType !== "milvus" && dbType !== "weaviate" && dbType !== "etcd" && dbType !== "mq" && dbType !== "nacos";
});
const isSingleDb = computed(() => isSingleDatabase(props.activeConnection?.db_type));
const hasDefaultDatabaseOption = computed(() => activeDatabaseOptions.value.includes(""));
@@ -251,7 +251,7 @@ function connectionById(connectionId: string): ConnectionConfig | undefined {
</template>
</SearchableSelect>
</div>
<div v-if="activeConnection?.db_type !== 'elasticsearch' && activeConnection?.db_type !== 'qdrant' && activeConnection?.db_type !== 'milvus' && !isSingleDb" class="flex items-center gap-1">
<div v-if="activeConnection?.db_type !== 'elasticsearch' && activeConnection?.db_type !== 'qdrant' && activeConnection?.db_type !== 'milvus' && activeConnection?.db_type !== 'weaviate' && !isSingleDb" class="flex items-center gap-1">
<Database class="h-3.5 w-3.5 shrink-0" />
<SearchableSelect
:model-value="activeDatabaseValue"
@@ -402,7 +402,7 @@ async function ensureTreeLoadedForTarget(target: ActiveTabSidebarTarget, opts?:
await store.loadMongoDatabases(connId);
} else if (config.db_type === "elasticsearch") {
await store.loadElasticsearchIndices(connId);
} else if (config.db_type === "qdrant" || config.db_type === "milvus") {
} else if (config.db_type === "qdrant" || config.db_type === "milvus" || config.db_type === "weaviate") {
await store.loadVectorCollections(connId);
} else if (config.db_type === "mq") {
await store.loadMqTenants(connId, loadOptions);
@@ -350,6 +350,7 @@ function connectionTooltipScheme(config: Pick<ConnectionConfig, "db_type" | "ssl
case "elasticsearch":
case "qdrant":
case "milvus":
case "weaviate":
case "rqlite":
case "turso":
case "mq":
@@ -474,7 +475,7 @@ async function toggle() {
await connectionStore.loadMongoDatabases(node.connectionId);
} else if (config?.db_type === "elasticsearch") {
await connectionStore.loadElasticsearchIndices(node.connectionId);
} else if (config?.db_type === "qdrant" || config?.db_type === "milvus") {
} else if (config?.db_type === "qdrant" || config?.db_type === "milvus" || config?.db_type === "weaviate") {
await connectionStore.loadVectorCollections(node.connectionId);
} else if (config?.db_type === "mq") {
await connectionStore.loadMqTenants(node.connectionId);
@@ -3052,7 +3053,7 @@ const nodeIconClass = computed(() => {
const canConfigureVisibleDatabases = computed(() => {
if (props.node.type !== "connection" || !props.node.connectionId) return false;
const dbType = connectionStore.getConfig(props.node.connectionId)?.db_type;
return dbType !== "elasticsearch" && dbType !== "qdrant" && dbType !== "milvus" && dbType !== "etcd" && dbType !== "mq" && dbType !== "nacos";
return dbType !== "elasticsearch" && dbType !== "qdrant" && dbType !== "milvus" && dbType !== "weaviate" && dbType !== "etcd" && dbType !== "mq" && dbType !== "nacos";
});
const canCopyFinalProxyPort = computed(() => {
if (props.node.type !== "connection" || !props.node.connectionId) return false;
@@ -49,7 +49,7 @@ const terminalStatus = ref<SqlFileStatus | "idle">("idle");
const terminalError = ref("");
const refreshedTarget = ref(false);
const sqlConnections = computed(() => store.connections.filter((c) => !["redis", "mongodb", "elasticsearch", "qdrant", "milvus", "etcd", "mq", "nacos"].includes(c.db_type)));
const sqlConnections = computed(() => store.connections.filter((c) => !["redis", "mongodb", "elasticsearch", "qdrant", "milvus", "weaviate", "etcd", "mq", "nacos"].includes(c.db_type)));
const selectedConnection = computed(() => sqlConnections.value.find((c) => c.id === connectionId.value));
@@ -32,7 +32,7 @@ const operationMode = ref<VectorOperationMode>("browse");
const requestText = ref(defaultRequestText(props.databaseType, props.database, props.collection, operationMode.value));
let loadingTimer: ReturnType<typeof setInterval> | undefined;
const productLabel = computed(() => (props.databaseType === "milvus" ? "Milvus" : "Qdrant"));
const productLabel = computed(() => (props.databaseType === "milvus" ? "Milvus" : props.databaseType === "weaviate" ? "Weaviate" : "Qdrant"));
const collectionLabel = computed(() => props.collection || t("vector.collectionFallback"));
const executeLabel = computed(() => (operationMode.value === "browse" ? t("vector.run") : t("vector.apply")));
const operationIcon = computed(() => (operationMode.value === "delete" ? Trash2 : operationMode.value === "upsert" ? Save : Play));
@@ -94,6 +94,26 @@ function defaultRequestText(databaseType: DatabaseType | undefined, database: st
const endpoint = mode === "delete" ? "delete" : mode === "upsert" ? "upsert" : "query";
return `POST /v2/vectordb/entities/${endpoint}\n${JSON.stringify(body, null, 2)}`;
}
if (databaseType === "weaviate") {
const collectionName = collection || "Collection";
if (mode === "delete") {
return "DELETE /v1/objects/{id}";
}
if (mode === "upsert") {
return `POST /v1/objects\n${JSON.stringify(
{
class: collectionName,
properties: {
title: "updated vector",
kind: "demo",
},
},
null,
2,
)}`;
}
return `GET /v1/objects?class=${encodeURIComponent(collectionName)}&limit=100`;
}
const collectionPath = pathSegment(collection);
if (mode === "delete") {
return `POST /collections/${collectionPath}/points/delete?wait=true\n${JSON.stringify({ points: [1] }, null, 2)}`;