fix(db): timestamp columns store a real ISO value on omit, not the literal string - #656
Conversation
…he literal string
drizzle's `.default("CURRENT_TIMESTAMP")` is a STATIC default: drizzle applies
it client-side and injects the literal string "CURRENT_TIMESTAMP" into any
insert that omits the column (it never reaches SQLite's CURRENT_TIMESTAMP
function, even though the migration DDL uses the real default). This corrupted
timestamp columns on omit — observed in prod on webhook_events.received_at,
which broke ordering/time-range queries on that table.
Replace all 59 `.default("CURRENT_TIMESTAMP")` with `.$defaultFn(() => nowIso())`
so an omitted timestamp column gets a real ISO-8601 value consistent with every
explicit nowIso() insert. App-layer only — no migration, prod column DDL already
uses a valid default; this just stops drizzle from injecting the bad literal.
Behavioral tests confirm omitted receivedAt/createdAt/updatedAt now store ISO
timestamps, never "CURRENT_TIMESTAMP".
|
gittensory · advisory review Reviewed 2 changed file(s) — two independent AI reviewers. Suggested action: ✅ Safe to merge — both reviewers found no blocking issues. Reviewer A · Suggestions
Worth double-checking
Reviewer B · No blocking issues spotted. |
|
Note Gittensory Gate skippedPR closed before full evaluation. No late first comment was created.
💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by Gittensory, a quiet PR intelligence layer for OSS maintainers. |
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
1 similar comment
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
The bug
Found while investigating the gate hang: prod
webhook_events.received_atcontained the literal string"CURRENT_TIMESTAMP"for a range of rows, which breaks ordering and time-range queries on that table.Root cause: drizzle's
.default("CURRENT_TIMESTAMP")is a static default — drizzle applies it client-side and injects the literal string"CURRENT_TIMESTAMP"into any insert that omits the column. It never reaches SQLite'sCURRENT_TIMESTAMPfunction (the migration DDL, e.g.migrations/0001_initial.sql, does use a validDEFAULT CURRENT_TIMESTAMP, but drizzle pre-empts it). So every timestamp column that an insert omits gets the bad literal instead of a timestamp. This pattern is used on 59 columns across the schema.The fix
Replace every
.default("CURRENT_TIMESTAMP")with.$defaultFn(() => nowIso()), so drizzle injects a real ISO-8601 timestamp on omit — consistent with thenowIso()value every explicit insert already uses.src/testdepends on the literal string; there is no drizzle schema-drift check in CI.Tests
Behavioral tests insert rows omitting
receivedAt/createdAt/updatedAtand assert the stored values are ISO-8601 and never"CURRENT_TIMESTAMP". Full suite green; coverage holds above the 97% gate; Workers-runtime tests pass.Note
Existing historical rows still hold the literal (fixing those needs a backfill/table rebuild on the ~2.8GB prod D1 — out of scope here). This stops new bad writes.
Separate from #652 (AI review/BYOK) and #655 (gate finalize-on-error); all three came out of the same gate-hang investigation.