Repository navigation
Group an aggregating item over a property key by the property, and refuse a key of another shape there, as drivine4j does, at Cypher spec v0.14.0 - #315
Merged
Conversation
…fuse a key of another shape there, as drivine4j does, at Cypher spec v0.14.0 Ports drivine4j's #491 (merged as liberation-data/drivine4j#496), with the spec's liberation-data/drivine-cypher-spec#39. - _require_explicit_grouping reads a key inside an item that aggregates, beside its aggregates and in a body, only where it is a variable or a variable's property (_is_plain_key); in a pattern's parts only a variable. toUpper(p.name), x.a.b, x['a'] or x.a + 1 read there is refused (42I18). _named_in_bodies goes: _named_outside reads the whole item. - _aggregates_first takes an item that aggregates and reads a property key, and works it out over the keys' columns, so r.role + count(*) beside r.role groups per role. A list comprehension's WHERE reads the key by its name; its projection, a quantifier's WHERE and a reduce's step keep the key's variable beside, as Neo4j groups by it there. - The reader names an unaliased map projection after its variable. - _project reads an order term written as an item, apart from its functions' names' case, as that item, so ORDER BY toupper(p.name) after TOUPPER(p.name) AS u compiles; _grouping_key lowers a function's name in a comprehension's, a quantifier's or a reduce's body too, as keyOf does. - drivine4j's CompilerRefusalTest, CypherQueryContract and CypherReaderTest cases are ported. Fixes #311
This was referenced Oct 31, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Ports drivine4j's #491, merged as liberation-data/drivine4j#496, and syncs the Cypher spec from v0.13.0 to v0.14.0 (liberation-data/drivine-cypher-spec#39).
Fixes #311
A key inside an item that aggregates (Neo4j's 42I18)
_require_explicit_groupingnow reads a key inside an aggregating item, beside its aggregates and in a body, only where the key is a variable or a variable's property (_is_plain_key). In a pattern's parts, only a variable counts. So these are refused, as Neo4j refuses them:RETURN toUpper(p.name) AS u, toUpper(p.name) + count(*) AS cRETURN toUpper(p.name) AS u, [t IN collect(m.title) | t + toUpper(p.name)] AS c. Before, this compiled: Refuse an aggregate in a WHERE, and one beside a variable no item groups by in a body or an ORDER BY, as drivine4j does, at Cypher spec v0.13.0 #310 read a key of any shape in a body.x.a.b,x['a']andx.a + 1read as a key there.RETURN p.name AS name, size([(q:Person)-[:KNOWS]->() WHERE q.name = p.name | q]) + count(*) AS c_named_in_bodiesis gone:_named_outsidereads the whole item. The ORDER BY check is unchanged. It still reads a key of any shape, as Neo4j does.Grouped by the property, not its variable
_aggregates_firstalso takes an aggregating item that reads a property key. It works the item out over the keys' columns, sor.role + count(*)besider.rolegives one row for each role, not one for each relationship. A NULL key is one group. Two property keys of one variable group by both.Neo4j has a quirk here, and the spec pins it. With the key
r.role:r.rekeyedfollows this: it replaces the key by its column in a comprehension's WHERE and leaves the other bodies as written, sorstays beside.Reader
An unaliased map projection item is named after its variable, as Neo4j names it. So
RETURN p {.name}, count(*) ORDER BY p.nameandWITH p {.name}, count(*) AS c RETURN p.namecompile.An order term written as an item, in another case
#310 compared keys with
_grouping_keyin_require_explicit_groupingand_aggregates_first. An order term that doesn't aggregate never reaches_aggregates_first, soRETURN TOUPPER(p.name) AS u, count(*) AS c ORDER BY toupper(p.name)(a spec v0.14.0 step) failed with "p is not defined"._projectnow does what drivine4j'sprojectdoes: before anything else, it rewrites an order term, or a part of one, written as an item apart from the case of its function names, to that item._grouping_keynow also lowercases function names in a comprehension's, a quantifier's or a reduce's body, as drivine4j'skeyOfdoes.Tests
CompilerRefusalTest"an aggregating item reads a key that is a variable or a variable's property…" (unit);CypherQueryContract"an aggregating item over a key that is a property groups by the property…" (integration, async and sync);CypherReaderTestnames.The golden statements are unchanged.