Full text search sobre asignaturas para clonación de asignaturas

This commit is contained in:
2026-03-24 20:46:35 -06:00
parent 77a5b3ad06
commit 220b830aa8
@@ -0,0 +1,167 @@
-- Paso 1
drop text search configuration if exists public.es_simple_unaccent cascade;
create text search configuration public.es_simple_unaccent (copy = pg_catalog.simple);
alter text search configuration public.es_simple_unaccent
alter mapping for hword, hword_part, word
with unaccent, simple;
-- Paso 2
alter table public.asignaturas
add column if not exists search_vector tsvector;
-- Paso 3
create or replace function public.fn_asignaturas_update_search_vector()
returns trigger
language plpgsql
as $$
begin
new.search_vector :=
setweight(
to_tsvector('public.es_simple_unaccent', coalesce(new.nombre, '')),
'A'
)
||
setweight(
to_tsvector('public.es_simple_unaccent', coalesce(new.codigo, '')),
'A'
)
||
setweight(
to_tsvector('public.es_simple_unaccent', coalesce(new.datos, '{}'::jsonb)::text),
'B'
)
||
setweight(
to_tsvector('public.es_simple_unaccent', coalesce(new.contenido_tematico, '[]'::jsonb)::text),
'B'
);
return new;
end;
$$;
-- Paso 4
drop trigger if exists trg_asignaturas_search_vector on public.asignaturas;
create trigger trg_asignaturas_search_vector
before insert or update of nombre, codigo, datos, contenido_tematico
on public.asignaturas
for each row
execute function public.fn_asignaturas_update_search_vector();
-- Paso 5
update public.asignaturas
set search_vector =
setweight(
to_tsvector('public.es_simple_unaccent', coalesce(nombre, '')),
'A'
)
||
setweight(
to_tsvector('public.es_simple_unaccent', coalesce(codigo, '')),
'A'
)
||
setweight(
to_tsvector('public.es_simple_unaccent', coalesce(datos, '{}'::jsonb)::text),
'B'
)
||
setweight(
to_tsvector('public.es_simple_unaccent', coalesce(contenido_tematico, '[]'::jsonb)::text),
'B'
);
-- Paso 6
create index if not exists asignaturas_search_vector_gin_idx
on public.asignaturas
using gin (search_vector);
-- Paso 7
create or replace function public.build_asignaturas_prefix_tsquery(p_search text)
returns tsquery
language plpgsql
stable
as $$
declare
cleaned text;
tokens text[];
query_text text;
begin
cleaned := trim(coalesce(p_search, ''));
if cleaned = '' then
return null;
end if;
cleaned := lower(public.unaccent(cleaned));
cleaned := regexp_replace(cleaned, '[^[:alnum:]\s]+', ' ', 'g');
cleaned := regexp_replace(cleaned, '\s+', ' ', 'g');
tokens := regexp_split_to_array(cleaned, '\s+');
select string_agg(token || ':*', ' & ')
into query_text
from unnest(tokens) as token
where token <> '';
if query_text is null or query_text = '' then
return null;
end if;
return to_tsquery('public.es_simple_unaccent', query_text);
end;
$$;
-- Paso 8
create or replace function public.search_asignaturas(
p_search text,
p_plan_estudio_id uuid default null,
p_limit integer default 20,
p_offset integer default 0
)
returns table (
id uuid,
plan_estudio_id uuid,
codigo text,
nombre text,
tipo public.tipo_asignatura,
creditos numeric,
numero_ciclo integer,
datos jsonb,
contenido_tematico jsonb,
estado public.estado_asignatura,
rank real
)
language sql
stable
as $$
with q as (
select public.build_asignaturas_prefix_tsquery(p_search) as tsq
)
select
a.id,
a.plan_estudio_id,
a.codigo,
a.nombre,
a.tipo,
a.creditos,
a.numero_ciclo,
a.datos,
a.contenido_tematico,
a.estado,
ts_rank(a.search_vector, q.tsq) as rank
from public.asignaturas a
cross join q
where
q.tsq is not null
and a.search_vector @@ q.tsq
and (p_plan_estudio_id is null or a.plan_estudio_id = p_plan_estudio_id)
order by
rank desc,
a.nombre asc
limit p_limit
offset p_offset;
$$;