fix: fix MERGE NULL property matching bug#166
Conversation
#146) - Skip NULL properties in CREATE per openCypher spec (NULL = "no value") - Add pattern variable validation with correct semantics: * Allow node variables to repeat (self-loops: CREATE (a)-[:R]->(a)) * Reject duplicate relationship variables * Reject using same variable for both node and relationship - Add 13 new tests for NULL properties, variable validation, and expressions - Update existing test to reflect correct NULL semantics - All 971 integration tests passing, 92.27% coverage Fixes edge cases identified in openCypher TCK compliance testing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit fixes 8 failing SNAP dataset loading tests by addressing test isolation issues caused by shared global registry state. Changes: 1. Update all HTTP test URLs to HTTPS in unit tests (test_registry.py) - Prevents HTTP URLs from polluting integration tests - Aligns test data with production SNAP dataset URLs 2. Add registry setup fixture for integration tests - Ensures SNAP datasets are registered before tests run - Makes tests order-independent (works after unit tests clear registry) - Module-scoped autouse fixture prevents registry pollution 3. Update test_url_format_consistency to filter test datasets - Filters out example.com test URLs from validation - Improves error messages with dataset names - Defensive check ensures real datasets are present 4. Document registry state contract in module docstring - Clarifies test isolation expectations - Explains fixture behavior for future maintainers Root Cause: Global singleton registry shared across test modules combined with inconsistent test setup (unit tests clear, integration tests assume populated) caused non-deterministic failures depending on test execution order. All tests now pass regardless of execution order. Coverage maintained at 92.27%. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace string startswith() check with proper URL parsing using urlparse to check hostname. This satisfies CodeQL's security requirements while maintaining the same functionality. The previous string-based check was flagged by CodeQL as "incomplete URL substring sanitization" (CWE-20), even though this is test filtering code not security-critical. Using urlparse is the correct approach regardless. Fixes security code scanning alert #13. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix NULL property handling in MERGE pattern matching - NULL in pattern now never matches (per openCypher spec) - NULL in node property now never matches non-NULL pattern - Add explicit NULL checks before comparison to prevent ternary logic issues Root cause: CypherNull.equals() returns CypherNull (not CypherBool), causing comparison check to fail and incorrectly match nodes with NULL properties. Solution: Add explicit isinstance(CypherNull) checks before comparison to ensure NULL never matches NULL (per openCypher ternary logic semantics). Changes: - src/graphforge/executor/executor.py: Add NULL checks in _execute_merge() - tests/integration/test_complex_merge_patterns.py: Fix incorrect test expectations - tests/integration/test_merge_edge_cases.py: Add 15 comprehensive edge case tests Test coverage: - 15 new tests for NULL handling and multi-property matching - All 71 integration MERGE tests pass - Coverage: 90.08% for executor.py (up from 84.16%) - Total coverage: 92.21% (exceeds 85% threshold) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
WalkthroughIntroduces pattern variable validation in the executor to enforce openCypher CREATE rules, enhances NULL property handling to skip CypherNull values during node/relationship creation, and strengthens MERGE matching validation to treat CypherNull as non-matching. Expands integration test coverage for CREATE/MERGE edge cases including NULL semantics, multi-property matching, and pattern validation. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant QueryExecutor
participant PatternValidator
participant PropertyEvaluator
participant NodeCreator
participant RelationshipCreator
Client->>QueryExecutor: CREATE pattern
activate QueryExecutor
QueryExecutor->>PatternValidator: _validate_pattern_variables(pattern_parts)
activate PatternValidator
PatternValidator->>PatternValidator: Check node vars can repeat
PatternValidator->>PatternValidator: Check relationship vars unique
PatternValidator->>PatternValidator: Check no var reuse (node vs rel)
PatternValidator-->>QueryExecutor: Validation pass/fail
deactivate PatternValidator
alt Validation Success
QueryExecutor->>PropertyEvaluator: Evaluate properties
activate PropertyEvaluator
PropertyEvaluator->>PropertyEvaluator: Skip CypherNull properties
PropertyEvaluator-->>QueryExecutor: Filtered properties
deactivate PropertyEvaluator
QueryExecutor->>NodeCreator: Create nodes with non-null properties
activate NodeCreator
NodeCreator-->>QueryExecutor: Nodes created
deactivate NodeCreator
QueryExecutor->>RelationshipCreator: Create relationships with non-null properties
activate RelationshipCreator
RelationshipCreator-->>QueryExecutor: Relationships created
deactivate RelationshipCreator
else Validation Failure
QueryExecutor-->>Client: ValueError
end
deactivate QueryExecutor
sequenceDiagram
participant Client
participant QueryExecutor
participant PatternMatcher
participant PropertyComparator
Client->>QueryExecutor: MERGE with pattern
activate QueryExecutor
QueryExecutor->>PatternMatcher: Find matching node
activate PatternMatcher
loop For each candidate node
PatternMatcher->>PropertyComparator: Compare properties
activate PropertyComparator
alt Property value is CypherNull
PropertyComparator-->>PatternMatcher: No match (CypherNull never matches)
else Property exists and matches
PropertyComparator->>PropertyComparator: Ensure comparison yields CypherBool
alt CypherBool is true
PropertyComparator-->>PatternMatcher: Match continues
else CypherBool is false
PropertyComparator-->>PatternMatcher: No match
end
else Property missing
PropertyComparator-->>PatternMatcher: No match
end
deactivate PropertyComparator
end
PatternMatcher-->>QueryExecutor: Match result
deactivate PatternMatcher
alt Match found
QueryExecutor->>QueryExecutor: Execute ON MATCH SET
else No match
QueryExecutor->>QueryExecutor: Create new node
end
deactivate QueryExecutor
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 4 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
⚔️ Resolve merge conflicts (beta)
No actionable comments were generated in the recent review. 🎉 🧹 Recent nitpick comments
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. Comment |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #166 +/- ##
==========================================
- Coverage 89.00% 88.96% -0.05%
==========================================
Files 32 32
Lines 5066 5100 +34
Branches 1326 1338 +12
==========================================
+ Hits 4509 4537 +28
- Misses 319 322 +3
- Partials 238 241 +3
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report in Codecov by Sentry.
|
Summary
Fixes #145 - Critical bug where MERGE incorrectly matches nodes with NULL properties, violating openCypher specification.
Problem
MERGE was incorrectly matching nodes when NULL properties were present in the pattern:
Root cause:
CypherNull.equals()returnsCypherNull(notCypherBool), causing theisinstance(comparison_result, CypherBool)check to fail and allowing NULL properties to match.Solution
Add explicit NULL checks before property comparison:
CypherBoolChanges
Modified Files
src/graphforge/executor/executor.py (lines 1954-1990)
isinstance(expected_value, CypherNull)checkisinstance(node_value, CypherNull)checktests/integration/test_complex_merge_patterns.py (line 210)
New Files
Test Results
✅ All 15 new tests pass
✅ All 71 integration MERGE tests pass
✅ No regressions in existing tests
✅ 2703 total tests pass
Coverage
openCypher Compliance
This fix implements correct NULL handling per openCypher specification:
Related Issues
Created follow-up issues for out-of-scope items:
Summary by CodeRabbit
Bug Fixes
Tests