fix(cache): invalidate identity-keyed entries on compound-key updates#26
Closed
alexstandiford wants to merge 2 commits into
Closed
fix(cache): invalidate identity-keyed entries on compound-key updates#26alexstandiford wants to merge 2 commits into
alexstandiford wants to merge 2 commits into
Conversation
where()/getModels() hydration caches each row under its table identity (primary columns). updateCompound() only invalidated the caller-provided compound context, so an update keyed on a compound business key (e.g. a config row's type/subtype/configKey) left the identity-keyed cache entry serving the pre-update row until TTL — observed in production-shaped E2E as reads returning stale entities after writes. updateCompound() now resolves the row's table identity before the update and invalidates that context too. The resolution is skipped for the common update-by-identity path (the caller's key already IS the identity) and for tables without identity fields. Identity values are projected from the query result so the cache context contains identity fields only, regardless of what the query strategy returns. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ution - from() before select(): the builder prefixes selected columns with the current table's alias, which is stale until from() runs. - When the caller's key has the same fields as the table identity in a different order, reorder locally instead of querying — the cache context is order-sensitive. - Resolution failures degrade to a possibly-stale entry (logged) instead of breaking the write. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.
where()/getModels()hydration caches each row under its table identity (primary columns).updateCompound()only invalidated the caller-provided compound context — so an update keyed on a compound business key (e.g. a config row's type/subtype/configKey) left the identity-keyed entry serving the pre-update row until TTL.Found in Siren: with a persistent cache backing (Redis), REST reads returned stale entities after writes for every field stored via compound-key updates, and it reproduced against any working cache. Sibling of the int/string identity divergence fixed in 6e423f7 — same cache, third key-shape mismatch.
Fix: resolve the row's table identity before the update and invalidate that context too. Skipped when the caller's key already is the table identity (the common update-by-id path — no extra query) and for tables without identity fields. Identity values are projected from the query result so the context contains identity fields only.
Includes a regression test (
testUpdateByCompoundBusinessKeyInvalidatesIdentityKeyedEntry). All 18 package tests green.Downstream note: Siren also carries this fix in its tenant-scoped handler override (Novatorius/siren#195), which additionally handles tenant-decorated/bare key variants the framework can't know about — that override stays correct with or without this patch.
🤖 Generated with Claude Code