-- Persian normalization fn (idempotent via OR REPLACE). CREATE OR REPLACE FUNCTION teknav_norm_fa(t text) RETURNS text LANGUAGE sql IMMUTABLE PARALLEL SAFE AS $$ SELECT regexp_replace( translate( coalesce(t, ''), E'يكأإآٱ‌ـًٌٍَُِّْ،؛؟', E'یکاااا ,;?' ), '\s+', ' ', 'g' ); $$; -- Trigram support for autocomplete / fuzzy matching. CREATE EXTENSION IF NOT EXISTS pg_trgm; -- Weighted tsvector computed column (A=title, B=subtitle+summary, C=content). ALTER TABLE "Article" ADD COLUMN IF NOT EXISTS "search_tsv" tsvector GENERATED ALWAYS AS ( setweight(to_tsvector('simple', teknav_norm_fa("title")), 'A') || setweight(to_tsvector('simple', teknav_norm_fa(coalesce("subtitle", ''))), 'B') || setweight(to_tsvector('simple', teknav_norm_fa("summary")), 'B') || setweight(to_tsvector('simple', teknav_norm_fa("content")), 'C') ) STORED; -- GIN index for full-text search. CREATE INDEX IF NOT EXISTS "Article_search_tsv_idx" ON "Article" USING GIN ("search_tsv"); -- Trigram index for title autocomplete. CREATE INDEX IF NOT EXISTS "Article_title_trgm_idx" ON "Article" USING GIN ("title" gin_trgm_ops);