fix(db): add CHECK constraint for userId XOR guestToken invariant
The Order entity Javadoc states "Either userId or guestToken is set;
never both, never neither" but only the @PrePersist lifecycle callback
enforced this in Java. A stray INSERT (admin tooling, manual SQL) could
violate it silently — creating an order with neither set (invisible to
both JWT and guest lookup paths) or both set (ambiguous ownership).
Changes:
- V13 Flyway migration adds a CHECK constraint on the orders table:
CHECK ((user_id IS NULL) <> (guest_token IS NULL))
This evaluates TRUE when exactly one column is NULL (the other is
set), and FALSE when both are NULL or both are set.
- Standard SQL CHECK constraint, supported by both H2 (tests/dev) and
PostgreSQL (prod).
Verified:
- Flyway migration check passes (V13 is next available version)
- ./gradlew :backend:test — BUILD SUCCESSFUL (all tests pass)
- H2 accepts the constraint at Flyway migration time
Closes #23
This commit is contained in:
parent
48c2a50c5d
commit
928a995298
1 changed files with 17 additions and 0 deletions
|
|
@ -0,0 +1,17 @@
|
|||
-- Enforce the Order entity invariant at the database level: exactly one of
|
||||
-- (user_id, guest_token) must be set — never both, never neither.
|
||||
--
|
||||
-- The Order Javadoc states "Either userId or guestToken is set; never both,
|
||||
-- never neither", but previously only the @PrePersist lifecycle callback
|
||||
-- enforced this in Java. A stray INSERT (admin tooling, manual SQL) could
|
||||
-- violate it silently.
|
||||
--
|
||||
-- The CHECK expression (user_id IS NULL) <> (guest_token IS NULL) evaluates:
|
||||
-- TRUE when exactly one column is NULL (the other is set) — allowed
|
||||
-- FALSE when both are NULL or both are set — rejected
|
||||
--
|
||||
-- Standard SQL CHECK constraint, supported by both H2 (tests/dev) and
|
||||
-- PostgreSQL (prod).
|
||||
ALTER TABLE orders
|
||||
ADD CONSTRAINT chk_user_or_guest
|
||||
CHECK ((user_id IS NULL) <> (guest_token IS NULL));
|
||||
Loading…
Reference in a new issue