Skip to content

fix: classify duplicate-key Insert as record.IsAlreadyExists - #30

Merged
trakhimenok merged 1 commit into
mainfrom
dalgo2sqlite-record-exists
Aug 23, 2026
Merged

trakhimenok merged 1 commit into
mainfrom
dalgo2sqlite-record-exists

Conversation

@trakhimenok

Copy link
Copy Markdown
Contributor

Summary

  • Bump dal-go/dalgo2sql to v0.11.0 (adds the DbOptions.IsAlreadyExists classifier hook), dal-go/dalgo to v0.66.1 (adds the now-passing unconditional dalgotest conformance check), and dal-go/record to v0.1.3 (adds ErrRecordExists/IsAlreadyExists).
  • Add IsAlreadyExists, this adapter's classifier for modernc.org/sqlite (the driver this repo actually uses — confirmed via go.mod, no mattn/go-sqlite3 dependency). It matches errors.As(err, *sqlite.Error) against the extended result codes SQLITE_CONSTRAINT_PRIMARYKEY (1555) and SQLITE_CONSTRAINT_UNIQUE (2067) — never on message text. Both codes are matched deliberately: a duplicate primary key reports 1555, not 2067, and is the commonest case (this repo's own conformance suite exercises exactly that path). The primary result code SQLITE_CONSTRAINT (19) is deliberately not matched, since it also covers NOT NULL/CHECK/FOREIGN KEY violations.
  • Wire it into NewDatabaseWithOptions as the default whenever the caller-supplied DbOptions.IsAlreadyExists is nil, so NewDatabase and every existing caller (including this package's own TestConformance) get classification with zero extra configuration, while still allowing an explicit override.
  • Exported (dalgo2sqlite.IsAlreadyExists) so a caller assembling a custom DbOptions can reuse or compose with it.

Verification

  • Cross-checked both constants against modernc.org/sqlite@v1.57.0's lib/sqlite.go, and confirmed the driver enables extended result codes on every connection it opens (conn.go's open() calls sqlite3_extended_result_codes(db, 1) unconditionally), so (*sqlite.Error).Code() reports the extended code, not the primary one.
  • Confirmed the wiring is load-bearing: temporarily reverting the NewDatabaseWithOptions default made TestConformance/rejects_an_Insert_over_an_existing_key_with_record.IsAlreadyExists fail with the driver reporting exactly extended code 1555.
  • New sqlite_classifier_test.go drives a real in-memory modernc.org/sqlite database (not hand-built error structs, since sqlite.Error's fields are unexported) to prove: a duplicate primary key is classified, a duplicate unique-index value is classified, and a NOT NULL violation and a CHECK violation are each not classified.
  • go build ./..., go vet ./..., gofmt -l . (clean), golangci-lint run ./... (0 issues), and go test -race ./... all pass, including the shared dalgotest conformance suite (SQLite is in-process, so it runs for real here — no env-gate, no skip).

Test plan

  • go build ./...
  • go vet ./...
  • gofmt -l .
  • golangci-lint run ./...
  • go test -race ./... (including TestConformance)
  • CI green on the PR

🤖 Generated with Claude Code

Bump dal-go/dalgo2sql to v0.11.0 (adds the DbOptions.IsAlreadyExists
classifier hook), dal-go/dalgo to v0.66.1 (adds the now-passing
unconditional dalgotest conformance check), and dal-go/record to v0.1.3
(adds ErrRecordExists/IsAlreadyExists).

Add IsAlreadyExists, this adapter's classifier for modernc.org/sqlite
(the pure-Go driver dalgo2sqlite registers): it matches
errors.As(err, *sqlite.Error) against the extended result codes
SQLITE_CONSTRAINT_PRIMARYKEY (1555) and SQLITE_CONSTRAINT_UNIQUE (2067),
never on message text. Both codes are matched deliberately — a duplicate
primary key reports 1555, not 2067, and is the commonest case (verified
against modernc.org/sqlite@v1.57.0's lib/sqlite.go and by confirming
this repo's own conformance suite fails with exactly that code when the
wiring below is reverted). The primary result code SQLITE_CONSTRAINT
(19) is deliberately not matched: it also covers NOT NULL, CHECK, and
FOREIGN KEY violations, none of which are duplicate keys.

Wire it into NewDatabaseWithOptions as the default whenever the
caller-supplied DbOptions leaves IsAlreadyExists nil, so NewDatabase and
every existing caller building their own DbOptions (including this
package's own TestConformance) get classification with no extra
configuration, while still allowing an explicit override. Exported so a
caller assembling a custom DbOptions from scratch can reuse or compose
with it directly.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@trakhimenok
trakhimenok merged commit c98694f into main Aug 23, 2026
3 checks passed
@trakhimenok
trakhimenok deleted the dalgo2sqlite-record-exists branch August 23, 2026 13:06
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.

1 participant