gregfelice opened a new pull request, #2359:
URL: https://github.com/apache/age/pull/2359
## Summary
Implements the four openCypher predicate functions (issues #552, #553, #555,
#556):
- `all(x IN list WHERE predicate)` — true if all elements match
- `any(x IN list WHERE predicate)` — true if at least one matches
- `none(x IN list WHERE predicate)` — true if no elements match
- `single(x IN list WHERE predicate)` — true if exactly one matches
These are among the most requested Cypher features for AGE and are critical
for users migrating from Neo4j and Kuzu (recently archived).
## Implementation
**Approach:** Builds on the existing list comprehension infrastructure
(`unnest`-based subqueries with child parsestates for variable scoping).
**SQL transformation strategy:**
- `all()` → `NOT EXISTS (SELECT 1 FROM unnest(list) AS x WHERE NOT
predicate)`
- `any()` → `EXISTS (SELECT 1 FROM unnest(list) AS x WHERE predicate)`
- `none()` → `NOT EXISTS (SELECT 1 FROM unnest(list) AS x WHERE predicate)`
- `single()` → `(SELECT count(*) FROM unnest(list) AS x WHERE predicate) = 1`
EXISTS/NOT EXISTS short-circuits on first match for optimal performance.
**Files changed (12):**
| File | Change |
|------|--------|
| `cypher_nodes.h` | New `cypher_predicate_function` node type with
`CPFK_ALL/ANY/NONE/SINGLE` enum |
| `ag_nodes.h` / `ag_nodes.c` | Node registration |
| `cypher_outfuncs.h` / `cypher_outfuncs.c` | Serialization |
| `cypher_kwlist.h` | Three new keywords: `ANY_P`, `NONE`, `SINGLE` |
| `cypher_gram.y` | Grammar rules in `expr_func_subexpr`,
`build_predicate_function_node()` helper, `extract_iter_variable_name()` shared
helper, keywords added to `safe_keywords` |
| `cypher_clause.c` | `transform_cypher_predicate_function()` — builds query
tree from predicate node |
| `cypher_analyze.c` | Expression walker for new node type |
| `Makefile` | Register new regression test |
| `regress/sql/predicate_functions.sql` | New test file |
| `regress/expected/predicate_functions.out` | Expected output |
**Backward compatibility:**
- `ANY_P`, `NONE`, `SINGLE` added to `safe_keywords` so they work as
property keys and label names (e.g., `{any: 1, none: 2, single: 3}`)
- `ALL` was already a reserved keyword with `safe_keywords` entry
- No grammar conflicts (verified: zero new shift/reduce or reduce/reduce
warnings)
## Regression Tests
28 test queries covering:
- Basic true/false for each function
- Empty list edge cases (vacuous truth for `all()`/`none()`, false for
`any()`/`single()`)
- Graph data integration (`MATCH (u) WHERE all(x IN u.vals WHERE ...)`)
- Boolean combinations (`any(...) AND all(...)`)
- Nested predicates (`any(x IN ... WHERE all(y IN ... WHERE ...))`)
- Keyword backward compatibility (`{any: 1, none: 2, single: 3}`)
- Deterministic ordering (all graph queries use `ORDER BY`)
All 32 regression tests pass (31 existing + 1 new).
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]