Add ErrRecordExists sentinel and IsAlreadyExists predicate - #2
Merged
Merged
Conversation
Insert is specified to fail when a key already exists, but there was no exported way to tell that failure apart from any other insert error — the mirror-image gap of ErrRecordNotFound/IsNotFound. Downstream consumers (sneat-co/slugs, bookius) currently must treat every insert failure as "slug taken", so a transient backend blip is misreported to users as a name collision. ErrRecordExists/IsAlreadyExists follow the exact ErrRecordNotFound/IsNotFound idiom: a wrapped sentinel plus an errors.Is-based predicate. IsAlreadyExists positively identifies a confirmed conflict; false is not proof of the opposite, because an adapter that hasn't adopted the sentinel yet will never return it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
8 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ErrRecordExistsandIsAlreadyExists, the mirror image of the existingErrRecordNotFound/IsNotFoundpair, so an adapter that can reliably tell "insert failed because the key already exists" from any other insert failure has an exported sentinel/predicate to use.errors.Newsentinel plus anerrors.Is-based predicate, documented with the caveat thatfalseis not proof of "not a conflict" — only adapters that adopt the sentinel reporttrue.Why
Insertis specified to fail when a key already exists, and adapters already implement that, but there is no way for a caller to distinguish that failure from any other insert error. This has already caused a real defect:sneat-co/slugsclaims a unique slug viatx.Insertand, lacking any way to tell "already exists" apart, treats every insert failure asErrSlugTaken— so a transient backend blip is misreported to a user as their chosen name being taken.sneat-co/bookiushas the identical issue.This is step 1 of a 3-repo rollout:
dal-go/record(this PR) →dal-go/dalgo(adapters + conformance suite) →dal-go/dalgo2firestore(the adapter that actually fixes the live defect, since Firestore is what Sneat runs on).Test plan
go build ./...go vet ./...go test -race ./... -covergofmt -l .(clean except a pre-existing, untouchedupdate/update.gofinding)golangci-lint run ./...(0 issues)errors_test.gocovers both predicates: true on the sentinel (bare and wrapped), false onnil, the other sentinel, and an unrelated error🤖 Generated with Claude Code