diff --git a/frontend/src/viewers/ArtifactView.test.tsx b/frontend/src/viewers/ArtifactView.test.tsx index 03342f4c..ccf02393 100644 --- a/frontend/src/viewers/ArtifactView.test.tsx +++ b/frontend/src/viewers/ArtifactView.test.tsx @@ -10,6 +10,11 @@ test("sql artifact renders the SQL text", () => { expect(screen.getByText("SELECT 1")).toBeInTheDocument(); }); +test("sql artifact accepts a { content } wrapper", () => { + render(); + expect(screen.getByText("SELECT 7")).toBeInTheDocument(); +}); + test("cte_plan renders an ordered list of names", () => { render(); expect(screen.getByText("a_cte")).toBeInTheDocument(); diff --git a/frontend/src/viewers/ArtifactView.tsx b/frontend/src/viewers/ArtifactView.tsx index d1b00643..14903191 100644 --- a/frontend/src/viewers/ArtifactView.tsx +++ b/frontend/src/viewers/ArtifactView.tsx @@ -38,6 +38,7 @@ function toSqlBlocks(raw: unknown): SqlBlock[] | null { const rec = asRecord(raw); if (!rec) return null; if (typeof rec.sql === "string") return [{ name: "SQL", sql: rec.sql }]; + if (typeof rec.content === "string") return [{ name: "SQL", sql: rec.content }]; if (Array.isArray(rec.ctes)) { const blocks = rec.ctes .map((c) => asRecord(c)) diff --git a/frontend/src/viewers/SchemaLinkingViewer.test.tsx b/frontend/src/viewers/SchemaLinkingViewer.test.tsx index 8a706196..a5e1a699 100644 --- a/frontend/src/viewers/SchemaLinkingViewer.test.tsx +++ b/frontend/src/viewers/SchemaLinkingViewer.test.tsx @@ -97,3 +97,16 @@ test("(e) buildErDiagram emits entities, attributes and a relation", () => { expect(def).toContain("col id"); expect(def).toContain("orders }o--o{ customers : join"); }); + +test("(f) buildErDiagram uses a column's real type when the data carries one", () => { + const def = buildErDiagram( + [ + { kind: "table", name: "orders", decision: "promoted" }, + { kind: "column", name: "orders.total", decision: "promoted", signals: { data_type: "numeric" } }, + { kind: "column", name: "orders.id", decision: "promoted" }, // no type -> generic "col" + ], + [], + ); + expect(def).toContain("numeric total"); + expect(def).toContain("col id"); +}); diff --git a/frontend/src/viewers/SchemaLinkingViewer.tsx b/frontend/src/viewers/SchemaLinkingViewer.tsx index cc9c6b1c..b8f18074 100644 --- a/frontend/src/viewers/SchemaLinkingViewer.tsx +++ b/frontend/src/viewers/SchemaLinkingViewer.tsx @@ -33,6 +33,19 @@ function reasonFor(c: Candidate): string { return ""; } +// The real DB type for a promoted column, when the schema-linking data carries it +// (`data_type`/`type`, at top level or under `signals`). Today's schema_linking.json +// has no column types, so this falls back to the generic `col` token that Mermaid +// still needs as the attribute type; a real type shows as soon as the pipeline +// provides one. The token is sanitized to keep the erDiagram valid. +function attrType(c: Candidate): string { + const sig = (c.signals ?? {}) as Record; + const rec = c as unknown as Record; + const raw = sig["data_type"] ?? sig["type"] ?? rec["data_type"] ?? rec["type"]; + const t = typeof raw === "string" && raw.trim() ? raw.trim() : "col"; + return t.replace(/[^a-zA-Z0-9]/g, "_"); +} + export function buildErDiagram(promoted: Candidate[], joins: Join[]): string { const sanitize = (name: string) => name.replace(/[^a-zA-Z0-9]/g, "_"); const tables = promoted.filter((c) => c.kind === "table"); @@ -46,7 +59,7 @@ export function buildErDiagram(promoted: Candidate[], joins: Join[]): string { const cols = columns.filter((col) => col.name.startsWith(t.name + ".")); lines.push(` ${id} {`); for (const col of cols) { - lines.push(` col ${sanitize(col.name.slice(t.name.length + 1))}`); + lines.push(` ${attrType(col)} ${sanitize(col.name.slice(t.name.length + 1))}`); } lines.push(` }`); }