From 2138f59da4c30945d2195a3645437c6044132423 Mon Sep 17 00:00:00 2001 From: zipg Date: Thu, 27 Aug 2026 08:39:45 +0800 Subject: [PATCH] fix(compare): keep oracle prefill selections during async loads --- .../src/components/diff/DataCompareDialog.vue | 27 ++++--- .../DataCompareDialog.prefill.spec.ts | 71 +++++++++++++++++++ 2 files changed, 89 insertions(+), 9 deletions(-) create mode 100644 apps/desktop/src/components/diff/__tests__/DataCompareDialog.prefill.spec.ts diff --git a/apps/desktop/src/components/diff/DataCompareDialog.vue b/apps/desktop/src/components/diff/DataCompareDialog.vue index de62aebb3e..a3351692a5 100644 --- a/apps/desktop/src/components/diff/DataCompareDialog.vue +++ b/apps/desktop/src/components/diff/DataCompareDialog.vue @@ -118,6 +118,7 @@ const showRemoved = ref(true); const showModified = ref(true); let syncPlanRequestId = 0; +let initializingPrefill = false; const sqlConnections = computed(() => store.connections.filter((connection) => !["redis", "mongodb", "elasticsearch", "easysearch", "meilisearch", "qdrant", "milvus", "weaviate", "chromadb", "etcd", "zookeeper", "consul", "mq", "nacos"].includes(connection.db_type))); const selectedSourceTableNames = computed(() => sourceTables.value.filter((table) => selectedSourceTables.value.has(table))); @@ -780,6 +781,7 @@ function formatModifiedSummary(row: SelectableDataCompareModifiedRow): string { } watch(sourceConnectionId, (id) => { + if (initializingPrefill) return; clearResult(); sourceDatabase.value = ""; sourceSchema.value = ""; @@ -799,6 +801,7 @@ watch(targetConnectionId, (id) => { loadDatabases(id, "target").catch((e) => toast(String(e), 5000)); }); watch(sourceDatabase, () => { + if (initializingPrefill) return; clearResult(); sourceSchema.value = ""; sourceSchemas.value = []; @@ -816,6 +819,7 @@ watch(targetDatabase, () => { loadSchemas("target").catch((e) => toast(String(e), 5000)); }); watch(sourceSchema, () => { + if (initializingPrefill) return; clearResult(); sourceTables.value = []; sourceTable.value = ""; @@ -853,16 +857,21 @@ watch( if (!value) return; clearResult(); if (props.prefillConnectionId) { - sourceConnectionId.value = props.prefillConnectionId; - await loadDatabases(props.prefillConnectionId, "source"); - if (props.prefillDatabase) sourceDatabase.value = props.prefillDatabase; - if (props.prefillDatabase) await loadSchemas("source", props.prefillSchema); - if (props.prefillTable) { - await loadTables("source"); - if (sourceTables.value.includes(props.prefillTable)) { - resetSelectedSourceTables([props.prefillTable]); - sourceTable.value = props.prefillTable; + initializingPrefill = true; + try { + sourceConnectionId.value = props.prefillConnectionId; + await loadDatabases(props.prefillConnectionId, "source"); + if (props.prefillDatabase) sourceDatabase.value = props.prefillDatabase; + if (props.prefillDatabase) await loadSchemas("source", props.prefillSchema); + if (props.prefillTable) { + await loadTables("source"); + if (sourceTables.value.includes(props.prefillTable)) { + resetSelectedSourceTables([props.prefillTable]); + sourceTable.value = props.prefillTable; + } } + } finally { + initializingPrefill = false; } } }, diff --git a/apps/desktop/src/components/diff/__tests__/DataCompareDialog.prefill.spec.ts b/apps/desktop/src/components/diff/__tests__/DataCompareDialog.prefill.spec.ts new file mode 100644 index 0000000000..6ec1735051 --- /dev/null +++ b/apps/desktop/src/components/diff/__tests__/DataCompareDialog.prefill.spec.ts @@ -0,0 +1,71 @@ +// @vitest-environment happy-dom + +import { createApp, defineComponent, h, nextTick, type App } from "vue"; +import { afterEach, describe, expect, it, vi } from "vitest"; +import i18n from "@/i18n"; +import DataCompareDialog from "@/components/diff/DataCompareDialog.vue"; + +const mocks = vi.hoisted(() => ({ + ensureConnected: vi.fn().mockResolvedValue(undefined), + listDatabases: vi.fn().mockResolvedValue([{ name: "DBX_TEST" }, { name: "OPS$ORACLE" }]), + listSchemas: vi.fn().mockResolvedValue(["DBX_TEST"]), + listTables: vi.fn().mockResolvedValue([{ name: "CODEX_7046_META", table_type: "TABLE" }]), + getColumns: vi.fn().mockResolvedValue([{ name: "ID", data_type: "NUMBER", is_primary_key: true }]), +})); + +vi.mock("@/stores/connectionStore", () => ({ + useConnectionStore: () => ({ + connections: [{ id: "oracle-11g", name: "Oracle XE 11g", db_type: "oracle", driver_profile: "oracle", database: "XE" }], + getConfig: (id: string) => (id === "oracle-11g" ? { id, name: "Oracle XE 11g", db_type: "oracle", driver_profile: "oracle", database: "XE" } : undefined), + ensureConnected: mocks.ensureConnected, + }), +})); + +vi.mock("@/lib/backend/api", () => ({ + listDatabases: mocks.listDatabases, + listSchemas: mocks.listSchemas, + listTables: mocks.listTables, + getColumns: mocks.getColumns, +})); + +const mountedApps: App[] = []; + +async function flushAsyncSetup() { + for (let index = 0; index < 8; index += 1) { + await nextTick(); + await new Promise((resolve) => setTimeout(resolve, 0)); + } +} + +afterEach(() => { + for (const app of mountedApps.splice(0)) app.unmount(); + document.body.innerHTML = ""; + vi.clearAllMocks(); +}); + +describe("DataCompareDialog source prefill", () => { + it("keeps the Oracle source table after loading database and schema prefills", async () => { + const container = document.createElement("div"); + document.body.append(container); + const app = createApp( + defineComponent({ + setup: () => () => + h(DataCompareDialog, { + open: true, + prefillConnectionId: "oracle-11g", + prefillDatabase: "DBX_TEST", + prefillSchema: "DBX_TEST", + prefillTable: "CODEX_7046_META", + }), + }), + ); + mountedApps.push(app); + app.use(i18n); + app.mount(container); + await flushAsyncSetup(); + + expect(mocks.listTables).toHaveBeenCalledWith("oracle-11g", "DBX_TEST", "DBX_TEST"); + expect(document.body.textContent).toContain("CODEX_7046_META"); + expect(document.body.textContent).not.toContain("暂无可比较的表"); + }); +});