fix(schema-diff): refresh table lists before comparing

This commit is contained in:
jearhe authored and GitHub committed 2026-08-27 08:38:20 +08:00
1 parent 168e7bcb54
commit 6875ca4000
3 files changed
+23 -5

No files matched your search

@@ -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).
@@ -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<SchemaDiffTableSide, SchemaDiffTableIdentity> = {
@@ -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");
@@ -9,7 +9,7 @@ export interface SchemaDiffTableIdentity {
}
export interface SchemaDiffTableListLoader {
load(identity: SchemaDiffTableIdentity): Promise<TableInfo[]>;
load(identity: SchemaDiffTableIdentity, options?: { refresh?: boolean }): Promise<TableInfo[]>;
}
interface SchemaDiffTableListLoaderDependencies {
@@ -46,12 +46,12 @@ export function createSchemaDiffTableListLoader(dependencies: SchemaDiffTableLis
const pending = new Map<string, Promise<TableInfo[]>>();
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;