Core: tag names fold every letter, as the server does (#5385)
SQLite's lower() folds ASCII only, so a device could hold "Café" and "CAFÉ" as two tags while the server held one. derive::fold (to_lowercase) is now the one comparison. It is registered as the deterministic SQL function fold() on every connection (schema::migrate), and find_or_create, the rename clash, the pull clash and the unique index all use it. derive's push_unique used eq_ignore_ascii_case and now folds the same way. v14 merges pairs a device already holds before rebuilding the index. The older row survives, as in rename_label. Memberships move with via_tag kept, affected notes go dirty, and the merged-away row is a pending delete. It is written out rather than calling store::merge_labels so the migration doesn't depend on store code that later versions may change. rusqlite gains its "functions" feature (operator-approved, 2026-10-08). grammar.json gains "#café and #CAFÉ" -> ["café"], which all three implementations run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Vendored
+1
@@ -44,6 +44,7 @@
|
||||
{ "body": "#todo buy milk", "tags": ["todo"] },
|
||||
{ "body": "buy #milk and #eggs", "tags": ["milk", "eggs"] },
|
||||
{ "body": "#Todo and #todo", "tags": ["Todo"] },
|
||||
{ "body": "#café and #CAFÉ", "tags": ["café"] },
|
||||
{ "body": "line one\n#two", "tags": ["two"] },
|
||||
{ "body": "#tag, and #more.", "tags": ["tag", "more"] },
|
||||
{ "body": "#x-y_z9", "tags": ["x-y_z9"] },
|
||||
|
||||
Reference in New Issue
Block a user