feat: food search sheet with FTS+trgm, dish/recent endpoints, multilingual aliases
Backend: - GET /dishes/search — hybrid FTS (english + simple) + trgm + ILIKE search - GET /diary/recent — recently used dishes and products for the current user - product search upgraded: FTS on canonical_name and product_aliases, ranked by GREATEST(ts_rank, similarity) - importoff: collect product_name_ru/de/fr/... as product_aliases for multilingual search (e.g. "сникерс" → "Snickers") - migrations: FTS + trgm indexes merged into 001_initial_schema.sql (002 removed) Flutter: - FoodSearchSheet: debounced search field, recently-used section, product/dish results, scan-photo and barcode chips - DishPortionSheet: quick ½/1/1½/2 buttons + custom input - + button in meal card now opens FoodSearchSheet instead of going directly to AI scan - 7 new l10n keys across all 12 languages Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -202,15 +202,33 @@ func (r *Repository) Search(requestContext context.Context, query string, limit
|
||||
FROM product_aliases pa
|
||||
WHERE pa.product_id = p.id AND pa.lang = $3
|
||||
) al ON true
|
||||
WHERE EXISTS (
|
||||
SELECT 1 FROM product_aliases pa
|
||||
WHERE pa.product_id = p.id
|
||||
AND (pa.lang = $3 OR pa.lang = 'en')
|
||||
AND pa.alias ILIKE '%' || $1 || '%'
|
||||
WHERE (
|
||||
to_tsvector('english', p.canonical_name) @@ plainto_tsquery('english', $1)
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM product_aliases pa
|
||||
WHERE pa.product_id = p.id
|
||||
AND (pa.lang = $3 OR pa.lang = 'en')
|
||||
AND to_tsvector('simple', pa.alias) @@ plainto_tsquery('simple', $1)
|
||||
)
|
||||
OR p.canonical_name ILIKE '%' || $1 || '%'
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM product_aliases pa
|
||||
WHERE pa.product_id = p.id
|
||||
AND (pa.lang = $3 OR pa.lang = 'en')
|
||||
AND pa.alias ILIKE '%' || $1 || '%'
|
||||
)
|
||||
OR similarity(p.canonical_name, $1) > 0.3
|
||||
)
|
||||
OR p.canonical_name ILIKE '%' || $1 || '%'
|
||||
OR similarity(p.canonical_name, $1) > 0.3
|
||||
ORDER BY similarity(p.canonical_name, $1) DESC
|
||||
ORDER BY
|
||||
GREATEST(
|
||||
ts_rank(to_tsvector('english', p.canonical_name), plainto_tsquery('english', $1)),
|
||||
COALESCE((
|
||||
SELECT MAX(ts_rank(to_tsvector('simple', pa.alias), plainto_tsquery('simple', $1)))
|
||||
FROM product_aliases pa
|
||||
WHERE pa.product_id = p.id AND (pa.lang = $3 OR pa.lang = 'en')
|
||||
), 0),
|
||||
similarity(p.canonical_name, $1)
|
||||
) DESC
|
||||
LIMIT $2`
|
||||
|
||||
rows, queryError := r.pool.Query(requestContext, searchQuery, query, limit, lang)
|
||||
|
||||
Reference in New Issue
Block a user