Skip to content

fix: escape special characters in query-dsl page refs - #13541

Open
tiensonqin wants to merge 8 commits into
masterfrom
logseq/query-dsl-quote-page-refs-2ce2
Open

tiensonqin wants to merge 8 commits into
masterfrom
logseq/query-dsl-quote-page-refs-2ce2

Conversation

@tiensonqin

@tiensonqin tiensonqin commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Fixes logseq/db-test#1374

Query DSL strings reference pages by title — (tags [[Project"]]). After a tag was renamed to a title containing ", \, [[, or ]], pre-transform re-rendered the stored query with the raw title and cljs.reader crashed on unmatched delimiters.

Instead of hardening the reader path against arbitrary title text, this keeps page refs in their stored [[uuid]] form end to end — uuid characters are reader-safe, so the crash case can't occur.

  • Execution reads the stored title. query-result, flashcards, and the query builder now use :block/raw-title (the stored [[uuid]] form) instead of the display-substituted :block/title. Rendering continues to show titles via canonical-block's substituted :block/title.
  • New writes store [[uuid]]. ensure-query-property-on-tag-additions (pipeline), create-property-text-block!, and the file-graph exporter's handle-queries run title-ref->id-ref on query values before storing.
  • DSL clauses resolve [[uuid]] args. tags, page, between/timestamps, and (property k v) resolve ref args through ldb/get-page (which already accepts uuid strings); (property ... "2 [[uuid]]") keeps quoted values literal.
  • pre-transform keeps a simplified scanner (pr-str quoting + scan for the terminating ]]) as the fallback for legacy stored queries that still contain title-form refs and for hand-written ones.

Tests:

  • src/test/frontend/db/query_dsl_test.cljs — uuid-form args for [[uuid]], (tags), (page), (between), (property), plus the remaining title-form cases
  • deps/outliner/test/logseq/outliner/property_test.cljs — asserts query property values are stored with [[uuid]] refs
  • deps/db/test/logseq/db/frontend/query_dsl_test.cljs — trimmed to core pre-transform cases

Link to Devin session: https://app.devin.ai/sessions/89ffdb2b39ce45469c10960d91f6ecc7
Open in Devin Desktop: https://app.devin.ai/desktop/session/89ffdb2b39ce45469c10960d91f6ecc7?variant=devin
Requested by: @megayu

@devin-ai-integration
devin-ai-integration Bot force-pushed the logseq/query-dsl-quote-page-refs-2ce2 branch from ff00b3e to b7bae86 Compare September 30, 2026 16:41
@devin-ai-integration
devin-ai-integration Bot marked this pull request as ready for review September 30, 2026 16:41
devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

@devin-ai-integration

Copy link
Copy Markdown
Contributor

Before / after UX verification

Before: master a538a9b60c95490c35bf278903e60f3a9f03a330 — renaming Project to Project" causes the existing Beta task query to show “Query error”.

Before video

After: 812ef628518b6301a1ccc9a43bd7b759533f9441 — the same rename leaves the existing, unedited query working. Beta task and the renamed tag remain visible after reload.

After video

Existing query after rename and reload

Desktop quote-in-title flow passed; loaded revision verified. Other parser edge cases were not exercised in this browser recording.

@megayu
megayu self-requested a review October 1, 2026 06:48
cursoragent and others added 7 commits October 1, 2026 07:02
pre-transform quoted [[page]] titles without escaping, so renaming a
tag to include ", \, [[, or ]] made existing queries fail to parse.

Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Avoid embedding ]] inside string literals that confuse the CLJS reader
and clj-kondo when asserting page refs with bracket titles.

Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Keep titles with mid-title ]] or nested [[...]] intact, and stop
quoting a trailing vector ] as part of the page name.

Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Close the pre-transform-test form so later deftest vars register
instead of nesting inside it.

Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Treat only a lone vector ] as a closer, and stop leftover-]]
lookahead at the current list so later titles cannot steal an
earlier between date.

Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
A ) only ends leftover-]] lookahead when the next token is a
sibling list, so titles like A]] B) C stay one page-ref.

Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
After a form close, [[ starts the next argument, so a later
title ending in ]] cannot swallow an earlier between date.

Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
@devin-ai-integration
devin-ai-integration Bot force-pushed the logseq/query-dsl-quote-page-refs-2ce2 branch from 812ef62 to c83036f Compare October 1, 2026 07:03
Query DSL strings that reference pages by title (e.g. (tags [[Project"]]))
break cljs.reader when a title contains special characters like " or \\.
Instead of hardening the title-form reader path, keep page refs in their
stored [[uuid]] form end to end:

- execution reads :block/raw-title (the stored form) instead of the
  display-substituted :block/title (query-result, flashcards, query builder)
- new query value blocks write [[uuid]] refs: pipeline tag-query sync,
  create-property-text-block!, and the file-graph exporter
- dsl clauses resolve [[uuid]] args via get-page (tags/page/between/property)
- display still shows titles via canonical-block's substituted :block/title
- pre-transform keeps a simplified scanner for legacy title-form queries

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

@devin-ai-integration devin-ai-integration 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.

Devin Review found 2 new potential issues.

1 flag not posted on this PR by your GitHub settings — view it in Devin Review. (Configure)

Devin Review

Comment on lines +58 to +59
(= \) (nth s i))
false

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.

🟡 Parenthesized page titles break query parsing

For (tags [[A]] B) C]]), unmatched-page-ref-close? stops at the title's ) before seeing its final ]]. The query splits the page title at A, leaving invalid trailing text instead of matching A]] B) C.

