import type { CatalogRelationship, CatalogRepository } from "./types.js"; export interface EffectiveRelationshipSnapshotReader { list(databaseId: string): Promise; } export interface EffectiveRelationshipSnapshotCoordinator { run(databaseId: string, operation: () => Promise): Promise; } export class EffectiveRelationshipSnapshotStaleError extends Error {} interface EffectiveRelationship { sourceTable: string; sourceColumns: string[]; targetTable: string; targetColumns: string[]; origin: CatalogRelationship["origin"]; } interface EffectiveRelationshipSnapshot { schemaVersion: 1; workspaceId: string; relationships: EffectiveRelationship[]; } const originRank: Record = { physical: 0, manual: 1, generated: 2, }; function endpointKey(relationship: EffectiveRelationship): string { return [ relationship.sourceTable, relationship.sourceColumns.join("\u0000"), relationship.targetTable, relationship.targetColumns.join("\u0000"), ].join("\u0001"); } function compareRelationships(left: EffectiveRelationship, right: EffectiveRelationship): number { return endpointKey(left).localeCompare(endpointKey(right)) || originRank[left.origin] - originRank[right.origin]; } /** * Adapter from the mutable Catalog model to the immutable relationship contract consumed by the * harness. The returned JSON is a deterministic projection, never an authored second store. */ export class EffectiveRelationshipSnapshotProvider { constructor( private readonly repository: Pick, private readonly relationships: EffectiveRelationshipSnapshotReader, private readonly operations: EffectiveRelationshipSnapshotCoordinator, ) {} async render(workspaceId: string): Promise { const database = await this.repository.getByWorkspace(workspaceId); if (!database) return undefined; return await this.operations.run(database.id, async () => { const current = await this.repository.get(database.id); if (!current || current.schemaSyncedVersion !== current.version) { throw new EffectiveRelationshipSnapshotStaleError( "effective relationship snapshot requires a current full schema synchronization", ); } const projected = (await this.relationships.list(database.id)) .filter((relationship) => relationship.status === "active") .map((relationship): EffectiveRelationship => ({ sourceTable: relationship.sourceTableName, sourceColumns: relationship.columns.map((column) => column.sourceColumnName), targetTable: relationship.targetTableName, targetColumns: relationship.columns.map((column) => column.targetColumnName), origin: relationship.origin, })) .sort(compareRelationships); const seen = new Set(); const snapshot: EffectiveRelationshipSnapshot = { schemaVersion: 1, workspaceId, relationships: projected.filter((relationship) => { const key = endpointKey(relationship); if (seen.has(key)) return false; seen.add(key); return true; }), }; return `${JSON.stringify(snapshot, null, 2)}\n`; }); } }