fix(metadata)!: a $filter array that is not a filter AST is rejected, not passed through (#4121) - #4200
Merged
Merged
Conversation
…4121) isFilterAST was read as a CONVERSION gate: an array it refused was assigned to options.where unconverted, leaving each backend to make sense of a value the protocol had already decided it could not parse. Filed as item 2 of #3948 — error locality. The investigation found more. It closes the last silently-unfiltered shape. #3948 made the drivers throw on a bare triple with an unknown operator and on any element that is neither a join keyword nor a condition array. What it could not reach is a lone ['and'] / ['or']: the driver sets its join mode, matches no element, emits NO predicate, and returns every row. isFilterAST refuses it (a logical node needs length >= 2), so it arrived as an opaque `where` and no driver-side check applied. For every other shape this is not a narrowing: driver-sql throws, driver-memory throws, driver-mongodb fails at the server. This changes WHICH error the caller sees, not whether there is one — and puts the request's own vocabulary in the message instead of a driver's builder state. Scoped narrowly, because the regression to fear is rejecting something valid: - only arrays are in scope; a `where` OBJECT is untouched ($and/$or/$gte); - an empty [] is left alone — it means "no filter"; - isFilterAST accepts nested arrays, so [[a,'=',1],[b,'=',2]] and ['and', […], ['or', …]] keep converting. A naive "arrays are suspect" rule would have broken those, so the accepted shapes are pinned by more tests than the rejected ones. status 400 + code INVALID_FILTER, matching UNSUPPORTED_QUERY_PARAM alongside. 12 new tests driving the real findData normalisation rather than a re-implementation of its rule; reverting the change fails six. Package suite 122 tests / 19 files green. Closes #4121. Refs #3948, objectstack-ai/objectui#2945 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 1 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
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.
Closes #4121. Filed as item 2 of #3948 — error locality. The investigation found it is more than that.
It closes the last silently-unfiltered shape
#3948 made the drivers throw on a bare triple with an unknown operator, and on any element that is neither a join keyword nor a condition array. What it could not reach is a lone
['and']/['or']:No driver-side check applies, because there is no offending element to reject — the array is well-formed and empty of conditions. It is the last survivor of the class #3948 closed, and it is now a 400.
For every other shape this is not a narrowing
That was the open question in #4121 — whether an opaque array
whereis a supported input. Traced through every driver:wherethat is not an ASTdriver-sqlapplyFiltersrejects any element that is neitherand/ornor a condition array (#3948)driver-memorydriver-mongodb$${op}So rejecting at the protocol changes which error the caller sees, not whether there is one. The gain is that the message is in the request's own vocabulary —
unrecognised operator "not in",element 1 is number, plus the recognised operator list — instead of a driver's internal builder state, several layers from the query parameter that carried it.Scoped narrowly, because the regression to fear is rejecting something valid
whereobject is untouched:{status:'active'},{$and:[…]},{amount:{$gte:100}}all pass through exactly as before.[]is left alone. It means "no filter", and every path already treats it that way.isFilterASTaccepts nested arrays (filter.zod.ts— "Legacy flat array:[[cond],[cond]]"), so[[a,'=',1],[b,'=',2]]and['and', […], ['or', …]]keep converting. A naive "arrays are suspect" rule would have broken exactly those — which is why the accepted shapes are pinned by as many tests as the rejected ones.before/after, which A filter with an operator outside VALID_AST_OPERATORS is silently dropped, not rejected — single-condition views return unfiltered results #3948 added toAST_OPERATOR_MAP, convert normally — verified, not assumed.Errors carry
status: 400andcode: 'INVALID_FILTER', matching theUNSUPPORTED_QUERY_PARAMconvention immediately alongside.Verification
findDatanormalisation — not a re-implementation of its rule. My first draft extracted the predicate into the test, which would have verified the rule while proving nothing about the wiring or the message; this drivesObjectStackProtocolImplementation.findDatawith a stub engine and asserts on the options handed toengine.find.status/code.@objectstack/metadata-protocolsuite: 122 tests across 19 files, green.tsc --noEmit: 0 errors in the touched files.eslint --no-inline-config: clean.Refs #3948, objectstack-ai/objectui#2945
🤖 Generated with Claude Code