Skip to content

Add MINUS patterns and bulk delete/update operations with .where() clauses#28

Merged
flyon merged 21 commits intomainfrom
dev
Mar 11, 2026
Merged

Add MINUS patterns and bulk delete/update operations with .where() clauses#28
flyon merged 21 commits intomainfrom
dev

Conversation

@flyon
Copy link
Member

@flyon flyon commented Mar 11, 2026

No description provided.

claude and others added 21 commits March 10, 2026 10:58
…ures

Rewrote the ideation doc to reflect the current 2.0 codebase state
(DeleteBuilder, UpdateBuilder, .for()/.forAll() patterns, existing NOT EXISTS
support). Restructured into 3 features with multiple implementation routes:
MINUS/NOT EXISTS, bulk delete, and conditional update.

https://claude.ai/code/session_01TGZykDVZBEimHNvwXiAq2D
- Implementation plan for SPARQL MINUS support on select queries
- Implementation plan for where-clause-based delete mutations

https://claude.ai/code/session_01TGZykDVZBEimHNvwXiAq2D
- Accepts ShapeConstructor or WhereClause<S> (same callback types as .select())
- Supports shape, single/multi property, boolean, and nested callbacks
- Reuses existing callback processing, new IRMinusPattern through pipeline
- Chainable: .minus(A).minus(B) produces separate MINUS blocks

https://claude.ai/code/session_01TGZykDVZBEimHNvwXiAq2D
…leanup

- .deleteAll() for bulk, .delete().where(cb) for conditional, .deleteWhere() as sugar
- Returns void, no safety gate needed
- Schema-aware blank node cleanup using explicit property paths from shape tree
- FILTER(isBlank()) for sh:BlankNodeOrIRI properties
- Recursive depth determined at codegen by walking shape tree

https://claude.ai/code/session_01TGZykDVZBEimHNvwXiAq2D
…lder

- Thin layer over existing DELETE/INSERT/WHERE SPARQL generation
- Swap hardcoded entity IRI for variable, add type triple + filter conditions
- Field-level scoping: only touches fields in update data
- .forAll() keeps OPTIONAL for old bindings; .where() drops it (filter implies existence)
- No .updateWhere() sugar — just .update().where()

https://claude.ai/code/session_01TGZykDVZBEimHNvwXiAq2D
…te, conditional update)

Covers all three features from ideation with inter-component contracts,
file change matrix, IR types, algebra conversion signatures, and pitfalls.

https://claude.ai/code/session_01TGZykDVZBEimHNvwXiAq2D
- IRMinusPattern added to IRGraphPattern union
- IRDeleteAllMutation, IRDeleteWhereMutation, IRUpdateWhereMutation types
- Canonical IR builder functions for new mutation types
- Widened DeleteQuery and UpdateQuery type unions
- SparqlStore dispatches by kind with stubs for new mutation types

https://claude.ai/code/session_01TGZykDVZBEimHNvwXiAq2D
- QueryBuilder.minus(ShapeConstructor | WhereClause) with immutable chaining
- IRMinusPattern threaded through desugar → canonicalize → lower pipeline
- selectToAlgebra wraps algebra in SparqlMinus nodes
- Supports shape exclusion, condition-based exclusion, and chained MINUS blocks
- 3 new golden tests: minusShape, minusCondition, minusChained

https://claude.ai/code/session_01TGZykDVZBEimHNvwXiAq2D
…deleteAll/deleteWhere

Phase 3 of advanced query patterns:
- DeleteBuilder rewritten with mode-based dispatch (ids/all/where)
- Shape.deleteAll() and Shape.deleteWhere() static convenience methods
- deleteAllToAlgebra() with schema-aware blank node cleanup via walkBlankNodeTree()
- deleteWhereToAlgebra() with WHERE filter condition support
- SparqlStore dispatch wired up for delete_all and delete_where
- Golden tests for both deleteAll and deleteWhere

https://claude.ai/code/session_01TGZykDVZBEimHNvwXiAq2D
…forAll()

