diff --git a/apps/desktop/src/components/transfer/__tests__/DataTransferDialog.spec.ts b/apps/desktop/src/components/transfer/__tests__/DataTransferDialog.spec.ts index 353e1363c8..c9dcb241d6 100644 --- a/apps/desktop/src/components/transfer/__tests__/DataTransferDialog.spec.ts +++ b/apps/desktop/src/components/transfer/__tests__/DataTransferDialog.spec.ts @@ -47,6 +47,22 @@ describe("DataTransferDialog transfer prefill", () => { expect(dialogSource).toContain("groups[kind] = objects.map((o) => o.name)"); }); + it("routes table-only database kinds through the table-list request", () => { + expect(dialogSource).toContain("const kinds = transferObjectKindsForDatabase(config?.db_type)"); + expect(dialogSource).toContain("for (const kind of kinds)"); + expect(dialogSource).toContain('if (kind === "TABLE")'); + expect(dialogSource).toContain("await api.listTables(sourceConnectionId.value, sourceDatabase.value, schema"); + }); + + it("keeps MongoDB collection loading ahead of the generic object-kind path", () => { + const mongoCollectionBranch = dialogSource.indexOf("if (isMongoConnection(sourceConnectionId.value))"); + const genericObjectKinds = dialogSource.indexOf("const kinds = transferObjectKindsForDatabase(config?.db_type)"); + + expect(mongoCollectionBranch).toBeGreaterThan(-1); + expect(dialogSource).toContain("await api.mongoListCollections(sourceConnectionId.value, sourceDatabase.value)"); + expect(mongoCollectionBranch).toBeLessThan(genericObjectKinds); + }); + it("disables non-table groups for data-only and cross-family transfers", () => { expect(dialogSource).toContain("treeDisabledGroups"); expect(dialogSource).toContain('transferContent.value === "dataOnly"'); diff --git a/apps/desktop/src/lib/database/__tests__/transferObjectKinds.spec.ts b/apps/desktop/src/lib/database/__tests__/transferObjectKinds.spec.ts index 3ae0e79dfc..cce87000a2 100644 --- a/apps/desktop/src/lib/database/__tests__/transferObjectKinds.spec.ts +++ b/apps/desktop/src/lib/database/__tests__/transferObjectKinds.spec.ts @@ -1,5 +1,10 @@ import { describe, expect, it } from "vitest"; import { transferObjectFamily, transferObjectKindsForDatabase, isSameTransferFamily, crossFamilyTransferableKinds, TransferObjectFamily } from "@/lib/database/transferObjectKinds"; +import { manifestDatabaseTypes } from "@/lib/database/databaseDriverManifest"; +import { supportsTransfer } from "@/lib/database/databaseFeatureSupport"; +import type { DatabaseType } from "@/types/database"; + +const TABLE_ONLY_TRANSFER_DATABASES: DatabaseType[] = ["sqlite", "rqlite", "cloudflare-d1", "duckdb", "clickhouse", "mongodb", "questdb", "hive", "spark"]; describe("transferObjectKinds", () => { it("groups databases into transfer families", () => { @@ -12,10 +17,22 @@ describe("transferObjectKinds", () => { it("returns per-family object kinds", () => { expect(transferObjectKindsForDatabase("mysql")).toEqual(["TABLE", "VIEW", "PROCEDURE", "FUNCTION", "TRIGGER", "EVENT"]); - expect(transferObjectKindsForDatabase("postgres")).toContain("SEQUENCE"); - expect(transferObjectKindsForDatabase("dameng")).toContain("TRIGGER"); + expect(transferObjectKindsForDatabase("postgres")).toEqual(["TABLE", "VIEW", "MATERIALIZED_VIEW", "PROCEDURE", "FUNCTION", "TRIGGER", "SEQUENCE"]); + expect(transferObjectKindsForDatabase("oracle")).toEqual(["TABLE", "VIEW", "MATERIALIZED_VIEW", "PROCEDURE", "FUNCTION", "TRIGGER", "SEQUENCE"]); expect(transferObjectKindsForDatabase("sqlserver")).toEqual(["TABLE", "VIEW", "PROCEDURE", "FUNCTION", "TRIGGER", "SEQUENCE"]); - expect(transferObjectKindsForDatabase("sqlite")).toEqual([]); + }); + + it.each(TABLE_ONLY_TRANSFER_DATABASES)("falls back to tables for transfer-capable %s databases", (dbType) => { + expect(transferObjectKindsForDatabase(dbType)).toEqual(["TABLE"]); + }); + + it("covers every transfer-capable database outside the richer object families", () => { + expect(manifestDatabaseTypes().filter((dbType) => supportsTransfer(dbType) && !transferObjectFamily(dbType))).toEqual(TABLE_ONLY_TRANSFER_DATABASES); + }); + + it("does not expose objects for databases without transfer support", () => { + expect(transferObjectKindsForDatabase("redis")).toEqual([]); + expect(transferObjectKindsForDatabase(undefined)).toEqual([]); }); it("detects same-family transfers", () => { @@ -40,7 +57,7 @@ describe("transferObjectKinds", () => { const same = crossFamilyTransferableKinds("mysql", "mysql"); expect(same).toContain("TRIGGER"); expect(same).toContain("EVENT"); - // unsupported db + // transfer-capable database without a modeled cross-family executor expect(crossFamilyTransferableKinds("sqlite", "mysql")).toEqual([]); }); }); diff --git a/apps/desktop/src/lib/database/transferObjectKinds.ts b/apps/desktop/src/lib/database/transferObjectKinds.ts index e8812612ea..6da60f956a 100644 --- a/apps/desktop/src/lib/database/transferObjectKinds.ts +++ b/apps/desktop/src/lib/database/transferObjectKinds.ts @@ -1,4 +1,5 @@ import type { DatabaseType } from "@/types/database"; +import { supportsTransfer } from "@/lib/database/databaseFeatureSupport"; export enum TransferObjectFamily { Mysql = "mysql", @@ -48,7 +49,7 @@ export function transferObjectKindsForDatabase(dbType?: DatabaseType): TransferO case TransferObjectFamily.SqlServer: return [...SQLSERVER_KINDS]; default: - return []; + return supportsTransfer(dbType) ? ["TABLE"] : []; } }