import { describe, expect, test, vi } from "vitest"; import { EffectiveRelationshipSnapshotProvider } from "../src/catalog/effective-relationship-snapshot.js"; import type { CatalogRelationship, WorkspaceDatabase } from "../src/catalog/types.js"; const timestamp = "2026-08-31T10:00:00.000Z"; function database(): WorkspaceDatabase { return { id: "database-1", workspaceId: "psd", engine: "postgres", databaseName: "warehouse", schema: "public", version: 1, createdAt: timestamp, updatedAt: timestamp, binding: { transport: "postgres_direct" }, connectionStatus: "reachable", schemaSyncedVersion: 1, schemaSyncedAt: timestamp, }; } const operations = { async run(_databaseId: string, operation: () => Promise): Promise { return await operation(); }, }; function relationship(options: { id: string; origin: "physical" | "generated" | "manual"; status?: "active" | "excluded"; sourceTable?: string; sourceColumns?: string[]; targetTable?: string; targetColumns?: string[]; }): CatalogRelationship { const sourceColumns = options.sourceColumns ?? ["user_id"]; const targetColumns = options.targetColumns ?? ["id"]; const columns = sourceColumns.map((sourceColumnName, position) => ({ position: position + 1, sourceColumnId: `source-${position}`, sourceColumnName, targetColumnId: `target-${position}`, targetColumnName: targetColumns[position], })); const common = { id: options.id, databaseId: "database-1", sourceTableId: "source-table", sourceTableName: options.sourceTable ?? "orders", targetTableId: "target-table", targetTableName: options.targetTable ?? "users", columns, createdAt: timestamp, updatedAt: timestamp, }; if (options.origin === "physical") { return { ...common, constraintName: `fk_${options.id}`, updateRule: "NO ACTION", deleteRule: "NO ACTION", deferrable: false, initiallyDeferred: false, lastSyncedDatabaseVersion: 1, lastSyncedAt: timestamp, origin: "physical", status: "active", }; } return { ...common, constraintName: null, updateRule: null, deleteRule: null, deferrable: false, initiallyDeferred: false, lastSyncedDatabaseVersion: null, lastSyncedAt: null, origin: options.origin, status: options.status ?? "active", columns: [columns[0]!], }; } describe("EffectiveRelationshipSnapshotProvider", () => { test("returns no projection for a workspace without a Catalog database", async () => { const list = vi.fn(); const provider = new EffectiveRelationshipSnapshotProvider( { get: vi.fn().mockResolvedValue(undefined), getByWorkspace: vi.fn().mockResolvedValue(undefined), }, { list }, operations, ); await expect(provider.render("legacy")).resolves.toBeUndefined(); expect(list).not.toHaveBeenCalled(); }); test("renders a deterministic active map with physical precedence", async () => { const duplicateGenerated = relationship({ id: "generated", origin: "generated" }); const physical = relationship({ id: "physical", origin: "physical" }); const compositePhysical = relationship({ id: "physical-composite", origin: "physical", sourceTable: "order_lines", sourceColumns: ["order_id", "tenant_id"], targetTable: "orders", targetColumns: ["id", "tenant_id"], }); const manual = relationship({ id: "manual", origin: "manual", sourceTable: "invoices", sourceColumns: ["customer_id"], targetTable: "customers", targetColumns: ["id"], }); const excluded = relationship({ id: "excluded", origin: "generated", status: "excluded", sourceTable: "invoices", }); const list = vi.fn().mockResolvedValue([ manual, duplicateGenerated, excluded, physical, compositePhysical, ]); const provider = new EffectiveRelationshipSnapshotProvider( { get: vi.fn().mockResolvedValue(database()), getByWorkspace: vi.fn().mockResolvedValue(database()), }, { list }, operations, ); const rendered = await provider.render("psd"); expect(rendered?.endsWith("\n")).toBe(true); expect(JSON.parse(rendered!)).toEqual({ schemaVersion: 1, workspaceId: "psd", relationships: [ { sourceTable: "invoices", sourceColumns: ["customer_id"], targetTable: "customers", targetColumns: ["id"], origin: "manual", }, { sourceTable: "order_lines", sourceColumns: ["order_id", "tenant_id"], targetTable: "orders", targetColumns: ["id", "tenant_id"], origin: "physical", }, { sourceTable: "orders", sourceColumns: ["user_id"], targetTable: "users", targetColumns: ["id"], origin: "physical", }, ], }); expect(list).toHaveBeenCalledWith("database-1"); }); test("fails closed when the Catalog schema is absent or stale", async () => { const stale = database(); delete stale.schemaSyncedVersion; delete stale.schemaSyncedAt; const list = vi.fn(); const provider = new EffectiveRelationshipSnapshotProvider( { get: vi.fn().mockResolvedValue(stale), getByWorkspace: vi.fn().mockResolvedValue(stale), }, { list }, operations, ); await expect(provider.render("psd")).rejects.toThrow( "effective relationship snapshot requires a current full schema synchronization", ); expect(list).not.toHaveBeenCalled(); }); });