Skip to content

fix: honor $parameters in rel inline filters (#96), RETURN created rel vars (#95), caller-assigned edge ids for upsert_edge (#97) - #98

Merged
dylanbstorey merged 5 commits into
mainfrom
claude/verify-open-issues-eeuhv3
Aug 25, 2026
Merged

fix: honor $parameters in rel inline filters (#96), RETURN created rel vars (#95), caller-assigned edge ids for upsert_edge (#97)#98
dylanbstorey merged 5 commits into
mainfrom
claude/verify-open-issues-eeuhv3

Conversation

@dylanbstorey

Copy link
Copy Markdown
Contributor

Summary

Test plan

  • make test-unit — 947/947 pass (3 new CUnit regression tests: rel $param filter, MATCH+CREATE+RETURN created var, MERGE $param properties)
  • make test-functional — clean, including new tests/functional/39_issue_regression_tests.sql (17 hard assertions; CHECK-constrained temp table aborts under sqlite3 -bail on any mismatch)
  • python -m tests.tck --backend extension — 3778 pass; per-scenario diff against a pre-change run of the same tree: zero regressions
  • make test-python — 357 pass (3 new edge_id tests)
  • make test-rust — 244 integration tests pass (1 new upsert_edge_with_id test)
  • Reproduced each issue's exact repro script before the fix and re-ran it after

Semantic coverage matrix

  • Cells added/modified in docs/testing/semantic-coverage-matrix.md:
    • Section 1: MATCH (a) CREATE (a)-[:R]->(b) literal cell now covers RETURN r/r.k read-back on the created rel var (39:GH-95)
    • Section 3 (param vs literal symmetry): new rows for MATCH rel inline prop filter (read) (39:GH-96), MERGE node inline prop match phase (39:GH-97 3.1), MERGE rel inline prop match phase (39:GH-97 3.2)
    • Dated coverage-update section describing all three fixes
  • Regression tests added/updated in tests/functional/:
    • tests/functional/39_issue_regression_tests.sql (new — the file the matrix process references)
  • If neither: reviewer may apply skip-coverage-matrix label (pure refactors only).

Checklist

  • angreal test functional green locally (run via make test-functional equivalent — sqlite3 -bail over tests/functional/*.sql)
  • angreal test unit green locally (run via make test-unit)
  • PR title follows conventional-commit style (fix:, feat:, chore: …)

Fixes #95, fixes #96, closes #97.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QuzbsuTddFm245sZ9egekS


Generated by Claude Code

claude added 5 commits August 25, 2026 02:59
…lters (#96)

MATCH ()-[r:TYPE {prop: $param}]->() silently skipped the parameter and
matched every edge of the type — dangerous for SET/DELETE scoped by such
a filter. Mirror the node-pattern parameter handling: OR of EXISTS
subqueries across the four edge property type tables bound to the named
parameter. Literal filters and WHERE-clause parameters were already
correct.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QuzbsuTddFm245sZ9egekS
MATCH (x),(y) CREATE (x)-[r:T]->(y) RETURN r raised 'Unknown variable: r'
after the CREATE had already committed: the handler re-executed
MATCH+RETURN, which has no binding for variables introduced by CREATE.

execute_multi_match_create_query can now hand back one variable_map per
processed MATCH row (matched + CREATE-introduced bindings). The
MATCH+CREATE+RETURN handler detects RETURN items referencing CREATE-only
variables and projects them from those row maps (bare var, var.prop, and
aggregates, with SKIP/LIMIT), one result row per MATCH row. Queries whose
RETURN only references MATCH-bound variables keep the legacy path
unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QuzbsuTddFm245sZ9egekS
MERGE previously ignored parameter-valued inline properties: the match
phase skipped them (matching any node of the label / any edge on the
triple) and node creation dropped them. Fix find_node_by_pattern,
find_edge_by_pattern, and the node-create property phase to resolve
$parameters, so MERGE (a)-[r:T {id: $eid}]->(b) matches/creates by that
property like a literal would.

On top of that, expose caller-assigned edge identities in the bindings:

- Python: upsert_edge(..., edge_id=None). With edge_id, the edge is
  merged on that id (stored as an 'id' relationship property) instead of
  the (source, target, rel_type) triple, so parallel edges on the same
  triple are individually addressable and upsertable in place. Default
  behavior is unchanged.
- Rust: new upsert_edge_with_id(source, target, props, rel_type, edge_id)
  with the same semantics; upsert_edge is untouched.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QuzbsuTddFm245sZ9egekS
Requested in #95: neither the README nor the docs mentioned concurrent
writers, multi-process access, or WAL mode, leaving it an open question
for anyone evaluating embedded concurrent-write use.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QuzbsuTddFm245sZ9egekS
Adds tests/functional/39_issue_regression_tests.sql (the file the
semantic-coverage-matrix process points at) with hard assertions — a
CHECK-constrained temp table aborts the run under sqlite3 -bail on any
mismatch — covering all three fixes, and links the cells from
docs/testing/semantic-coverage-matrix.md.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QuzbsuTddFm245sZ9egekS
@dylanbstorey
dylanbstorey merged commit 1cc7fe1 into main Aug 25, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment