Throw on mismatched filters in EntityFilter.merge and cover merged-query row distribution - #1317
Conversation
Silently dropping a filter that doesn't match the batch operator would leave its already registered in-memory index without the matching db rows. This is reachable through an operation key collision: a single-child And prints the same key as its flat filter. Also extend the storage mock with stubbed rows filtered by EntityFilter.matches, and cover that rows of a merged query are distributed to the matching filter indices. https://claude.ai/code/session_01RPHfND7Ge1qS598LWPvfif
…into claude/entity-filter-merge-hardening
📝 WalkthroughWalkthroughAdds EntityFilter.getParams and stricter merge validation that throws on incompatible batched filters; updates LoadLayer error context to include operation and params; extends MockIndexer to return filtered dbEntities; adds tests verifying getParams, merge error, and merged-query row distribution. ChangesFilter merge validation with integration test support
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
A failed storage query was logged as the executed filter's internal representation, which after batch merging is a query the user never wrote. Log the operation key with the values bound to its placeholders instead, so the log maps back to the getWhere calls in handlers. https://claude.ai/code/session_01RPHfND7Ge1qS598LWPvfif
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/envio/src/LoadLayer.res (1)
400-410:⚠️ Potential issue | 🟡 MinorFix operation/params mismatch in merged Eq→In error logging context
In
packages/envio/src/LoadLayer.resthe loggedoperationcomes from the outer input filter’stoOperationKey(e.g.Eq=>getWhere({field: $1})), but the loggedparamscome from the merged query loop variable’sgetParams(e.g. mergedIn=> params is the whole array for_in). So Eq→In batching can produce an operation showing a single$1while params contains multiple values.Consider updating the catch block to derive
operationfrom the mergedfilter(inside themap) or explicitly annotate thatparamscome from an Eq→In merged batch.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/envio/src/LoadLayer.res` around lines 400 - 410, The logged "operation" currently uses the outer variable key while "params" uses the merged loop variable filter, causing Eq→In mismatch; inside the merged-query catch/map where you build params (the code referencing filter->EntityFilter.getParams), change the operation source to the merged filter's operation (use filter->EntityFilter.toOperationKey or equivalent on the same merged filter) so both operation and params come from the same filter instance, or alternatively add an explicit note in the logged message that params are from a merged batch; update the logging call that sets ~params and ~msg accordingly so operation and params stay consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@packages/envio/src/LoadLayer.res`:
- Around line 400-410: The logged "operation" currently uses the outer variable
key while "params" uses the merged loop variable filter, causing Eq→In mismatch;
inside the merged-query catch/map where you build params (the code referencing
filter->EntityFilter.getParams), change the operation source to the merged
filter's operation (use filter->EntityFilter.toOperationKey or equivalent on the
same merged filter) so both operation and params come from the same filter
instance, or alternatively add an explicit note in the logged message that
params are from a merged batch; update the logging call that sets ~params and
~msg accordingly so operation and params stay consistent.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 6141c829-aa44-4a9e-8d8f-82bbba8318a0
📒 Files selected for processing (3)
packages/envio/src/LoadLayer.respackages/envio/src/db/EntityFilter.resscenarios/test_codegen/test/EntityFilter_test.res
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/envio/src/db/EntityFilter.res
Hardening follow-up to #1316, addressing review findings.
Throw on mismatched filters in
EntityFilter.mergePreviously a filter that didn't match the batch's operator was silently dropped from the merged
Inquery. SinceloadByFilterregisters an in-memory index for every filter in the batch before querying, a dropped filter would resolve from an index that was never backfilled from the db — silently missing rows.This is reachable through an operation key collision:
toOperationKeyprints a single-childAnd({filters: [Eq({fieldName: "a"})]})identically to a flatEqona(User.getWhere({a: $1})), so the two can land in the same batch. Nothing constructs such a filter today, but before the merge optimization a key collision was harmless — now it would corrupt results, somergethrows loudly instead.Test coverage for merged-query row distribution
The storage mock previously always returned
[], so no test proved that rows returned by a mergedInquery are routed to the correct per-filter index.MockIndexer.Storage.makenow accepts~dbEntitiesand servesloadOrThrowby filtering them withEntityFilter.matches, behaving like a real db. New test asserts two concurrentgetWherecalls issue a single merged query and each resolves with only its own rows.https://claude.ai/code/session_01RPHfND7Ge1qS598LWPvfif
Generated by Claude Code
Summary by CodeRabbit