fix(cypher): conservative nullable default for complex expressions #6
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Fix: Conservative nullability for Cypher expressions
Follow-up to PR #2 (Nullable return types). That PR added
Requiredmetadata from schema to codegen, allowing nullable fields to generate pointer types. However, it missed cases where nullability comes from query structure, not schema.Problem
Two issues with the original approach:
Both generated non-pointer types, causing compile errors when mocks returned nil.
Solution
Conservative default: only trust schema
Requiredfor simplevar.propon non-optional bindings. Everything else bails to nullable.Result
u.nameon MATCHu.nameon OPTIONAL MATCH*stringtoUpper(u.name)*stringcount(u),avg(u.age)*int,*float64dialects/cypher/analyzer.go: track optional bindings, flip defaultDesign Decision
Chose conservative default over full null propagation tracking. Modeling Cypher's null semantics through arbitrary expressions (functions, operators, CASE) would require version-specific rules for dozens of constructs with limited benefit.
Being "over-nullable" (extra pointers) is safer than "under-nullable" (compile errors) for test scaffolding.
Future Work
Gradual whitelist for known non-null constructs:
count(*)→ always returns int, never null1,"foo",true) → non-null by definitionIS NULL/IS NOT NULL→ always returns boolcoalesce(expr, <literal>)→ non-null if fallback is non-null