Skip to content

Fix backtick stripping in Cypher map literal keys - #3322

Merged
robfrank merged 1 commit into
ArcadeData:mainfrom
ExtReMLapin:claude/fix-cypher-backticks-ZP7Ub
Feb 4, 2026
Merged

Fix backtick stripping in Cypher map literal keys#3322
robfrank merged 1 commit into
ArcadeData:mainfrom
ExtReMLapin:claude/fix-cypher-backticks-ZP7Ub

Conversation

@ExtReMLapin

Copy link
Copy Markdown
Contributor

What does this PR do?

This PR fixes an issue where backticks in map literal keys were not being properly stripped during Cypher query parsing. The stripBackticks method in CypherASTBuilder is now made static and called when parsing map literals in CypherExpressionBuilder, ensuring that backticked keys (e.g., `@rid`) are correctly converted to their unquoted form (e.g., @rid).

Motivation

When using map literals in Cypher queries with backticked keys (commonly needed for special characters like @), the backticks were being retained in the resulting map keys. This caused queries like:

RETURN {`@rid`: ID(c), text: c.text} AS chunks

to produce maps with keys like `@rid` instead of @rid, breaking downstream code that expected the unquoted key names.

Related issues

This fix addresses the handling of backticked identifiers in map literals, which is part of the Cypher specification for escaping reserved words and special characters.

Additional Notes

  • The stripBackticks method is now static to allow reuse across different builder classes
  • Two locations in CypherExpressionBuilder now call this method: parseMapLiteralExpression and parseMapProperties
  • Comprehensive test coverage added with three test cases covering:
    • Single backticked keys in map literals
    • Multiple backticked keys in the same map
    • Escaped backticks within key names ( ` ``)

Checklist

  • I have run the build using mvn clean package command
  • My unit tests cover both failure and success scenarios

https://claude.ai/code/session_01ATpxvdUh9HNtuBW7x9NmLT

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @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 resolves an issue in the Cypher parser where map literal keys enclosed in backticks were not being properly unquoted. This fix ensures that keys like `@rid` are correctly processed as @rid, aligning with the Cypher specification and preventing unexpected behavior in applications consuming these query results.

Highlights

  • Method Visibility and Reusability: The stripBackticks method in CypherASTBuilder has been made static to allow its reuse across different builder classes, improving code modularity.
  • Cypher Map Literal Key Parsing: The CypherExpressionBuilder now correctly strips backticks from map literal keys by calling the CypherASTBuilder.stripBackticks method within both parseMapLiteralExpression and parseMapProperties.
  • Comprehensive Test Coverage: New unit tests have been added in CypherMapBackticksTest.java to validate the correct stripping of backticks from map literal keys, covering scenarios with single backticked keys, multiple backticked keys, and escaped backticks within key names.

🧠 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.

Changelog
  • engine/src/main/java/com/arcadedb/query/opencypher/parser/CypherASTBuilder.java
    • Changed the stripBackticks method from private to static to enable broader accessibility.
  • engine/src/main/java/com/arcadedb/query/opencypher/parser/CypherExpressionBuilder.java
    • Modified parseMapLiteralExpression to apply CypherASTBuilder.stripBackticks to map keys, ensuring backticks are removed.
    • Modified parseMapProperties to apply CypherASTBuilder.stripBackticks to map keys, ensuring backticks are removed.
  • engine/src/test/java/com/arcadedb/query/opencypher/CypherMapBackticksTest.java
    • Added a new test file to validate the correct stripping of backticks from map literal keys.
    • Included test cases for single backticked keys, multiple backticked keys, and escaped backticks (e.g., -> ` ``).
Activity
  • The author, ExtReMLapin, has confirmed that the build has been run using mvn clean package.
  • Unit tests covering both failure and success scenarios have been implemented and verified by the author.
  • Development of this feature appears to have involved AI assistance, as indicated by a Claude AI session link in the PR description.
Using Gemini Code Assist

The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

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

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request correctly addresses an issue with backticked keys in Cypher map literals by introducing and applying the stripBackticks utility method. The change to make stripBackticks static is a good design choice for reusability, and the new tests provide solid coverage for the fixed scenarios. However, the fix appears to be partial, as similar logic is needed in other parts of the parser to ensure consistent handling of backticked keys across all map-like constructs. I've added a specific comment detailing the missed locations.

@mergify