Phase 4 of advanced query patterns:
- UpdateBuilder extended with .where(fn) and .forAll() fluent methods
- updateWhereToAlgebra() generates DELETE/INSERT/WHERE with variable subject
  (?a0) instead of hardcoded entity IRI, adds type triple and filter conditions
- SparqlStore dispatch wired up for update_where
- Golden tests for both updateForAll and updateWhere

https://claude.ai/code/session_01TGZykDVZBEimHNvwXiAq2D
Export toWhere from IRDesugar and add lowerWhereToIR to IRLower —
these changes support the WHERE processing in mutation builders.

https://claude.ai/code/session_01TGZykDVZBEimHNvwXiAq2D
…nce tests

- Extract processUpdateFields() and wrapOldValueOptionals() from
  updateToAlgebra, shared with updateWhereToAlgebra (eliminates duplication)
- deleteAll/deleteWhere/updateWhere now resolve to void (not placeholder objects)
  via typed R parameter on DeleteBuilder<S, R> and UpdateBuilder<S, U, R>
- Add builder equivalence tests: Person.deleteAll() === DeleteBuilder.from().all()
  and Person.deleteWhere(fn) === DeleteBuilder.from().where(fn)

https://claude.ai/code/session_01TGZykDVZBEimHNvwXiAq2D
Plan for .minus(p => [p.hobby, p.name]) — exclude entities where all
listed properties exist. Threads propertyPaths through the pipeline
without touching WhereClause or processWhereClause.

https://claude.ai/code/session_01TGZykDVZBEimHNvwXiAq2D
…erty

Update the Phase 6 plan to support .minus(p => [p.bestFriend.name]) with
nested path traversal, not just flat properties. Reuses existing
FieldSet.collectPropertySegments() and createProxiedPathBuilder() for
maximum code reuse.

https://claude.ai/code/session_01TGZykDVZBEimHNvwXiAq2D
Add .minus(p => [p.hobby, p.bestFriend.name]) syntax for property
existence exclusion in SPARQL MINUS blocks. Supports:
- Multi-property: .minus(p => [p.hobby, p.name])
- Nested paths: .minus(p => [p.bestFriend.name])
- Mixed: .minus(p => [p.hobby, p.bestFriend.name])
- Single property (no array): .minus(p => p.hobby)

Reuses existing FieldSet.collectPropertySegments() for path extraction
and createProxiedPathBuilder() for proxy creation. Threads
PropertyPathSegment[][] through IRDesugar → IRCanonicalize → IRLower,
where segments are converted to chained IRTraversePatterns.

4 new golden tests with exact SPARQL string matching.

https://claude.ai/code/session_01TGZykDVZBEimHNvwXiAq2D
…elete API

1. Deprecate sortBy() on QueryBuilder — use orderBy() instead. Updated
   all fixtures and tests to use orderBy.

2. Require data in Shape.update() — removed no-arg overload, data is
   now a required parameter. UpdateBuilder.set() jsdoc updated to
   "Replace the update data".

3. Simplify delete API — removed .for() from DeleteBuilder. ID-based
   deletes use DeleteBuilder.from(shape, ids). deleteAll() is strictly
   no-arg (null cannot trigger it). deleteWhere(fn) for conditional.

https://claude.ai/code/session_01TGZykDVZBEimHNvwXiAq2D
- Add MINUS examples (shape, property, multi-property, nested path, condition)
- Update sortBy → orderBy in examples
- Update delete section with deleteAll/deleteWhere
- Update update section with .where()/.forAll() and required data
- Update mutation builders to show DeleteBuilder.from(shape, id) instead of .for()
- Remove docs/ideas/007 and docs/plans/001 (work complete, report at docs/reports/009)

https://claude.ai/code/session_01TGZykDVZBEimHNvwXiAq2D
Add MINUS patterns and bulk delete/update operations with .where() clauses
@flyon flyon merged commit e32239f into main Mar 11, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants