fix: global search case-insensitive + keyboard layout swap
Unified search normalization across InternalLinkPicker and GlobalSearch: 1. GlobalSearch.svelte: multi-variant search (same as InternalLinkPicker) - expandKeyboardVariants() for RU/EN layout swap - Parallel Search queries with dedup by type+nodeId+targetId+title - 180ms debounce preserved 2. Backend: fix LOWER() in SQL for links/actions - Replace LOWER(column) LIKE with lowercased columns (title_lower, url_lower, etc.) - Migration 020: add lowercased columns + indexes for links and actions - BackfillLinksLower() + BackfillActionsLower() in storage.go - Update INSERT in bindings_links.go and action.go to populate lowercased columns 3. FTS5 search: Unicode case-insensitive - Index lowercased title/content/tags in search_index - sanitizeFTS() now lowercases query before MATCH - RebuildFTS() called after migrations 4. Case-insensitive search for nodes (already done in previous commit, verified): - title_lower column with Go strings.ToLower - Search() queries title_lower with lowercased query All test suites PASS, full build OK.
This commit is contained in:
@@ -127,9 +127,11 @@ func (a *App) createResolvedLink(nodeID, rawURL, title, note, source, capturedAt
|
||||
now := time.Now().UTC().Format(time.RFC3339)
|
||||
id := util.UUID7()
|
||||
if _, err := a.db.Exec(
|
||||
`INSERT INTO links (id,node_id,title,url,hostname,note,source,captured_at,created_at,updated_at)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?)`,
|
||||
id, nodeID, title, rawURL, hostnameForURL(rawURL), note, source, capturedAt, now, now); err != nil {
|
||||
`INSERT INTO links (id,node_id,title,url,hostname,note,source,captured_at,created_at,updated_at,
|
||||
title_lower,url_lower,hostname_lower,note_lower)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,
|
||||
id, nodeID, title, rawURL, hostnameForURL(rawURL), note, source, capturedAt, now, now,
|
||||
strings.ToLower(title), strings.ToLower(rawURL), strings.ToLower(hostnameForURL(rawURL)), strings.ToLower(note)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return a.getLink(id)
|
||||
|
||||
@@ -321,7 +321,7 @@ func (a *App) Search(query string) ([]SearchResultDTO, error) {
|
||||
FROM links l
|
||||
LEFT JOIN nodes n ON n.id = l.node_id
|
||||
WHERE n.deleted_at IS NULL
|
||||
AND (LOWER(l.title) LIKE ? OR LOWER(l.url) LIKE ? OR LOWER(l.hostname) LIKE ? OR LOWER(COALESCE(l.note,'')) LIKE ?)
|
||||
AND (l.title_lower LIKE ? OR l.url_lower LIKE ? OR l.hostname_lower LIKE ? OR l.note_lower LIKE ?)
|
||||
ORDER BY l.created_at DESC
|
||||
LIMIT ?`,
|
||||
likeQuery(query), likeQuery(query), likeQuery(query), likeQuery(query), 20-len(out))
|
||||
@@ -359,7 +359,7 @@ func (a *App) Search(query string) ([]SearchResultDTO, error) {
|
||||
FROM actions ac
|
||||
LEFT JOIN nodes n ON n.id = ac.node_id
|
||||
WHERE n.deleted_at IS NULL
|
||||
AND (LOWER(ac.title) LIKE ? OR LOWER(ac.kind) LIKE ? OR LOWER(COALESCE(ac.url,'')) LIKE ? OR LOWER(COALESCE(ac.command,'')) LIKE ?)
|
||||
AND (ac.title_lower LIKE ? OR ac.kind_lower LIKE ? OR ac.url_lower LIKE ? OR ac.command_lower LIKE ?)
|
||||
ORDER BY ac.created_at DESC
|
||||
LIMIT ?`,
|
||||
likeQuery(query), likeQuery(query), likeQuery(query), likeQuery(query), 20-len(out))
|
||||
|
||||
+21
-21
File diff suppressed because one or more lines are too long
@@ -19,7 +19,7 @@
|
||||
background: #13131f;
|
||||
}
|
||||
</style>
|
||||
<script type="module" crossorigin src="/assets/main-Dn9NERfF.js"></script>
|
||||
<script type="module" crossorigin src="/assets/main-FdTYg97q.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/main-bQpH1es2.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
Reference in New Issue
Block a user