From 6875ca4000b02da1d0f89242105a49e611d01330 Mon Sep 17 00:00:00 2001 From: jearhe <0verme7753@gmail.com> Date: Thu, 27 Aug 2026 08:38:20 +0800 Subject: [PATCH] fix(schema-diff): refresh table lists before comparing --- .../src/components/diff/SchemaDiffDialog.vue | 4 +++- .../schema/schemaDiffTableList.spec.ts | 18 +++++++++++++++++- .../src/lib/schema/schemaDiffTableList.ts | 6 +++--- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/apps/desktop/src/components/diff/SchemaDiffDialog.vue b/apps/desktop/src/components/diff/SchemaDiffDialog.vue index 9088456ee5..eb2b14554f 100644 --- a/apps/desktop/src/components/diff/SchemaDiffDialog.vue +++ b/apps/desktop/src/components/diff/SchemaDiffDialog.vue @@ -441,7 +441,9 @@ async function handleCompare() { const sourceTableIdentity: SchemaDiffTableIdentity = { connectionId: sourceConnectionId.value, database: sourceDatabase.value, schema: sourceSchema.value }; const targetTableIdentity: SchemaDiffTableIdentity = { connectionId: targetConnectionId.value, database: targetDatabase.value, schema: targetSchema.value }; - const [srcTables, tgtTables] = await Promise.all([schemaDiffTableListLoader.load(sourceTableIdentity), schemaDiffTableListLoader.load(targetTableIdentity)]); + // The dialog can remain open while either database changes, so Compare must not reuse + // the table list cached while configuring the comparison. + const [srcTables, tgtTables] = await Promise.all([schemaDiffTableListLoader.load(sourceTableIdentity, { refresh: true }), schemaDiffTableListLoader.load(targetTableIdentity, { refresh: true })]); // Explicit (visual) table selection is applied here, BEFORE any per-table // metadata details are loaded, so metadata requests only happen for the // final table set. `undefined`/empty means no restriction (legacy path). diff --git a/apps/desktop/src/lib/__tests__/schema/schemaDiffTableList.spec.ts b/apps/desktop/src/lib/__tests__/schema/schemaDiffTableList.spec.ts index ab361d74ab..1598a81332 100644 --- a/apps/desktop/src/lib/__tests__/schema/schemaDiffTableList.spec.ts +++ b/apps/desktop/src/lib/__tests__/schema/schemaDiffTableList.spec.ts @@ -37,7 +37,7 @@ describe("schemaDiffTableList", () => { expect(shouldLoadSchemaDiffTableList("target", true, 0, true)).toBe(false); }); - it("loads each side at most once and reuses successful results for Compare", async () => { + it("loads each side at most once for non-refreshing reads", async () => { const listTables = vi.fn(async (connectionId: string) => [table(`${connectionId}_table`)]); const loader = createSchemaDiffTableListLoader({ ensureConnected: vi.fn().mockResolvedValue(undefined), listTables }); const identities: Record = { @@ -59,6 +59,22 @@ describe("schemaDiffTableList", () => { expect(listTables).toHaveBeenCalledWith("target", "app", "public"); }); + it("refreshes table names before a second compare after the database changes", async () => { + const listTables = vi + .fn() + .mockResolvedValueOnce([table("removed_table")]) + .mockResolvedValueOnce([table("current_table")]); + const loader = createSchemaDiffTableListLoader({ ensureConnected: vi.fn().mockResolvedValue(undefined), listTables }); + const identity: SchemaDiffTableIdentity = { connectionId: "source", database: "app", schema: "public" }; + + const firstTables = await loader.load(identity); + const refreshedTables = await loader.load(identity, { refresh: true }); + + expect(firstTables.map((entry) => entry.name)).toEqual(["removed_table"]); + expect(refreshedTables.map((entry) => entry.name)).toEqual(["current_table"]); + expect(listTables).toHaveBeenCalledTimes(2); + }); + it("prunes deleted selections only after a successful source load", async () => { const listTables = vi.fn(async (_connectionId: string, database: string) => { if (database === "unavailable") throw new Error("offline"); diff --git a/apps/desktop/src/lib/schema/schemaDiffTableList.ts b/apps/desktop/src/lib/schema/schemaDiffTableList.ts index 04e0256995..1ab1dcb0e1 100644 --- a/apps/desktop/src/lib/schema/schemaDiffTableList.ts +++ b/apps/desktop/src/lib/schema/schemaDiffTableList.ts @@ -9,7 +9,7 @@ export interface SchemaDiffTableIdentity { } export interface SchemaDiffTableListLoader { - load(identity: SchemaDiffTableIdentity): Promise; + load(identity: SchemaDiffTableIdentity, options?: { refresh?: boolean }): Promise; } interface SchemaDiffTableListLoaderDependencies { @@ -46,12 +46,12 @@ export function createSchemaDiffTableListLoader(dependencies: SchemaDiffTableLis const pending = new Map>(); return { - async load(identity) { + async load(identity, options) { const key = identityKey(identity); const inFlight = pending.get(key); if (inFlight) return inFlight; - const cached = successful.get(key); + const cached = options?.refresh ? undefined : successful.get(key); if (cached) { await dependencies.ensureConnected(identity.connectionId); return cached;