fix(tests): resolve workspace compilation + CJK search failures
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled

- saas test harness: align WorkerDispatcher::new and AppState::new
  signatures with SpawnLimiter addition and init_db(&DatabaseConfig)
- growth sqlite: add CJK fallback (LIKE-based) when FTS5 unicode61
  tokenizer fails on Chinese queries (unicode61 doesn't index CJK)
This commit is contained in:
iven
2026-04-04 00:34:34 +08:00
parent 5db2907420
commit 8faefd6a61
2 changed files with 64 additions and 21 deletions

View File

@@ -497,25 +497,63 @@ impl VikingStorage for SqliteStorage {
match fts_candidates {
Ok(rows) if !rows.is_empty() => rows,
Ok(_) => {
// FTS5 returned no results — memories are genuinely irrelevant.
// Do NOT fall back to scope scan (that was the root cause of
// injecting "广东光华" memories into "1+9" queries).
Ok(_) | Err(_) => {
// FTS5 returned no results or failed — check if query contains CJK
// characters. unicode61 tokenizer doesn't index CJK, so fall back
// to LIKE-based search for CJK queries.
let has_cjk = query.chars().any(|c| {
matches!(c, '\u{4E00}'..='\u{9FFF}' | '\u{3400}'..='\u{4DBF}' | '\u{F900}'..='\u{FAFF}')
});
if !has_cjk {
tracing::debug!(
"[SqliteStorage] FTS5 returned no results for query: '{}'",
query.chars().take(50).collect::<String>()
);
return Ok(Vec::new());
}
tracing::debug!(
"[SqliteStorage] FTS5 returned no results for query: '{}'",
"[SqliteStorage] FTS5 miss for CJK query, falling back to LIKE: '{}'",
query.chars().take(50).collect::<String>()
);
return Ok(Vec::new());
}
Err(e) => {
// FTS5 syntax error after sanitization — return empty rather
// than falling back to irrelevant scope-based results.
tracing::debug!(
"[SqliteStorage] FTS5 query failed for '{}': {}",
query.chars().take(50).collect::<String>(),
e
);
return Ok(Vec::new());
let pattern = format!("%{}%", query);
if let Some(ref scope) = options.scope {
sqlx::query_as::<_, MemoryRow>(
r#"
SELECT uri, memory_type, content, keywords, importance,
access_count, created_at, last_accessed, overview, abstract_summary
FROM memories
WHERE content LIKE ?
AND uri LIKE ?
ORDER BY importance DESC, access_count DESC
LIMIT ?
"#
)
.bind(&pattern)
.bind(format!("{}%", scope))
.bind(limit as i64)
.fetch_all(&self.pool)
.await
.unwrap_or_default()
} else {
sqlx::query_as::<_, MemoryRow>(
r#"
SELECT uri, memory_type, content, keywords, importance,
access_count, created_at, last_accessed, overview, abstract_summary
FROM memories
WHERE content LIKE ?
ORDER BY importance DESC, access_count DESC
LIMIT ?
"#
)
.bind(&pattern)
.bind(limit as i64)
.fetch_all(&self.pool)
.await
.unwrap_or_default()
}
}
}
} else {