Replace query internals with canonical backend-agnostic IR AST#9
Merged
Conversation
Refactored intermediate representation Enhance Jest configuration and documentation for Intermediate Representation - Added new test patterns for Intermediate Representation related tests in jest.config.js. - Updated README to include a section on Intermediate Representation with a link to the documentation.
Refactored intermediate representation Enhance Jest configuration and documentation for Intermediate Representation - Added new test patterns for Intermediate Representation related tests in jest.config.js. - Updated README to include a section on Intermediate Representation with a link to the documentation.
Phase 0: plan document covering 8 phases to complete the IR refactor — expand desugar, lift to full AST, test parity, production wiring, cleanup, and documentation sync. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Added 6 new desugared types (DesugaredCountStep, DesugaredTypeCastStep, DesugaredSubSelect, DesugaredCustomObjectSelect, DesugaredEvaluationSelect, DesugaredMultiSelection) to handle sub-selects, custom result objects, type casting, preload, and count/aggregation patterns. Expanded desugar tests from 3 to 35 covering all query patterns in query.test.ts. Updated downstream consumers (IRPipeline, IRProjection) for new union types. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract shared QueryCaptureStore to src/test-helpers/query-capture-store.ts, merge ir-pipeline-parity tests into ir-select-golden, document pipeline architecture in documentation/intermediate-representation.md. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rewrite IR docs with comprehensive examples for all variant types, add migration section to README, mark docs 002/003 as superseded. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…/DeleteQuery are now IR types Old interfaces renamed to LegacySelectQuery/LegacyCreateQuery/LegacyUpdateQuery/LegacyDeleteQuery. IQuadStore and LinkedStorage now import canonical query types from their query files. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…Object/getIR All four query factories now expose build() as the primary method. getQueryObject() and getIR() are deprecated aliases. QueryParser and internal callers (getPropertyPath, isValidResult) updated. getLegacyQueryObject() remains internally for pipeline input (Phase 11) and test helpers (Phase 12). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…peline Define RawSelectInput as the internal pipeline input type capturing exactly what the desugar pass needs. SelectQueryFactory.build() now constructs RawSelectInput directly from factory state, bypassing getLegacyQueryObject(). IRDesugar.ts and IRPipeline.ts no longer import LegacySelectQuery. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ery.test.ts - Delete getLegacyQueryObject() from all four factories - Add toRawInput() on SelectQueryFactory for pipeline/test access - Delete LegacySelectQuery, LegacyCreateQuery, LegacyUpdateQuery, LegacyDeleteQuery - Define mutation input types locally in IRMutation.ts - Update query-capture-store to use toRawInput() for select, build() for mutations - Simplify ir-mutation-parity.test.ts (capture store now returns IR directly) - Update core-utils.test.ts to use toRawInput() - Delete query.test.ts (superseded by ir-select-golden.test.ts) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…SelectQuery, update docs - Delete SelectQueryIR type alias from IRPipeline.ts - Rename buildSelectQueryIR to buildSelectQuery - Update ir-select-golden.test.ts to use SelectQuery type and build() - Update documentation/intermediate-representation.md for current pipeline - Update README.md migration section for build() API Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ion type discriminators - Delete getQueryObject() from all 4 factories and QueryFactory base class - Delete getIR() from SelectQueryFactory - Delete LinkedQuery interface (no longer needed) - Remove dead buildCanonicalMutationIR dispatcher and CanonicalMutationIR type - Remove type:'create'|'update'|'delete' discriminators from mutation input types - Fix as any in BoundComponent.getPropertyPath() with proper Array.isArray narrowing Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…p redundant structure
- Top-level kinds: select_query→select, create_mutation→create, update_mutation→update, delete_mutation→delete
- Graph pattern: exists_pattern→exists
- Flatten IRShapeRef {shapeId: string} and IRPropertyRef {propertyShapeId: string} to plain strings
- Rename description→data and updates→data on mutations
- Rename IRNodeDescription→IRNodeData, IRNodeFieldUpdate→IRFieldUpdate
- Drop kind from projection items, order by items (unambiguous from context)
- Flatten resultMap from {kind: 'result_map', entries: [...]} to just [...]
- Remove IRResultMap wrapper type
- Update all pipeline stages, tests, documentation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…arser This commit completes the IR refactoring branch with final improvements for downstream implementers: ### Dead code removal - QueryFactory.ts: removed ~50 lines of commented-out type variants - SelectQuery.ts: removed commented-out QueryBoolean stub ### Documentation improvements - Added JSDoc comments to all 13 exported IR pipeline functions - Functions documented: buildSelectQuery, desugarSelectQuery, canonicalizeWhere, canonicalizeDesugaredSelectQuery, lowerSelectQuery, projectionKeyFromPath, lowerSelectionPathExpression, buildCanonicalProjection, and mutation IR builders - Added JSDoc for IRAliasBinding type and validateAliasReference function ### QueryParser simplification - Deleted IQueryParser interface (existed only for swappability with one impl) - Shape now calls QueryParser.selectQuery/updateQuery/createQuery/deleteQuery directly - Removed Shape.queryParser static property and queryParser from method this constraints - Updated QueryCaptureStore to use jest.spyOn instead of implementing IQueryParser - Tests updated to use new captureQuery API (6 test files updated) - Result: cleaner module boundaries, one less abstraction, no runtime circular dependency ### Consolidation - Merged docs 002, 003, 004 into single docs/003-ir-refactoring.md - All 26 implementation phases summarized with key decisions and final state All 147 tests pass. TypeScript clean. Ready for production. Co-Authored-By: Claude Haiku 4.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.
Summary
Replaces the internal query representation with a canonical backend-agnostic IR AST. The public Shape DSL (
Shape.select(),.create(),.update(),.delete()) is unchanged — what changed is whatIQuadStoreimplementations receive.Why
Stores previously received ad-hoc nested arrays and objects (
query.select[0][0].property.label). This made downstream store implementations brittle, hard to reason about, and tightly coupled to internal DSL structure. A normalized IR with typed discriminated unions gives store implementers a stable, well-documented contract to build against.What
SelectQuery,CreateQuery,UpdateQuery,DeleteQueryARE the IR types. No separate "IR" vs "query" type hierarchy — factories emit IR directly viabuild().root(shape scan pattern),projection(expression-based),where(expression tree),orderBy,limit,subjectId,singleResult,resultMap.kinddiscriminators (create,update,delete) withIRFieldUpdate[],IRNodeDescription, and set modification support (add/remove).shapeIdandpropertyShapeIdstrings only — no embedded shape/property objects.some()→exists(),every()→not exists(not ...)during canonicalization. Boolean trees flattened.a0,a1, ...) with lexical scope validation.How
A multi-stage pipeline converts DSL traces to IR:
Mutations convert directly via
buildCanonical*MutationIR()inIRMutation.ts.New modules:
IRDesugar.ts,IRCanonicalize.ts,IRLower.ts,IRPipeline.ts,IRProjection.ts,IRAliasScope.ts,IRMutation.ts. All exported functions have JSDoc documentation.Breaking changes for downstream stores
IQuadStoremethod signatures are unchanged, but the objects they receive are structurally different. Select queries are completely new (query.root,query.projection,query.where). Mutation queries are structurally similar but properly typed. Store result types are now exported:ResultRow,SelectResult,CreateResult,UpdateResult,SetOverwriteResult,SetModificationResult.Full IR reference:
documentation/intermediate-representation.md.Other improvements
IQueryParserinterface. Shape calls QueryParser directly — no swappable indirection.query.test.tshas IR assertions. Old legacy test file deleted.docs/003-ir-refactoring.md.Test plan
npx jest --config jest.config.js)npx tsc --noEmit)IQueryParser,getLegacyQueryObject,getCanonicalIR, etc.)query.types.test.ts)🤖 Generated with Claude Code