search for standard sites pub-search.waow.tech
search zig blog atproto
12
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix: only prefix last word in FTS query

"whats up" now becomes "whats up*" instead of "whats* up*"
prevents false matches like "WhatsApp" from "whats"

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

+14 -40
+14 -40
backend/src/db/mod.zig
··· 321 321 return .{ .documents = row.int(0), .publications = row.int(1) }; 322 322 } 323 323 324 - /// Build FTS5 query with prefix matching: "cat dog" -> "cat* dog*" 324 + /// Build FTS5 query with prefix on last word only: "cat dog" -> "cat dog*" 325 325 fn buildFtsQuery(alloc: Allocator, query: []const u8) ![]const u8 { 326 326 if (query.len == 0) return ""; 327 327 328 - // normalize dots to spaces 328 + // normalize dots to spaces and trim 329 329 const normalized = try alloc.dupe(u8, query); 330 330 for (normalized) |*c| { 331 331 if (c.* == '.') c.* = ' '; 332 332 } 333 333 334 - // count words 335 - var word_count: usize = 0; 336 - var in_word = false; 337 - for (normalized) |c| { 338 - if (c == ' ') { 339 - in_word = false; 340 - } else if (!in_word) { 341 - word_count += 1; 342 - in_word = true; 343 - } 344 - } 345 - 346 - if (word_count == 0) return ""; 347 - 348 - // allocate: original length + one '*' per word 349 - const buf = try alloc.alloc(u8, normalized.len + word_count); 350 - var pos: usize = 0; 351 - in_word = false; 334 + // find actual content bounds (trim whitespace) 335 + var start: usize = 0; 336 + var end: usize = normalized.len; 337 + while (start < end and normalized[start] == ' ') start += 1; 338 + while (end > start and normalized[end - 1] == ' ') end -= 1; 352 339 353 - for (normalized) |c| { 354 - if (c == ' ') { 355 - if (in_word) { 356 - buf[pos] = '*'; 357 - pos += 1; 358 - in_word = false; 359 - } 360 - buf[pos] = ' '; 361 - pos += 1; 362 - } else { 363 - buf[pos] = c; 364 - pos += 1; 365 - in_word = true; 366 - } 367 - } 340 + if (start >= end) return ""; 368 341 369 - if (in_word) { 370 - buf[pos] = '*'; 371 - pos += 1; 372 - } 342 + // allocate: trimmed length + 1 for '*' at end 343 + const trimmed_len = end - start; 344 + const buf = try alloc.alloc(u8, trimmed_len + 1); 345 + @memcpy(buf[0..trimmed_len], normalized[start..end]); 346 + buf[trimmed_len] = '*'; 373 347 374 - return buf[0..pos]; 348 + return buf[0 .. trimmed_len + 1]; 375 349 }