Skip to content

Fix query-engine bugs: :in predicate bindings, intra-tx lookup refs, EDN symbol chars - #15

Merged
tiensonqin merged 1 commit into
mainfrom
devin/query-engine-fixes
Sep 22, 2026
Merged

tiensonqin merged 1 commit into
mainfrom
devin/query-engine-fixes

Conversation

@tiensonqin

Copy link
Copy Markdown
Contributor

Summary

Fixes several engine bugs hit by the Logseq db-worker port, root-caused in the engine and verified against upstream juxt/datascript semantics. New test suite test_query_engine_fixes covers each fix (upstream tests ported where they exist; aliases added to upstream_test_aliases.tsv).

Bug: [(= ...)]/[(not= ...)] predicates over :in-bound vars drop all rows — CONFIRMED + FIXED.
bound_relation_clause in impl/query_where.ml only substituted bindings into patterns and 2-arg ComparisonPredicate, leaving EqualityPredicate/ComparisonPredicateN untouched. A :in-bound var stayed a QVar, so filter_relation_equality couldn't resolve it and every row was dropped. Now all relation-evaluable clause kinds get bound: equality predicates, N-arg comparison predicates, arithmetic/name/namespace/keyword value clauses, SourceClause, and Not/SourceNot/NotJoin/SourceNotJoin (the function is now rec). [(= ?v ?target)] and [(not= ?d ?x)] over :in scalars now return the right rows.

Bug: intra-transaction lookup refs in entity maps fail — CONFIRMED + FIXED.
apply_entity_map called resolve_entity_attrs which strictly resolved all attr values against the datoms accumulated before the entity map ran. An attr value like [:block/uuid #uuid "..."] referencing an entity created by an earlier attr of the same map (or an earlier tx op) raised "Nothing found for entity id". Upstream transact resolves each [:db/add] op sequentially against the accumulating db-after. Now the entity-map fold resolves each tx_value strictly inside apply_attr at its add step, so earlier attrs of the same map are visible; the upsert probe (entity_unique_identity, validate_explicit_upsert_target, tuple_identity_lookup_writes) uses a non-strict resolution matching upstream resolve-upserts (unresolvable refs keep raw form and never match). Verified: earlier-op refs, same-entity self-refs, Add-op refs to earlier-tx entities, tempid/uuid upsert merging all work; forward refs and unresolvable refs still correctly raise.

Bug: EDN reader can't tokenize ' inside symbols/keywords — CONFIRMED + FIXED.
' was in read_edn's is_delimiter set, splitting foo' into foo + quote. Upstream EDN treats ' as a non-terminating macro char: special only at token start, legal mid-symbol. Removed from the delimiter set; leading-' quoting still works via parse_form. {:user.property/foo*+!_'?<>=- nil} and [sym' foo*+!_'?<>=- 'quoted ?var] now parse like cljs edn/read-string.

Bug 1 (recursive rules wrong direction): not reproducible — ported upstream test-rules cases (recursive walk, "Rule with branches" positional binding with renamed head vars, swapped-arg symmetric closure) all pass on main. Kept as regression tests.

Bug 3 ([?x ...] collection :in ignored): not reproducible — collection inputs iterate correctly via the sequential clause path; ported upstream test-bindings collection case kept as regression test.

Bug 4 (avet not backfilled on kvs sqlite restore): not reproducible — restore paths rebuild avet (existing sqlite test asserts datoms restored Avet; memory/file storage verified empirically: attr+value lookups, lookup-ref resolution, and avet queries all work post-restore).

Full dune runtest is green with upstream parity checks enabled.

Link to Devin session: https://app.devin.ai/sessions/c82925b6976a4a6da2688c410e65011a
Open in Devin Desktop: https://app.devin.ai/desktop/session/c82925b6976a4a6da2688c410e65011a?variant=devin
Requested by: @tiensonqin

… symbol chars

- query_where: substitute :in bindings into equality/comparison-N
  predicates, arithmetic/value clauses, source clauses, and not/not-join
  clauses in bound_relation_clause so the relation fast path no longer
  drops rows for [(= ?v ?target)] / [(not= ...)] over :in-bound vars
- transact: resolve entity-map attr values per attr at add time against
  the accumulating tx datoms (upstream sequential [:db/add] order) so
  lookup refs see datoms added by earlier attrs of the same entity map;
  upsert probes resolve non-strictly like upstream resolve-upserts
- parser: ' is a non-terminating macro char in EDN, so it is legal
  mid-symbol; remove it from the delimiter set so symbols/keywords like
  foo*+!_'?<>=- tokenize like upstream cljs reader
- tests: new test_query_engine_fixes suite covering recursive-rule
  direction, predicates over :in scalars and collections, intra-tx
  lookup refs, and EDN symbol special chars; upstream alias entries
  added for ported tests
Copilot AI lite review requested due to automatic review settings September 22, 2026 05:44
@devin-ai-integration

Copy link
Copy Markdown

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@tiensonqin
tiensonqin merged commit 11a9f4b into main Sep 22, 2026
1 of 2 checks passed
@tiensonqin
tiensonqin deleted the devin/query-engine-fixes branch September 22, 2026 05:46
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