Learn more

The scanner decides whether a candidate ]] closes a page reference by searching ahead for another unmatched ]]. Stopping that search at every ) assumes parentheses cannot occur in page titles, even when a later closing pair is part of the same title. Such page names are valid, and queries using their rendered references no longer parse.

Example: A tag titled A]] B) C appears as (tags [[A]] B) C]]). The scanner quotes only [[A]] and leaves B) C]]) as query syntax rather than matching the tag.

Recommended fix: Distinguish a parenthesis inside a reference title from a DSL form closer during lookahead, and restore coverage for ]] followed by ) and more title text.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +1395 to +1403
(if (string/includes? query "[[")
(let [ref-pages (keep (fn [[_ page-name]]
(when-let [id (or (get @page-names-to-uuids page-name)
(get @page-names-to-uuids
(common-util/page-name-sanity-lc page-name)))]
{:block/title page-name :block/uuid id}))
(re-seq page-ref/page-ref-re query))]
(if (seq ref-pages)
(db-content/title-ref->id-ref query ref-pages {:replace-tag? false})

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.

🟡 Quoted query text changes during import

When an imported query contains a quoted [[page]] literal, query-refs->id-refs replaces it with [[uuid]]. Text searches and advanced query string predicates then search for different content, changing their results.

Learn more

The importer now converts all regex-matched page references in simple, advanced, and cards query text to IDs. This includes matches inside quoted query strings. Quoted strings in DSL property or content searches, and string constants in advanced Datalog queries, can be literal text rather than page arguments. Replacing those strings changes the stored query's meaning.

Example: An advanced query whose predicate compares a title against "[[Foo]]" is imported while a Foo page exists. The string becomes "[[<Foo's UUID>]]", so the predicate no longer matches the original title.

Recommended fix: Parse the query format and convert only syntactic page-reference operands, preserving quoted string literals. Add tests for quoted refs in advanced queries and literal-content searches.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

@devin-ai-integration

Copy link
Copy Markdown
Contributor

End-to-end verified on the Desktop dev build (Electron, db graph) — tag created, block tagged, query node running (tags [[<uuid>]]), tag renamed to Project", and the query still executes with title-form display.

Query results — tag renamed to Project" (was the cljs.reader crash case):

post-rename query still returns the tagged block

The Project" tag page — title with " works, linked ref shows the query node:

Project" tag page

What was verified
  • (tags [[Project]]) → executes, returns the tagged block (uuid-form args resolve via ldb/get-page)
  • Stored value block :block/title = (tags [[6abe25d2-bf65-4bb7-bda8-c1a34e549456]]) — [[uuid]], not [[Project]] (verified via db-worker pull)
  • Rename Project → Project" → existing query still executes; display shows Project" title everywhere, never the uuid
  • Hand-written title-form (tags [[Project"]]) executes through the worker parse path (scanner fallback)
  • create-property-text-block! write path converts [[Title]] → [[uuid]] on property-value writes
  • page / between clauses also resolve [[uuid]] args correctly

One unrelated pre-existing issue noticed while testing: /Query currently leaves the query value block empty (title not transferred) — git-blamed to fe65e36f13f, outside this diff; I typed the query into the value block directly to test.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Renaming a tag to a title with a double quote breaks every query that filters on it

3 participants