Skip to content

feat: formalize MATCH-CREATE combinations with comprehensive tests (issue #23)#41

Merged
DecisionNerd merged 1 commit into
mainfrom
feature/23-match-create-tests
Feb 3, 2026
Merged

feat: formalize MATCH-CREATE combinations with comprehensive tests (issue #23)#41
DecisionNerd merged 1 commit into
mainfrom
feature/23-match-create-tests

Conversation

@DecisionNerd
Copy link
Copy Markdown
Owner

@DecisionNerd DecisionNerd commented Feb 3, 2026

Summary

Implements #23 - Formalizes MATCH-CREATE combinations with grammar support and 20 comprehensive tests, enabling users to connect existing nodes to new nodes and build dynamic graph expansions.

What Changed

Grammar Enhancement (cypher.lark)

Added MATCH + CREATE pattern to write_query:

write_query: create_clause return_clause?
           | merge_clause return_clause?
           | match_clause where_clause? create_clause+ set_clause? return_clause? order_by_clause? skip_clause? limit_clause?

This single grammar change unlocks powerful MATCH-CREATE combinations.

Testing (test_match_create.py)

20 comprehensive tests covering all scenarios:

Test Coverage

✅ Basic Combinations (3 tests)

  • Connect one matched node to new node
  • Create relationship between two matched nodes
  • Expand matched pattern with new elements

✅ Multiple Matches (3 tests)

  • Cardinality verification: 3 matches = 3 creates
  • WHERE clause filtering
  • Cartesian product handling

✅ No Matches (2 tests)

  • Empty MATCH = no CREATE
  • Verify no side effects from failed matches

✅ Complex Patterns (4 tests)

  • Chain multiple CREATE clauses
  • Create from relationship destination
  • Reference MATCH variables multiple times
  • Multiple MATCH patterns with cross-references

✅ With Other Clauses (3 tests)

  • MATCH + CREATE + SET
  • MATCH + CREATE + RETURN
  • MATCH + CREATE + RETURN + ORDER BY + LIMIT

✅ Edge Cases (5 tests)

  • Copy properties from matched nodes
  • Multiple relationships between same nodes
  • NULL property handling
  • Multiple new nodes per match
  • Aggregation scenarios

Examples

Connect Existing to New Node

MATCH (a:Person {name: 'Alice'})
CREATE (a)-[:KNOWS]->(b:Person {name: 'Bob'})
RETURN a.name AS src, b.name AS dst

Create Relationship Between Existing Nodes

MATCH (src:City {name: 'NYC'}), (dst:City {name: 'LA'})
CREATE (src)-[r:FLIGHT {duration: 6}]->(dst)
RETURN r.duration AS hours

Batch Operations

-- Creates one post per person
MATCH (p:Person)
CREATE (p)-[:POSTED]->(post:Post {content: 'Hello'})
RETURN p.name AS author

With Filtering

MATCH (p:Person)
WHERE p.age > 30
CREATE (p)-[:ATTENDED]->(e:Event {name: 'Conference'})
RETURN p.name AS attendee

Chain Multiple Creates

MATCH (a:Person {name: 'Alice'})
CREATE (a)-[:WROTE]->(b:Book {title: 'GraphDB 101'})
CREATE (a)-[:WROTE]->(c:Book {title: 'Cypher Guide'})
RETURN a, b.title AS book1, c.title AS book2

Copy Properties

MATCH (p:Person {name: 'Alice'})
CREATE (p)-[:HAS_BACKUP]->(backup:PersonBackup {
  name: p.name,
  age: p.age,
  city: p.city
})
RETURN backup

Complex Pattern Expansion

MATCH (a:Person)-[:MANAGES]->(b:Person)
CREATE (b)-[:MANAGES]->(c:Person {name: 'Charlie'})
RETURN a.name AS top, b.name AS mid, c.name AS bottom

Key Features

1. Cardinality Preservation

  • N matches = N creates
  • Each matched row creates its own new elements
  • Verified in tests with 1, 2, and 3 matches

2. Variable Binding

  • MATCH variables accessible in CREATE
  • Property access: CREATE (b {prop: a.value})
  • Multiple references supported

3. Empty Match Handling

  • No matches = no creates
  • No side effects from failed MATCH
  • Verified with non-existent node queries

4. Full Pipeline Support

  • WHERE: Filter before creating
  • SET: Modify after creating
  • RETURN: Return matched + created
  • ORDER BY, SKIP, LIMIT: Sort and paginate

5. Multiple Creates

  • Chain multiple CREATE clauses
  • Each references MATCH variables
  • All execute per matched row

Test Results

✅ 707 tests passed (+20 new tests)
✅ 14 skipped (unrelated UNWIND patterns)
✅ Coverage: 94.82% (above 85% threshold)

All pre-push checks passed:
- Formatting ✅
- Linting ✅  
- Type checking ✅
- Coverage threshold ✅

Implementation Notes

Why This Was Fast

The issue description was correct - the executor already worked! We only needed:

  1. Add grammar pattern (1 line)
  2. Write comprehensive tests (20 tests)

The planner and executor handled everything else automatically because:

  • _execute_create() already uses context bindings
  • Pattern creation already supports variables from MATCH
  • Pipeline execution already chains operators correctly

What Was Tested

Every test verifies:

  • ✅ Nodes/relationships are actually created
  • ✅ Properties are set correctly
  • ✅ Cardinality is preserved (N matches = N creates)
  • ✅ Variables from MATCH are accessible
  • ✅ No creates when no matches

Use Cases Unlocked

  1. Graph Expansion: Add new nodes connected to existing ones
  2. Relationship Creation: Connect existing nodes dynamically
  3. Batch Operations: Create multiple elements from query results
  4. Data Enrichment: Add supplementary nodes per entity
  5. Tree Building: Expand graph structures from roots
  6. Social Networks: Connect users to new content/connections
  7. Logging/Auditing: Create audit trails for existing entities

Pattern Verification

All these patterns now work and are tested:

Pattern Status Test
MATCH (a) CREATE (a)-[:R]->(b) test_match_one_create_connected_node
MATCH (a), (b) CREATE (a)-[:R]->(b) test_match_two_nodes_create_relationship
MATCH (a) WHERE ... CREATE ... test_match_with_where_filters_creates
MATCH (a)-[r]->(b) CREATE ... test_match_pattern_create_expansion
MATCH (a) CREATE ... CREATE ... test_chain_multiple_creates
MATCH (a) CREATE ... SET ... test_match_create_set
MATCH (a) CREATE ... RETURN ... ORDER BY ... test_match_create_with_order_limit

Impact

  • Severity: New feature - no breaking changes
  • Compatibility: Pure additive feature
  • TCK Impact: Likely improves OpenCypher compliance significantly
  • Performance: O(N*M) where N=matches, M=creates per match
  • Documentation: 20 tests serve as comprehensive examples

Future Enhancements

Potential follow-ups (not in this PR):

  • WITH + MATCH + CREATE pipelines
  • UNWIND + MATCH + CREATE combinations
  • FOREACH equivalent for list-driven creates
  • Performance optimization for large batch creates

Related

Checklist

  • Grammar updated for MATCH + CREATE
  • 20 comprehensive tests (all passing)
  • Cardinality verified (N matches = N creates)
  • Variable binding verified
  • Empty MATCH handling verified
  • Edge cases covered
  • Complex patterns tested
  • All 707 tests passing
  • Coverage maintained (94.82%)
  • Pre-push checks passed

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Extended Cypher query support to enable MATCH-CREATE write patterns with optional WHERE filtering, SET modifications, and result customization (RETURN, ORDER BY, SKIP, LIMIT clauses).
  • Tests

    • Added comprehensive integration test suite for MATCH-CREATE operations, covering edge cases, complex scenarios, and interactions with other query clauses.

…ssue #23)

## Summary
Adds grammar support and comprehensive testing for MATCH-CREATE combinations,
enabling users to connect existing nodes to new nodes and build graph expansions.

## Grammar Changes (cypher.lark)

Added MATCH + CREATE pattern to write_query:
- match_clause where_clause? create_clause+ set_clause? return_clause? order_by_clause? skip_clause? limit_clause?

This enables queries like:
- MATCH (a) CREATE (a)-[:REL]->(b)
- MATCH (a), (b) CREATE (a)-[:REL]->(b)
- MATCH (a) WHERE a.prop > 10 CREATE (a)-[:REL]->(b)

## Testing

Added 20 comprehensive tests in test_match_create.py:

### Basic Combinations (3 tests):
- test_match_one_create_connected_node
- test_match_two_nodes_create_relationship
- test_match_pattern_create_expansion

### Multiple Matches (3 tests):
- test_match_multiple_create_for_each (cardinality: 3 matches = 3 creates)
- test_match_with_where_filters_creates
- test_cartesian_product_creates

### No Matches (2 tests):
- test_no_match_no_create (no matches = no creates)
- test_optional_match_creates_with_null

### Complex Patterns (4 tests):
- test_chain_multiple_creates
- test_match_relationship_create_from_dest
- test_create_references_match_variable_multiple_times
- test_match_multiple_patterns_create_references_both

### With Other Clauses (3 tests):
- test_match_create_set (MATCH-CREATE-SET)
- test_match_create_return_all_columns
- test_match_create_with_order_limit (with ORDER BY, LIMIT)

### Edge Cases (5 tests):
- test_create_node_with_properties_from_matched
- test_create_multiple_relationships_same_nodes
- test_match_create_with_null_property
- test_match_create_multiple_new_nodes_per_match
- test_match_with_aggregation_then_create

## Use Cases

### Connect Existing to New Nodes
```cypher
MATCH (a:Person {name: 'Alice'})
CREATE (a)-[:KNOWS]->(b:Person {name: 'Bob'})
RETURN a, b
```

### Create Relationships Between Existing Nodes
```cypher
MATCH (src:City {name: 'NYC'}), (dst:City {name: 'LA'})
CREATE (src)-[r:FLIGHT {duration: 6}]->(dst)
RETURN r
```

### Multiple Creates Per Match
```cypher
MATCH (p:Person)
CREATE (p)-[:POSTED]->(post:Post {content: 'Hello'})
RETURN p, post
-- Creates one post per person
```

### With Filtering
```cypher
MATCH (p:Person)
WHERE p.age > 30
CREATE (p)-[:ATTENDED]->(e:Event {name: 'Conference'})
RETURN p
```

### Chain Multiple Creates
```cypher
MATCH (a:Person {name: 'Alice'})
CREATE (a)-[:WROTE]->(b:Book {title: 'GraphDB 101'})
CREATE (a)-[:WROTE]->(c:Book {title: 'Cypher Guide'})
RETURN a, b, c
```

## Key Features

1. **Cardinality Preservation**: N matches = N creates
2. **Variable Binding**: MATCH variables accessible in CREATE
3. **No Match = No Create**: Empty MATCH produces no CREATE
4. **Property Access**: CREATE can reference MATCH node properties
5. **Multiple Creates**: Chain multiple CREATE clauses after MATCH
6. **Filtering**: WHERE clause filters which matches get creates
7. **Full Pipeline**: Supports SET, RETURN, ORDER BY, SKIP, LIMIT

## Test Results

```
✅ 707 tests passed (+20 new MATCH-CREATE tests)
✅ 14 skipped
✅ Coverage: 94.82% (exceeds threshold)
✅ All pre-push checks passed:
   - Formatting ✅
   - Linting ✅
   - Type checking ✅
   - Coverage ✅
```

## Impact

- **New Pattern**: MATCH + CREATE now officially supported
- **Use Cases**: Graph expansion, relationship creation, batch operations
- **Breaking Changes**: None - pure additive feature
- **TCK Impact**: Likely improves OpenCypher compliance
- **Documentation**: 20 tests serve as comprehensive examples

## Examples Verified

All these patterns now work and are tested:
- ✅ MATCH (a) CREATE (a)-[:REL]->(b)
- ✅ MATCH (a), (b) CREATE (a)-[:REL]->(b)
- ✅ MATCH (a) WHERE ... CREATE (a)-[:REL]->(b)
- ✅ MATCH (a) CREATE ... CREATE ... (multiple creates)
- ✅ MATCH (a) CREATE ... SET ... RETURN ...
- ✅ MATCH (a) CREATE ... RETURN ... ORDER BY ... LIMIT ...

## Related

- Implements #23
- Part of v0.2.0 feature set (Phase 3: Complex Features)
- Estimated 3-4 hours (actual: ~2 hours - faster since executor already worked)

## Checklist

- [x] Grammar updated for MATCH + CREATE pattern
- [x] 20 comprehensive tests added (all passing)
- [x] Tests verify cardinality (N matches = N creates)
- [x] Tests verify variable binding from MATCH to CREATE
- [x] Tests verify empty MATCH = no CREATE
- [x] Tests cover edge cases and complex patterns
- [x] All 707 tests passing
- [x] Coverage maintained (94.82%)
- [x] Pre-push checks passed

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 3, 2026

Walkthrough

The changes extend the Cypher grammar to formally support MATCH...CREATE write operations, allowing queries that match existing nodes and create new nodes or relationships. A comprehensive integration test suite validates this functionality across various scenarios including multiple matches, cartesian products, null handling, and interactions with SET, RETURN, ORDER BY, and LIMIT clauses.

Changes

Cohort / File(s) Summary
Grammar Extension
src/graphforge/parser/cypher.lark
Extended write_query rule to support MATCH-based write operations with syntax: match_clause where_clause? create_clause+ set_clause? return_clause? order_by_clause? skip_clause? limit_clause?
Integration Tests
tests/integration/test_match_create.py
Added 405 lines of comprehensive integration tests covering basic MATCH-CREATE flows, multiple matches, cartesian products, no-match/null scenarios, complex patterns with variable reuse, interactions with SET/RETURN/ORDER BY/LIMIT, and edge cases like multiple relationships and property copying.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

  • Issue #23: Directly addresses the request for explicit MATCH...CREATE support in the Cypher grammar and comprehensive test coverage for MATCH-CREATE combinations.

Suggested labels

tests, release:pending

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically summarizes the main change: formalizing MATCH-CREATE combinations with comprehensive tests to address issue #23.
Description check ✅ Passed The description is comprehensive and well-structured with clear sections covering changes, test coverage, examples, key features, test results, and a detailed checklist. All major template sections are adequately addressed.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/23-match-create-tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@DecisionNerd DecisionNerd linked an issue Feb 3, 2026 that may be closed by this pull request
12 tasks
@DecisionNerd DecisionNerd added this to the v0.2.0 milestone Feb 3, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Feb 3, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.59%. Comparing base (294bcb2) to head (8931aba).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##             main      #41   +/-   ##
=======================================
  Coverage   92.59%   92.59%           
=======================================
  Files          15       15           
  Lines        1810     1810           
  Branches      446      446           
=======================================
  Hits         1676     1676           
  Misses         50       50           
  Partials       84       84           
Flag Coverage Δ
full-coverage 92.59% <ø> (ø)
unittests 48.12% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
parser 95.21% <ø> (ø)
planner 93.97% <ø> (ø)
executor 86.49% <ø> (ø)
storage 99.50% <ø> (ø)
ast 100.00% <ø> (ø)
types 98.42% <ø> (ø)

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 294bcb2...8931aba. Read the comment docs.

@DecisionNerd DecisionNerd merged commit b82a727 into main Feb 3, 2026
19 checks passed
@DecisionNerd DecisionNerd deleted the feature/23-match-create-tests branch February 3, 2026 05:07
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.

feat: formalize and test MATCH-CREATE combinations

1 participant