mergify Bot commented Feb 4, 2026

Copy link
Copy Markdown
Contributor

🧪 CI Insights

Here's what we observed from your CI run for 42b9260.

🟢 All jobs passed!

But CI Insights is watching 👀

@ExtReMLapin

Copy link
Copy Markdown
Contributor Author

Claude wrote all of this.

Fixes #3321

@ExtReMLapin
ExtReMLapin force-pushed the claude/fix-cypher-backticks-ZP7Ub branch 2 times, most recently from 5e4d1d3 to 1c64267 Compare February 4, 2026 09:05
Fixed an issue where backticks in map literal keys and property names
were being included instead of being properly stripped. Applied the fix
consistently across all map-related and property access parsing contexts.

Changes:
- Made CypherASTBuilder.stripBackticks() static and package-private
  to allow access from CypherExpressionBuilder
- Updated CypherExpressionBuilder.parseMapLiteralExpression() to strip
  backticks from map keys (RETURN clause map literals)
- Updated CypherExpressionBuilder.parseMapProperties() to strip
  backticks from map keys (pattern properties)
- Updated CypherASTBuilder.visitMap() to strip backticks from map keys
  (CREATE/MERGE clause map literals)
- Updated CypherExpressionBuilder.parseMapProjection() to strip
  backticks from both explicit keys and property names (map projections)
- Updated CypherExpressionBuilder.parseExpression2WithPostfix() to strip
  backticks from property names in property access expressions
- Updated CypherExpressionBuilder.parseExpressionText() to strip
  backticks from property names in text-based parsing
- Added comprehensive test cases in CypherMapBackticksTest to verify:
  - Single backticked key in RETURN (e.g., `@rid`)
  - Multiple backticked keys in RETURN
  - Escaped backticks within keys (e.g., `key``with``backticks`)
  - Backticked keys in CREATE clause
  - Backticked keys in map projections
  - Property access with backticked names (e.g., n.`@id`)

Example queries that now work correctly:
- RETURN: collect({`@rid`: ID(c), text: c.text})
- CREATE: CREATE (n {`@special`: 'value'})
- Map projection: n{.name, `@id`: n.id}
- Property access: RETURN n.`@special`

Before: keys/properties were stored/accessed as "`@rid`" (with backticks)
After: keys/properties are stored/accessed as "@Rid" (without backticks)

https://claude.ai/code/session_01ATpxvdUh9HNtuBW7x9NmLT
@ExtReMLapin
ExtReMLapin force-pushed the claude/fix-cypher-backticks-ZP7Ub branch from 1c64267 to 42b9260 Compare February 4, 2026 09:13
@ExtReMLapin

Copy link
Copy Markdown
Contributor Author

mvn test -Dtest="com.arcadedb.query.opencypher.**.*"

[INFO] ArcadeDB ........................................... SUCCESS [ 0.038 s]
[INFO] ArcadeDB Engine .................................... SUCCESS [ 13.498 s]

@robfrank robfrank added this to the 26.2.1 milestone Feb 4, 2026
@codecov

codecov Bot commented Feb 4, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.71429% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 56.58%. Comparing base (0ffaf5b) to head (42b9260).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...ery/opencypher/parser/CypherExpressionBuilder.java 83.33% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3322      +/-   ##
==========================================
- Coverage   56.61%   56.58%   -0.03%     
==========================================
  Files        1368     1368              
  Lines      100618   100618              
  Branches    20486    20486              
==========================================
- Hits        56961    56934      -27     
- Misses      34538    34545       +7     
- Partials     9119     9139      +20     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@robfrank
robfrank merged commit ada9a89 into ArcadeData:main Feb 4, 2026
15 of 20 checks passed
robfrank pushed a commit that referenced this pull request Feb 17, 2026
…3322)

Fixed an issue where backticks in map literal keys and property names
were being included instead of being properly stripped. Applied the fix
consistently across all map-related and property access parsing contexts.

Changes:
- Made CypherASTBuilder.stripBackticks() static and package-private
  to allow access from CypherExpressionBuilder
- Updated CypherExpressionBuilder.parseMapLiteralExpression() to strip
  backticks from map keys (RETURN clause map literals)
- Updated CypherExpressionBuilder.parseMapProperties() to strip
  backticks from map keys (pattern properties)
- Updated CypherASTBuilder.visitMap() to strip backticks from map keys
  (CREATE/MERGE clause map literals)
