feat(lapis): support escaping single quotes in advanced query string values#1599
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
This PR updates the LAPIS advanced query language to support escaping within single-quoted metadata values, enabling queries like country='Côte d\'Ivoire' and treating backslash as an escape character inside quoted strings.
Changes:
- Extend the ANTLR grammar for quoted strings to support backslash escapes within single-quoted values.
- Unescape backslash-escaped characters when mapping parsed metadata values into the query model.
- Update tests and docs to cover escaped single quotes/backslashes and the new regex-escape requirements.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| lapis/src/test/kotlin/org/genspectrum/lapis/model/AdvancedQueryFacadeTest.kt | Updates/extends test cases for escaped quotes/backslashes and regex behavior. |
| lapis/src/main/kotlin/org/genspectrum/lapis/model/AdvancedQueryCustomListener.kt | Unescapes parsed quoted values before creating filter expressions. |
| lapis/src/main/antlr/org/genspectrum/lapis/model/advancedqueryparser/AdvancedQuery.g4 | Adjusts QUOTED_STRING lexer rule to allow backslash escapes. |
| lapis-docs/src/content/docs/concepts/advanced-query.mdx | Documents escaping single quotes and backslashes in quoted metadata values. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| DOT: '.'; | ||
| ASTERISK: '*'; | ||
| QUOTED_STRING: '\'' (~['\r\n])* '\''; // matches all strings with quotes, except if they contain a newline | ||
| QUOTED_STRING: '\'' ( '\\' . | ~['\\\r\n] )* '\''; // matches all strings with quotes, supports \' to escape a single quote |
There was a problem hiding this comment.
I simply decided to treat newlines as literal characters there. I don't see the need for the additional complexity of somehow getting rid of them and then having weird, inconsistent behavior.
lapis/src/main/kotlin/org/genspectrum/lapis/model/AdvancedQueryCustomListener.kt
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Pull request overview
Adds support for escaping single quotes (and backslashes) inside quoted values in LAPIS advanced queries, enabling queries like country='Côte d\'Ivoire' and requiring doubled backslashes for literal backslashes in regex patterns.
Changes:
- Update ANTLR grammar to allow backslash-escaped characters inside
QUOTED_STRING. - Unescape quoted metadata values in the advanced query listener.
- Extend tests and documentation with examples for escaped quotes/backslashes and newline handling.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| lapis/src/test/kotlin/org/genspectrum/lapis/model/AdvancedQueryFacadeTest.kt | Adds/updates test cases for escaped quotes/backslashes (including regex) and newline behavior. |
| lapis/src/main/kotlin/org/genspectrum/lapis/model/AdvancedQueryCustomListener.kt | Introduces unescaping for quoted values in enterMetadataQuery. |
| lapis/src/main/antlr/org/genspectrum/lapis/model/advancedqueryparser/AdvancedQuery.g4 | Extends QUOTED_STRING token to support backslash escaping. |
| lapis-docs/src/content/docs/concepts/advanced-query.mdx | Documents escaping single quotes and backslashes in quoted values. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| override fun enterMetadataQuery(ctx: AdvancedQueryParser.MetadataQueryContext) { | ||
| val metadataName = ctx.name().text | ||
| val metadataValue = ctx.value().text.trim('\'') | ||
| val metadataValue = ctx.value().text.trim('\'').replace(ESCAPE_SEQUENCE_REGEX, "$1") | ||
|
|
There was a problem hiding this comment.
I don't think this is true? There is a test that checks it.
anna-parker
left a comment
There was a problem hiding this comment.
this looks good, could you add some examples of some more weird characters that are escaped e.g. umlaut?
Yes, but I'll make a separate issue for that. It's beyond the scope of this PR. |
🤖 I have created a release *beep* *boop* --- ## [0.8.0](v0.7.2...v0.8.0) (2026-03-19) ### ⚠ BREAKING CHANGES * **lapis:** Backslash is now an escape character inside quoted strings. In regex queries that use `\` as a regex escape, you'll need to pass `\\` now, e.g. before: `division.regex=Basel\{1,2\}` -> after: `division.regex=Basel\\{1,2\\}` ### Features * **lapis:** support escaping single quotes in advanced query string values ([#1599](#1599)) ([88d59e9](88d59e9)) ### Bug Fixes * **lapis:** health check: consider LAPIS "UP" even when SILO is down ([#1594](#1594)) ([b9abdf9](b9abdf9)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
resolves #1597
Inside a quoted value,
\'now produces a literal', and\\produces a literal\.BREAKING CHANGE: Backslash is now an escape character inside quoted strings. In regex queries that use
\as a regex escape, you'll need to pass\\now, e.g. before:division.regex=Basel\{1,2\}-> after:division.regex=Basel\\{1,2\\}PR Checklist
- [ ] All necessary changes are explained in thellms.txt.