Skip to content

feat(db): atomic update expressions — d.expr, d.increment, d.decrement (#1743)#2292

Merged
viniciusdacal merged 6 commits into
mainfrom
feat/db-update-expressions
Apr 4, 2026
Merged

feat(db): atomic update expressions — d.expr, d.increment, d.decrement (#1743)#2292
viniciusdacal merged 6 commits into
mainfrom
feat/db-update-expressions

Conversation

@viniciusdacal
Copy link
Copy Markdown
Contributor

Summary

Adds atomic column-level update expressions to @vertz/db, enabling database-side operations without read-modify-write cycles.

  • d.increment(n) / d.decrement(n) — atomic arithmetic on numeric columns
  • **d.expr(col => sql\...`)** — arbitrary SQL expressions (e.g. LOWER(), COALESCE()`)
  • Works in update, updateMany, upsert, and ON CONFLICT DO UPDATE SET
  • Full PostgreSQL and SQLite dialect support
  • Type-safe: $update and $update_input accept InferColumnType<T> | DbExpr

Public API Changes

New exports from @vertz/db

  • DbExpr (type) — expression descriptor interface
  • isDbExpr() — type guard
  • sql — re-exported tagged template for use with d.expr()
  • SqlFragment (type) — for advanced expression composition

New methods on d

  • d.expr(col => sql\...`)` — general-purpose column expression
  • d.increment(n) — sugar for d.expr(col => sql\${col} + ${n}`)`
  • d.decrement(n) — sugar for d.expr(col => sql\${col} - ${n}`)`

Bug fix

  • autoUpdate() columns with user-provided DbExpr were silently overwritten by the NOW() sentinel because autoUpdate() sets isReadOnly: true, causing the readOnly filter to strip the expression before the autoUpdate guard could see it. Fixed by allowing DbExpr values through the readOnly filter on autoUpdate columns.

Files changed

Test plan

  • 13 unit tests for DbExpr, isDbExpr, d.expr(), d.increment(), d.decrement()
  • 7 tests for DbExpr in buildUpdate (increment, decrement, expr, multi-param, mixed, now-override, constant)
  • 3 tests for DbExpr in buildInsert ON CONFLICT (increment, expr, mixed)
  • 3 SQLite dialect tests for DbExpr in buildUpdate and buildInsert
  • 6 unit tests for renumberParamsWithDialect()
  • 1 CRUD-level regression test for autoUpdate + DbExpr interaction
  • Type-level tests (.test-d.ts) — positive and negative tests for DbExpr in $update and $update_input
  • Typecheck clean (no new errors in changed files)
  • turbo run build typecheck test --filter='@vertz/db' passes

Closes #1743

🤖 Generated with Claude Code

viniciusdacal and others added 6 commits April 4, 2026 20:12
…ypes #1743

Introduce column-relative SQL expressions for update operations.
- DbExpr interface and isDbExpr() type guard in sql/expr.ts
- d.expr(), d.increment(), d.decrement() on the d namespace
- Widen $update and $update_input types to accept DbExpr
- Re-export sql from main @vertz/db entry for single-import DX
- Export DbExpr type and isDbExpr from both @vertz/db and @vertz/db/sql

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…yer #1743

- Export renumberParamsWithDialect() from tagged.ts for dialect-aware
  fragment composition (supports both $N and ? param styles)
- buildUpdate: detect DbExpr values in SET clause, compose SqlFragment
  with correct param renumbering
- buildInsert: detect DbExpr values in ON CONFLICT DO UPDATE SET clause
  for upsert expression support
- Fix autoUpdate injection to not overwrite user-provided values/expressions
  in update(), updateMany(), and upsert()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ypass (#1743)

- SQLite dialect tests for DbExpr in buildUpdate and buildInsert
- Type-level tests (.test-d.ts) for DbExpr in $update and $update_input
- Unit tests for renumberParamsWithDialect()
- Regression test for autoUpdate + DbExpr interaction
- Fix: allow DbExpr through readOnly filter on autoUpdate columns

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add documentation for d.expr(), d.increment(), d.decrement() in
the queries guide. Update sql import path to vertz/db.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ns (#1743)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@viniciusdacal viniciusdacal merged commit 5d23ced into main Apr 4, 2026
7 checks passed
This was referenced Apr 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(db): add increment/decrement operations to update()

1 participant