- Updated CypherExpressionBuilder.parseMapProjection() to strip
  backticks from both explicit keys and property names (map projections)
- Updated CypherExpressionBuilder.parseExpression2WithPostfix() to strip
  backticks from property names in property access expressions
- Updated CypherExpressionBuilder.parseExpressionText() to strip
  backticks from property names in text-based parsing
- Added comprehensive test cases in CypherMapBackticksTest to verify:
  - Single backticked key in RETURN (e.g., `@rid`)
  - Multiple backticked keys in RETURN
  - Escaped backticks within keys (e.g., `key``with``backticks`)
  - Backticked keys in CREATE clause
  - Backticked keys in map projections
  - Property access with backticked names (e.g., n.`@id`)

Before: keys/properties were stored/accessed as "`@rid`" (with backticks)
After: keys/properties are stored/accessed as "@Rid" (without backticks)

(cherry picked from commit ada9a89)
tae898 pushed a commit to humemai/arcadedb-embedded-python that referenced this pull request Jun 28, 2026
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.31.4 to 4.31.5.
Release notes

*Sourced from [github/codeql-action's releases](https://github.com/github/codeql-action/releases).*

> v4.31.5
> -------
>
> CodeQL Action Changelog
> =======================
>
> See the [releases page](https://github.com/github/codeql-action/releases) for the relevant changes to the CodeQL CLI and language packs.
>
> 4.31.5 - 24 Nov 2025
> --------------------
>
> * Update default CodeQL bundle version to 2.23.6. [ArcadeData#3321](https://redirect.github.com/github/codeql-action/pull/3321)
>
> See the full [CHANGELOG.md](https://github.com/github/codeql-action/blob/v4.31.5/CHANGELOG.md) for more information.


Changelog

*Sourced from [github/codeql-action's changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md).*

> CodeQL Action Changelog
> =======================
>
> See the [releases page](https://github.com/github/codeql-action/releases) for the relevant changes to the CodeQL CLI and language packs.
>
> [UNRELEASED]
> ------------
>
> No user facing changes.
>
> 4.31.5 - 24 Nov 2025
> --------------------
>
> * Update default CodeQL bundle version to 2.23.6. [ArcadeData#3321](https://redirect.github.com/github/codeql-action/pull/3321)
>
> 4.31.4 - 18 Nov 2025
> --------------------
>
> No user facing changes.
>
> 4.31.3 - 13 Nov 2025
> --------------------
>
> * CodeQL Action v3 will be deprecated in December 2026. The Action now logs a warning for customers who are running v3 but could be running v4. For more information, see [Upcoming deprecation of CodeQL Action v3](https://github.blog/changelog/2025-10-28-upcoming-deprecation-of-codeql-action-v3/).
> * Update default CodeQL bundle version to 2.23.5. [ArcadeData#3288](https://redirect.github.com/github/codeql-action/pull/3288)
>
> 4.31.2 - 30 Oct 2025
> --------------------
>
> No user facing changes.
>
> 4.31.1 - 30 Oct 2025
> --------------------
>
> * The `add-snippets` input has been removed from the `analyze` action. This input has been deprecated since CodeQL Action 3.26.4 in August 2024 when this removal was announced.
>
> 4.31.0 - 24 Oct 2025
> --------------------
>
> * Bump minimum CodeQL bundle version to 2.17.6. [ArcadeData#3223](https://redirect.github.com/github/codeql-action/pull/3223)
> * When SARIF files are uploaded by the `analyze` or `upload-sarif` actions, the CodeQL Action automatically performs post-processing steps to prepare the data for the upload. Previously, these post-processing steps were only performed before an upload took place. We are now changing this so that the post-processing steps will always be performed, even when the SARIF files are not uploaded. This does not change anything for the `upload-sarif` action. For `analyze`, this may affect Advanced Setup for CodeQL users who specify a value other than `always` for the `upload` input. [ArcadeData#3222](https://redirect.github.com/github/codeql-action/pull/3222)
>
> 4.30.9 - 17 Oct 2025
> --------------------
>
> * Update default CodeQL bundle version to 2.23.3. [ArcadeData#3205](https://redirect.github.com/github/codeql-action/pull/3205)
> * Experimental: A new `setup-codeql` action has been added which is similar to `init`, except it only installs the CodeQL CLI and does not initialize a database. Do not use this in production as it is part of an internal experiment and subject to change at any time. [ArcadeData#3204](https://redirect.github.com/github/codeql-action/pull/3204)
>
> 4.30.8 - 10 Oct 2025
> --------------------
>
> No user facing changes.
>
> 4.30.7 - 06 Oct 2025
> --------------------
>
> * [v4+ only] The CodeQL Action now runs on Node.js v24. [ArcadeData#3169](https://redirect.github.com/github/codeql-action/pull/3169)
>
> 3.30.6 - 02 Oct 2025
> --------------------
>
> * Update default CodeQL bundle version to 2.23.2. [ArcadeData#3168](https://redirect.github.com/github/codeql-action/pull/3168)

... (truncated)


Commits

* [`fdbfb4d`](github/codeql-action@fdbfb4d) Merge pull request [ArcadeData#3322](https://redirect.github.com/github/codeql-action/issues/3322) from github/update-v4.31.5-ec2ee575c
* [`81f6d64`](github/codeql-action@81f6d64) Update changelog for v4.31.5
* [`ec2ee57`](github/codeql-action@ec2ee57) Merge pull request [ArcadeData#3321](https://redirect.github.com/github/codeql-action/issues/3321) from github/update-bundle/codeql-bundle-v2.23.6
* [`ecc8787`](github/codeql-action@ecc8787) Add changelog note
* [`1d2a238`](github/codeql-action@1d2a238) Update default bundle to codeql-bundle-v2.23.6
* [`ce729e4`](github/codeql-action@ce729e4) Merge pull request [ArcadeData#3315](https://redirect.github.com/github/codeql-action/issues/3315) from github/henrymercer/dead-code-elimination
* [`ac359aa`](github/codeql-action@ac359aa) Add return type
* [`112cd07`](github/codeql-action@112cd07) Merge branch 'main' into henrymercer/dead-code-elimination
* [`0b43179`](github/codeql-action@0b43179) Merge pull request [ArcadeData#3306](https://redirect.github.com/github/codeql-action/issues/3306) from github/dependabot/npm\_and\_yarn/types/sinon-21.0.0
* [`e818008`](github/codeql-action@e818008) Merge pull request [ArcadeData#3305](https://redirect.github.com/github/codeql-action/issues/3305) from github/dependabot/npm\_and\_yarn/eslint/compat-2.0.0
* Additional commits viewable in [compare view](github/codeql-action@e12f017...fdbfb4d)
  
[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility\_score?dependency-name=github/codeql-action&package-manager=github\_actions&previous-version=4.31.4&new-version=4.31.5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
  
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show  ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
tae898 pushed a commit to humemai/arcadedb-embedded-python that referenced this pull request Jun 28, 2026
…queries (ArcadeData#3322)

Fixed an issue where backticks in map literal keys and property names
were being included instead of being properly stripped. Applied the fix
consistently across all map-related and property access parsing contexts.

Changes:
- Made CypherASTBuilder.stripBackticks() static and package-private
  to allow access from CypherExpressionBuilder
- Updated CypherExpressionBuilder.parseMapLiteralExpression() to strip
  backticks from map keys (RETURN clause map literals)
- Updated CypherExpressionBuilder.parseMapProperties() to strip
  backticks from map keys (pattern properties)
- Updated CypherASTBuilder.visitMap() to strip backticks from map keys
  (CREATE/MERGE clause map literals)
- Updated CypherExpressionBuilder.parseMapProjection() to strip
  backticks from both explicit keys and property names (map projections)
- Updated CypherExpressionBuilder.parseExpression2WithPostfix() to strip
  backticks from property names in property access expressions
- Updated CypherExpressionBuilder.parseExpressionText() to strip
  backticks from property names in text-based parsing
- Added comprehensive test cases in CypherMapBackticksTest to verify:
  - Single backticked key in RETURN (e.g., `@rid`)
  - Multiple backticked keys in RETURN
  - Escaped backticks within keys (e.g., `key``with``backticks`)
  - Backticked keys in CREATE clause
  - Backticked keys in map projections
  - Property access with backticked names (e.g., n.`@id`)

Before: keys/properties were stored/accessed as "`@rid`" (with backticks)
After: keys/properties are stored/accessed as "@Rid" (without backticks)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cypher : `collect({@rid: ID(c), text: c.text})` should return a key with no backtick

3 participants