Skip to content

feat(database): typed constraint violations across dialects - #95

Merged
Makisuo merged 4 commits into
MapleTechLabs:mainfrom
artile:feat/constraint-errors
Nov 2, 2026
Merged

Makisuo merged 4 commits into
MapleTechLabs:mainfrom
artile:feat/constraint-errors

Conversation

@artile

@artile artile commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Closes #71

…tement timeout

ClickHouse code 469 is VIOLATED_CONSTRAINT (a failed CHECK). Effect's Node
driver reads it as StatementTimeoutError, which says retry. The HTTP client
copied that; it now gives ConstraintError.
refineConstraints turns a DatabaseError or TransactionCommitFailed for a
broken constraint into UniqueViolation, ForeignKeyViolation,
NotNullViolation or CheckViolation, with the constraint, table and column
the server named. Postgres: SQLSTATE 23505, 23503, 23502, 23514. ClickHouse:
code 469 is CheckViolation, named from the message.

DatabaseError and TransactionCommitFailed keep the server's numeric code as
errorCode, which sqlStateOf dropped for ClickHouse.
@coderabbitai

coderabbitai Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 49 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: f6c14769-fa2a-424b-9062-6082c48d975a
Commits

Reviewing files that changed from the base of the PR and between b57faf1 and 6967bcf.

Files selected for processing: 14
  • .changeset/constraint-errors.md
  • design/gap-review.md
  • docs/database.md
  • docs/reference.md
  • src/clickhouse-http/client.test.ts
  • src/clickhouse-http/client.ts
  • src/database.ts
  • src/database/constraint.test.ts
  • src/database/constraint.ts
  • src/database/database.test-d.ts
  • src/database/database.ts
  • src/database/errors.ts
  • src/database/sql-error.ts
  • tests/database.clickhouse.test.ts
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@artile
artile marked this pull request as ready for review October 25, 2026 15:02
… constraint errors

Merges main (SQLite/D1 dialects, Effect 4.0.6, afterCommit) and keeps
errorCode on the new COMMIT-failure path in restoreCause. refineConstraints
now reads SQLite's extended result code (node:sqlite errcode, D1 message)
so UNIQUE, PRIMARYKEY, FOREIGNKEY, NOTNULL and CHECK map to the same tagged
errors, with the table and column SQLite names.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Makisuo

Makisuo commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

Merge-readiness pass (head 6967bcf):

Changed

  • Merged main (SQLite/D1 dialects, Effect 4.0.6, afterCommit). The one real conflict was restoreCause: main now handles a COMMIT SqlError failure as well as a defect, so I kept main's version and carried errorCode onto that path.
  • SQLite and D1 constraint errors are classified too, since those dialects exist now. sqliteConstraintOf reads SQLite's extended result code from node:sqlite's errcode (via @effect/sql-sqlite-node), or from D1's message (... (extended: SQLITE_CONSTRAINT_UNIQUE), because @effect/sql-d1 classifies everything as UnknownError). UNIQUE/PRIMARYKEY map to UniqueViolation, and FOREIGNKEY, NOTNULL and CHECK map to their own errors. SQLite names no unique index, so a unique or NOT NULL violation gets table and, when the key has a single column, column. A CHECK gets its name (or its expression when it has no name) as constraint. Effect's SQLite UniqueViolation reason calls the column list "t.email" its constraint, so SQLite fields come from the message, not the reason. errorCode stays ClickHouse-only.
  • Tests: node:sqlite and D1 (Miniflare) cover every kind, plus a composite unique key and a non-constraint error. There is also a deferred FK on SQLite that fails at COMMIT and comes back as ForeignKeyViolation wrapping TransactionCommitFailed.
  • Docs (database.md table with a SQLite/D1 column), error JSDoc, gap-review.md and the changeset now mention SQLite/D1.

Verified

  • bun run typecheck, then bun run test with a live ClickHouse 26.8: 74 files, 1442 tests, plus doc checks, all green. The live CheckViolation test (code 469) passes.
  • FUZZ_SCALE=0.3 vitest run tests/fuzz: one run hit "generated fixtures: union results agree (postgres)", a generated-fixture flake. It passed on three reruns and this PR does not touch compile or query paths.
  • CI run 41472684990 passed.

@Makisuo
Makisuo merged commit 2b6873a into MapleTechLabs:main Nov 2, 2026
3 checks passed
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.

Typed constraint errors across dialects

2 participants