fix(db): stamp the dialect into generated query files
Quality / quality (ubuntu-latest) (push) Failing after 12m46s
Quality / quality (windows-latest) (push) Canceled after 0s

The same generate command emitted ? one run and $1 the next, which looked
like non-determinism. It is not: postgres uses $1 placeholders where
sqlite and mysql use ?, and the driver comes from the active profile, so
building under a different profile rewrites this committed file.

The header now records the dialect it was generated for, making the flip
visible in the diff and explaining check:generated-types failures instead
of leaving them looking like random churn.

Worth deciding separately: a committed artifact whose contents depend on
the active profile will keep drifting. Either generate per dialect, or
stop committing it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-18 19:44:36 +05:30
co-authored by Claude Opus 5
parent 5dbcc5b85d
commit b3b65dddd8
3 changed files with 32 additions and 2 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
// AUTO-GENERATED by `wrnexus db generate` — do not edit.
// AUTO-GENERATED by `wrnexus db generate` (dialect: sqlite) — do not edit.
import type { Db, ExecResult } from "@wrnexus/db";
import { users } from "./schema.ts";
+8 -1
View File
@@ -230,5 +230,12 @@ export function generateQueriesFile(
if (usedModels.size > 0) {
imports.push(`import { ${[...usedModels].sort().join(", ")} } from "./schema.ts";`);
}
return `// AUTO-GENERATED by \`wrnexus db generate\` — do not edit.\n${imports.join("\n")}\n\n${blocks.join("\n\n")}\n`;
// The dialect is stamped into the header because it changes the emitted SQL:
// postgres uses $1 placeholders where sqlite and mysql use ?. Regenerating
// under a different profile therefore rewrites this committed file, and
// without the stamp the diff looks like unexplained churn.
return (
`// AUTO-GENERATED by \`wrnexus db generate\` (dialect: ${dialect}) — do not edit.\n` +
`${imports.join("\n")}\n\n${blocks.join("\n\n")}\n`
);
}
+23
View File
@@ -0,0 +1,23 @@
import { expect, test } from "bun:test";
import { generateQueriesFile, parseQueries } from "../src/generate.ts";
const queries = parseQueries(`-- name: GetUser :one\nSELECT * FROM users WHERE email = :email;\n`);
test("the generated header records the dialect it was built for", () => {
// The same command emits different SQL per dialect, so a build under another
// profile rewrites the committed file. The stamp makes that visible in the
// diff instead of looking like unexplained churn.
expect(generateQueriesFile(queries, [], "sqlite")).toContain("(dialect: sqlite)");
expect(generateQueriesFile(queries, [], "postgres")).toContain("(dialect: postgres)");
});
test("placeholder style follows the dialect", () => {
expect(generateQueriesFile(queries, [], "sqlite")).toContain("email = ?");
expect(generateQueriesFile(queries, [], "postgres")).toContain("email = $1");
});
test("generation is deterministic for a fixed dialect", () => {
const first = generateQueriesFile(queries, [], "postgres");
const second = generateQueriesFile(queries, [], "postgres");
expect(first).toBe(second);
});