fix(spec,data): the five RPC query aliases resolve by one fold — spec table, not per-reader prose (#3795) - #4323
Merged
Conversation
… table, not per-reader prose (#3795) RpcQueryOptionsSchema documented its alias precedence in prose only, so both normalizers re-implemented it: protocol.ts had four of five pairs BACKWARDS (canonical consulted last) and disagreed with the runtime dispatcher's copy on three, so ?select=a&fields=b answered [a] or [b] depending on the path. The mapping now lives once in the spec (RPC_QUERY_ALIAS_SLOTS + foldQueryAliasSlots), applied as a parse transform on the RPC schemas and as the wire fold in findData, under #4181's rule generalized to all five slots: alias alone folds and is dropped from parsed output, identical duplicates collapse, different values are refused, an explicit null spelling is a withdrawal. The dispatcher's second copy of the fold is deleted. Also lowers a direct expand:[names] array to the expand record instead of reading its indices as relation names. Co-Authored-By: Claude Fable 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 3 package(s): 114 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
…lias-precedence-1fc2cd
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 #3795. The sweep's live-and-inverted cluster:
RpcQueryOptionsSchemastated its five alias precedences in prose only, so both readers re-implemented them —protocol.tshad four of five backwards (canonical consulted last), and disagreed with the runtime dispatcher's copy on three, so the same request resolved differently per path (?select=a&fields=b→[a]or[b]depending on which route served it).What changed
The mapping lives once, in the spec.
packages/spec/src/data/data-engine.zod.tsnow exportsRPC_QUERY_ALIAS_SLOTS(the five pairs) andfoldQueryAliasSlots(the fold), and both consumers run the same table:RpcQueryOptionsSchema(find/findOne) and the fourRpcLegacyFilterMixinoptions (update/delete/count/aggregate requests) fold at parse. Parsed output speaks canonical QueryAST keys only; the alias keys are dropped from the output type, so a TS consumer readingparsed.query.populatefails to compile instead of silently readingundefined— the fix(action): one precedence fortargetvs deprecatedexecute— lower the alias, then drop it (#3713) #3742/fix(field): fold deprecatedconditionalRequiredintorequiredWhenand drop the alias (#3754) #3764 shape one layer down, hence the minor for@objectstack/spec.protocol.ts findData— the four inverted open-coded folds are gone; the wire fold runs the spec table extended with the wire-only spellings (filters,$filter,$expand— the last settling the$expand ?? expandinversion the issue flagged "worth settling in the same pass").runtime/domains/data.ts— the dispatcher's second copy of the fold (opposite precedence on three pairs) is deleted, not fixed in place. GET-list wire params ride tofindDataverbatim; one fold, one answer.The rule (per slot)
#4181 had already replaced "pick a winner" with "refuse ambiguity" for the filter pair, with rationale that applies verbatim to the other four ("picking one is the silent drop itself"). This PR generalizes that rule rather than implementing the doc block's silent canonical-wins, and rewrites the doc block to match:
400 INVALID_REQUEST(wire) / parse failure (schema), naming the spellings the caller actually wrote ($expand, notexpand— the REST 列表:sort/select/expand指向不存在的字段时被静默丢弃(filter 轴已收口,这三条轴还没有) #4226 discipline) and the canonical key;nullspelling → a withdrawal, never a conflict: a null alias is dropped silently, a null canonical keeps its slot-specific answer (preserves REST 列表:sort/select/expand指向不存在的字段时被静默丢弃(filter 轴已收口,这三条轴还没有) #4226's pinned{orderBy: null, sort}behavior and REST 列表:无法解析的filterJSON 被静默忽略 —— 返回未过滤整页(#4134/#4164 家族第三员) #4181's{where: null}rejection).Behavior changes (deliberate, all toward one answer)
?filter=X&where=Y(GET list)Ysilently (dispatcher)400— matches whatPOST /queryalready did (#4181){select: a, fields: b}[a]— alias clobbered canonical400{skip: 10, offset: 0}10— alias clobbered canonical400{populate: [a], expand: b}populatewon, canonical only as fallback400{sort: a, orderBy: b}bsilently400(consistency — one rule for all five slots){expand: ['a','b']}onPOST /query400 Unknown field '0'(or raw array reached the driver registry-less){a: {…}, b: {…}}likepopulatealways didCallers mixing vocabularies with different values were already getting a wrong/ambiguous answer on at least one path — nothing that worked consistently before stops working.
Pins
data-engine.test.ts).it.eachover all five slots × {fold, conflict, redundant-identical}; rejection message quotes wire spellings incl. OData; canonical-only untouched; null-withdrawal; expand-array lowering (protocol-data.test.ts). The REST 列表:无法解析的filterJSON 被静默忽略 —— 返回未过滤整页(#4134/#4164 家族第三员) #4181 suite passes unchanged — the shared fold preserves its semantics exactly.http-dispatcher.test.ts).Verification
spec7132 /objectql1365 /runtime954 /metadata-protocol122 tests green.pnpm test: 131/132 tasks green; the one failure wasdogfood/two-factor-lockouttiming out at 5s under parallel load — passes standalone, untouched by this PR.check:generatedall 8 gates green;api-surface.json(+4 exports) andcontent/docs/referencesregenerated via--fix.@objectstack/spec, patch@objectstack/metadata-protocol+@objectstack/runtime.Scope notes
Per the issue:
$top/$select/$orderby/$skip(the OData rewrite loop) and the engine-leveltop→limitalias are left as-is;visibleWhenfamily already correct; the remaining@deprecatedspec markers are renamed exports with no key-precedence risk.🤖 Generated with Claude Code