Compare commits

...
Author SHA1 Message Date
Philipinho 17ee613b8b fix: unaccent in trigram title search and index 2026-08-26 01:22:10 +01:00
3 changed files with 28 additions and 6 deletions
@@ -48,7 +48,7 @@ export class SearchService {
const rankColumn = browseByFilters
? sql<number>`0`.as('rank')
: titleOnly
? sql<number>`word_similarity(lower(${titleQuery}), lower(pages.title))`.as(
? sql<number>`word_similarity(lower(f_unaccent(${titleQuery})), lower(f_unaccent(pages.title)))`.as(
'rank',
)
: sql<number>`ts_rank(tsv, to_tsquery('english', f_unaccent(${searchQuery})))`.as(
@@ -84,9 +84,9 @@ export class SearchService {
.$if(!browseByFilters && titleOnly, (qb) =>
qb.where((eb) =>
eb(
sql`lower(pages.title)`,
sql`lower(f_unaccent(pages.title))`,
'like',
sql`lower(${`%${titleLikeQuery}%`})`,
sql`lower(f_unaccent(${`%${titleLikeQuery}%`}))`,
),
),
)
@@ -1,12 +1,34 @@
import { type Kysely, sql } from 'kysely';
export async function up(db: Kysely<any>): Promise<void> {
await sql`CREATE INDEX IF NOT EXISTS pages_title_trgm_idx ON pages USING gin (lower(title) gin_trgm_ops)`.execute(
// f_unaccent must be schema-qualified in its body to be usable inside an index
// expression: Postgres 15+ builds indexes under a secured search_path
// (pg_catalog, pg_temp), so an unqualified unaccent() cannot be resolved during
// CREATE INDEX. Redefine f_unaccent in place (in whatever schema it already
// lives) with the unaccent function and dictionary both qualified.
await sql`
DO $migration$
DECLARE ext_schema text;
BEGIN
SELECT n.nspname INTO ext_schema
FROM pg_extension e JOIN pg_namespace n ON n.oid = e.extnamespace
WHERE e.extname = 'unaccent';
EXECUTE format(
'CREATE OR REPLACE FUNCTION f_unaccent(text) RETURNS text '
|| 'LANGUAGE sql IMMUTABLE PARALLEL SAFE STRICT '
|| 'AS $f$ SELECT %I.unaccent(%L::regdictionary, $1) $f$',
ext_schema, ext_schema || '.unaccent');
END
$migration$;
`.execute(db);
await sql`CREATE INDEX IF NOT EXISTS pages_title_trgm_idx ON pages USING gin (lower(f_unaccent(title)) gin_trgm_ops)`.execute(
db,
);
// separators normalized to spaces so space-typed queries match How_to_export.pdf
await sql`CREATE INDEX IF NOT EXISTS attachments_file_name_trgm_idx ON attachments USING gin (lower(translate(file_name, '_.-', ' ')) gin_trgm_ops)`.execute(
await sql`CREATE INDEX IF NOT EXISTS attachments_file_name_trgm_idx ON attachments USING gin (lower(f_unaccent(translate(file_name, '_.-', ' '))) gin_trgm_ops)`.execute(
db,
);
}