fix(sidebar): keep multi-object DDL in one connection context

This commit is contained in:
zipg authored and GitHub committed 2026-08-05 11:11:29 +08:00
1 parent 200d6f55ab
commit 4cd88384ba
5 files changed
+136 -26

No files matched your search

@@ -0,0 +1,38 @@
import { describe, expect, it, vi } from "vitest";
import { buildSidebarDdlTemplateSql, sidebarDdlTargetsForExecutionContext } from "@/lib/sidebar/sidebarDdlTemplate";
describe("sidebar DDL template", () => {
it("preserves the single-target SQL", async () => {
const sql = await buildSidebarDdlTemplateSql(
["one"],
async () => "CREATE TABLE one (id INT)",
async (ddl) => ddl,
);
expect(sql).toBe("CREATE TABLE one (id INT)");
});
it("loads, formats, and joins multiple targets in order", async () => {
const loadDdl = vi.fn(async (target: string) => `CREATE TABLE ${target} (id INT)`);
const formatDdl = vi.fn(async (ddl: string, target: string) => `${ddl} /* ${target} */`);
const sql = await buildSidebarDdlTemplateSql(["one", "two"], loadDdl, formatDdl);
expect(loadDdl.mock.calls).toEqual([["one"], ["two"]]);
expect(formatDdl.mock.calls).toEqual([
["CREATE TABLE one (id INT)", "one"],
["CREATE TABLE two (id INT)", "two"],
]);
expect(sql).toBe("CREATE TABLE one (id INT) /* one */;\n\nCREATE TABLE two (id INT) /* two */;\n");
});
it("keeps DDL targets in the active SQL execution context", () => {
const active = { id: "active", connectionId: "c1", database: "db1", catalog: "catalog1" };
const sameContext = { id: "same", connectionId: "c1", database: "db1", catalog: "catalog1" };
const otherDatabase = { id: "database", connectionId: "c1", database: "db2", catalog: "catalog1" };
const otherConnection = { id: "connection", connectionId: "c2", database: "db1", catalog: "catalog1" };
const otherCatalog = { id: "catalog", connectionId: "c1", database: "db1", catalog: "catalog2" };
expect(sidebarDdlTargetsForExecutionContext(active, [active, otherDatabase, sameContext, otherConnection, otherCatalog])).toEqual([active, sameContext]);
});
});
@@ -21,9 +21,10 @@ describe("sidebar export runtime", () => {
it("freezes the accepted structure selection before export work starts", () => {
const first: TreeNode = { id: "t1", label: "one", type: "table", connectionId: "c1", database: "db" };
const second: TreeNode = { id: "t2", label: "two", type: "view", connectionId: "c1", database: "db" };
const group: TreeNode = { id: "group", label: "Tables", type: "group-tables", children: [first, second] };
const third: TreeNode = { id: "t3", label: "three", type: "materialized_view", connectionId: "c1", database: "db" };
const group: TreeNode = { id: "group", label: "Tables", type: "group-tables", children: [first, second, third] };
expect(sidebarStructureExportTargets(first, [group], [first.id, second.id])).toEqual([first, second]);
expect(sidebarStructureExportTargets(first, [group], [third.id, first.id, second.id])).toEqual([first, second, third]);
expect(sidebarStructureExportTargets(first, [group], [second.id])).toEqual([first]);
});
});
@@ -0,0 +1,19 @@
import { joinExportedDdls } from "@/lib/export/ddlExport";
interface SidebarDdlExecutionTarget {
connectionId: string;
database: string;
catalog?: string;
}
export function sidebarDdlTargetsForExecutionContext<T extends SidebarDdlExecutionTarget>(activeTarget: SidebarDdlExecutionTarget, targets: readonly T[]): T[] {
return targets.filter((target) => target.connectionId === activeTarget.connectionId && target.database === activeTarget.database && (target.catalog ?? "") === (activeTarget.catalog ?? ""));
}
export async function buildSidebarDdlTemplateSql<T>(targets: readonly T[], loadDdl: (target: T) => Promise<string>, formatDdl: (ddl: string, target: T) => Promise<string>): Promise<string> {
const parts: string[] = [];
for (const target of targets) {
parts.push(await formatDdl(await loadDdl(target), target));
}
return parts.length === 1 ? parts[0]! : joinExportedDdls(parts);
}