Fix Cypher RETURN clause to unwrap single element results#3268
Fix Cypher RETURN clause to unwrap single element results#3268lvca merged 3 commits intoArcadeData:mainfrom
Conversation
When a Cypher query uses a single-variable RETURN clause (e.g.,
MATCH (n) RETURN n), the new OpenCypher engine was wrapping results
as {"n": element} instead of returning the element directly. This
differed from the Gremlin-based Cypher engine behavior where
MATCH (n) RETURN n returns [a, b, c] not [{"n":a}, {"n":b}, {"n":c}].
The fix is in FinalProjectionStep.filterResult(): when the RETURN
clause has exactly one item and its value is a Document (vertex/edge),
return it as an element-based ResultInternal instead of wrapping it
in a property map. Multi-variable RETURNs (e.g., RETURN n, m) are
unaffected and continue to use property maps.
https://claude.ai/code/session_01LmNejBtujWGirVHcc2ackZ
Summary of ChangesHello @ExtReMLapin, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request refines the OpenCypher query engine's result formatting to ensure consistency with standard Cypher semantics and the Gremlin-based implementation. Specifically, it modifies the Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
|
Claude wrote all of this, I just described the issue and the diagnosis. |
🧪 CI InsightsHere's what we observed from your CI run for 1290aee. 🟢 All jobs passed!But CI Insights is watching 👀 |
There was a problem hiding this comment.
Code Review
This pull request correctly aligns the OpenCypher engine's behavior with standard Cypher semantics by unwrapping single-element results. The core logic change in FinalProjectionStep.java is concise and effective. The addition of CypherResultFormatTest.java provides excellent, focused test coverage for this new behavior, and the updates to existing tests ensure the entire test suite is consistent with the change.
I've added a few suggestions to improve code clarity and ensure compatibility with older Java versions. Overall, this is a solid improvement that enhances the engine's consistency and usability.
| assertThat(results.getFirst().isElement()) | ||
| .as("Edge result should be an element, not a projection").isTrue(); |
There was a problem hiding this comment.
The List.getFirst() method was introduced in Java 21. If this project targets an earlier Java version, this will cause a compilation error. For better backward compatibility and consistency with other tests, consider using results.get(0) instead.
| assertThat(results.getFirst().isElement()) | |
| .as("Edge result should be an element, not a projection").isTrue(); | |
| assertThat(results.get(0).isElement()) | |
| .as("Edge result should be an element, not a projection").isTrue(); |
There was a problem hiding this comment.
I'm pretty sure we target >= Java 21
engine/src/test/java/com/arcadedb/query/opencypher/CypherResultFormatTest.java
Show resolved
Hide resolved
| final String singleProp = requestedProperties.iterator().next(); | ||
| if (inputResult.hasProperty(singleProp)) { | ||
| final Object value = inputResult.getProperty(singleProp); | ||
| if (value instanceof Document doc) { | ||
| return new ResultInternal(doc); | ||
| } | ||
| } |
There was a problem hiding this comment.
The inputResult.hasProperty(singleProp) check is redundant. The getProperty(singleProp) method will return null if the property doesn't exist, and null instanceof Document evaluates to false. You can simplify the code by removing the hasProperty check.
final String singleProp = requestedProperties.iterator().next();
final Object value = inputResult.getProperty(singleProp);
if (value instanceof Document doc) {
return new ResultInternal(doc);
}Tests for startNode() and endNode() Cypher functions also use single-variable RETURN clauses that return Vertex results. Update them to use result.toElement() instead of result.getProperty(). https://claude.ai/code/session_01LmNejBtujWGirVHcc2ackZ
|
Amazing, thanks! |
* fix: single-variable Cypher RETURN now returns elements directly
When a Cypher query uses a single-variable RETURN clause (e.g.,
MATCH (n) RETURN n), the new OpenCypher engine was wrapping results
as {"n": element} instead of returning the element directly. This
differed from the Gremlin-based Cypher engine behavior where
MATCH (n) RETURN n returns [a, b, c] not [{"n":a}, {"n":b}, {"n":c}].
The fix is in FinalProjectionStep.filterResult(): when the RETURN
clause has exactly one item and its value is a Document (vertex/edge),
return it as an element-based ResultInternal instead of wrapping it
in a property map. Multi-variable RETURNs (e.g., RETURN n, m) are
unaffected and continue to use property maps.
https://claude.ai/code/session_01LmNejBtujWGirVHcc2ackZ
* Fixed broken tests
* fix: update startNode/endNode function tests for single-var RETURN
Tests for startNode() and endNode() Cypher functions also use
single-variable RETURN clauses that return Vertex results. Update
them to use result.toElement() instead of result.getProperty().
https://claude.ai/code/session_01LmNejBtujWGirVHcc2ackZ
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: CNE Pierre FICHEPOIL <pierre-1.fichepoil@gendarmerie.interieur.gouv.fr>
(cherry picked from commit 1e65c9a)
What does this PR do?
This PR fixes the OpenCypher query engine to properly unwrap single element results when returning a single node or edge variable. When a Cypher query like
MATCH (n) RETURN nis executed, the result should be the element directly (a Vertex or Edge), not wrapped in a projection map like{"n": element}. This aligns with standard Cypher behavior and matches the behavior of the Gremlin-based Cypher engine.Changes Made:
FinalProjectionStep.java: Added logic to detect when a single property is being returned that resolves to a Document (vertex/edge) and return it as an element result directly instead of wrapping it in a projection.
CypherResultFormatTest.java (new): Added comprehensive test coverage for the new behavior, including:
Test Updates: Updated 15+ existing test files to use
result.toElement()instead ofresult.getProperty("varName")when accessing single returned elements, reflecting the new behavior.Motivation
The previous behavior of wrapping single element returns in projection maps was inconsistent with standard Cypher semantics and the Gremlin-based implementation. This caused confusion and required workarounds in test code. By unwrapping single element results, we provide a more intuitive and standards-compliant API.
Related issues
This fix addresses the inconsistency between the OpenCypher and Gremlin-based Cypher engines in result formatting.
Additional Notes
result.toElement()provides the same functionality as the previousresult.getProperty("varName")approachChecklist
mvn clean packagecommandhttps://claude.ai/code/session_01LmNejBtujWGirVHcc2ackZ