425c8611f7
- Agrega fn_log_cambios_planes_estudio y trigger para registrar cambios en cambios_plan, usando response_id (reemplaza interaccion_ia_id). - Extiende planes_estudio con conversation_id (unique) y plan_hash; agrega asignatura_hash en asignaturas; corrige unaccent_immutable y añade extensión http. - Actualiza seeds/backups (data_backup.sql / scheme_backup.sql) y ajusta script de diff (sql_para_local_como_remoto.sql), elimina el diff viejo y actualiza archivos auxiliares (deno.lock, CLI temp).
206 lines
8.2 KiB
PL/PgSQL
206 lines
8.2 KiB
PL/PgSQL
create extension if not exists "http" with schema "extensions";
|
|
|
|
alter table "public"."asignaturas" drop constraint "asignaturas_facultad_propietaria_id_fkey";
|
|
|
|
alter table "public"."cambios_plan" drop constraint "cambios_plan_plan_estudio_id_fkey";
|
|
|
|
alter type "public"."tipo_cambio" rename to "tipo_cambio__old_version_to_be_dropped";
|
|
|
|
create type "public"."tipo_cambio" as enum ('ACTUALIZACION_CAMPO', 'ACTUALIZACION_MAPA', 'TRANSICION_ESTADO', 'OTRO', 'CREACION', 'ACTUALIZACION');
|
|
|
|
alter table "public"."cambios_asignatura" alter column tipo type "public"."tipo_cambio" using tipo::text::"public"."tipo_cambio";
|
|
|
|
alter table "public"."cambios_plan" alter column tipo type "public"."tipo_cambio" using tipo::text::"public"."tipo_cambio";
|
|
|
|
drop type "public"."tipo_cambio__old_version_to_be_dropped";
|
|
|
|
alter table "public"."asignaturas" drop column "facultad_propietaria_id";
|
|
|
|
alter table "public"."asignaturas" add column "asignatura_hash" text generated always as (encode(SUBSTRING(extensions.digest((id)::text, 'sha512'::text) FROM 1 FOR 12), 'hex'::text)) stored;
|
|
|
|
alter table "public"."cambios_plan" drop column "interaccion_ia_id";
|
|
|
|
alter table "public"."cambios_plan" add column "response_id" text;
|
|
|
|
alter table "public"."planes_estudio" add column "conversation_id" text;
|
|
|
|
alter table "public"."planes_estudio" add column "plan_hash" text generated always as (encode(SUBSTRING(extensions.digest((id)::text, 'sha512'::text) FROM 1 FOR 12), 'hex'::text)) stored;
|
|
|
|
CREATE UNIQUE INDEX planes_estudio_conversation_id_key ON public.planes_estudio USING btree (conversation_id);
|
|
|
|
alter table "public"."planes_estudio" add constraint "planes_estudio_conversation_id_key" UNIQUE using index "planes_estudio_conversation_id_key";
|
|
|
|
set check_function_bodies = off;
|
|
|
|
CREATE OR REPLACE FUNCTION public.fn_log_cambios_planes_estudio()
|
|
RETURNS trigger
|
|
LANGUAGE plpgsql
|
|
AS $function$declare
|
|
k text;
|
|
old_val jsonb;
|
|
new_val jsonb;
|
|
|
|
v_response_id text;
|
|
begin
|
|
v_response_id := nullif(new.meta_origen->>'response_id','');
|
|
|
|
-- INSERT -> CREACION
|
|
if tg_op = 'INSERT' then
|
|
insert into public.cambios_plan (
|
|
plan_estudio_id,
|
|
cambiado_por,
|
|
tipo,
|
|
campo,
|
|
valor_anterior,
|
|
valor_nuevo,
|
|
response_id
|
|
)
|
|
values (
|
|
new.id,
|
|
new.creado_por,
|
|
'CREACION'::public.tipo_cambio,
|
|
null,
|
|
null,
|
|
to_jsonb(new),
|
|
null
|
|
);
|
|
|
|
return new;
|
|
end if;
|
|
|
|
-- DELETE (opcional): si no lo quieres, bórralo
|
|
if tg_op = 'DELETE' then
|
|
insert into public.cambios_plan (
|
|
plan_estudio_id,
|
|
cambiado_por,
|
|
tipo,
|
|
campo,
|
|
valor_anterior,
|
|
valor_nuevo,
|
|
response_id
|
|
)
|
|
values (
|
|
old.id,
|
|
old.actualizado_por,
|
|
'OTRO'::public.tipo_cambio,
|
|
'DELETE',
|
|
to_jsonb(old),
|
|
null,
|
|
null
|
|
);
|
|
|
|
return old;
|
|
end if;
|
|
|
|
-- UPDATE ----------------------------------------------------------
|
|
-- 1) Transición de estado
|
|
if (new.estado_actual_id is distinct from old.estado_actual_id) then
|
|
insert into public.cambios_plan (
|
|
plan_estudio_id, cambiado_por, tipo, campo, valor_anterior, valor_nuevo, response_id
|
|
)
|
|
values (
|
|
new.id,
|
|
new.actualizado_por,
|
|
'TRANSICION_ESTADO'::public.tipo_cambio,
|
|
'estado_actual_id',
|
|
to_jsonb(old.estado_actual_id),
|
|
to_jsonb(new.estado_actual_id),
|
|
null
|
|
);
|
|
end if;
|
|
|
|
-- 2) Cambios en JSONB "datos" (diff top-level por llave)
|
|
if (new.datos is distinct from old.datos) then
|
|
for k in
|
|
select distinct key
|
|
from (
|
|
select jsonb_object_keys(coalesce(old.datos, '{}'::jsonb)) as key
|
|
union all
|
|
select jsonb_object_keys(coalesce(new.datos, '{}'::jsonb)) as key
|
|
) t
|
|
loop
|
|
old_val := coalesce(old.datos, '{}'::jsonb) -> k;
|
|
new_val := coalesce(new.datos, '{}'::jsonb) -> k;
|
|
|
|
if (old_val is distinct from new_val) then
|
|
insert into public.cambios_plan (
|
|
plan_estudio_id, cambiado_por, tipo, campo, valor_anterior, valor_nuevo, response_id
|
|
)
|
|
values (
|
|
new.id,
|
|
new.actualizado_por,
|
|
'ACTUALIZACION_CAMPO'::public.tipo_cambio,
|
|
k,
|
|
old_val,
|
|
new_val,
|
|
v_response_id
|
|
);
|
|
end if;
|
|
end loop;
|
|
|
|
end if;
|
|
|
|
-- 3) Cambios en columnas "normales" (uno por columna)
|
|
if (new.nombre is distinct from old.nombre) then
|
|
insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(),
|
|
'ACTUALIZACION'::public.tipo_cambio, 'nombre', to_jsonb(old.nombre), to_jsonb(new.nombre), null);
|
|
end if;
|
|
|
|
if (new.nivel is distinct from old.nivel) then
|
|
insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(),
|
|
'ACTUALIZACION'::public.tipo_cambio, 'nivel', to_jsonb(old.nivel), to_jsonb(new.nivel), null);
|
|
end if;
|
|
|
|
if (new.tipo_ciclo is distinct from old.tipo_ciclo) then
|
|
insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(),
|
|
'ACTUALIZACION'::public.tipo_cambio, 'tipo_ciclo', to_jsonb(old.tipo_ciclo), to_jsonb(new.tipo_ciclo), null);
|
|
end if;
|
|
|
|
if (new.numero_ciclos is distinct from old.numero_ciclos) then
|
|
insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(),
|
|
'ACTUALIZACION'::public.tipo_cambio, 'numero_ciclos', to_jsonb(old.numero_ciclos), to_jsonb(new.numero_ciclos), null);
|
|
end if;
|
|
|
|
if (new.activo is distinct from old.activo) then
|
|
insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(),
|
|
'ACTUALIZACION'::public.tipo_cambio, 'activo', to_jsonb(old.activo), to_jsonb(new.activo), null);
|
|
end if;
|
|
|
|
if (new.carrera_id is distinct from old.carrera_id) then
|
|
insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(),
|
|
'ACTUALIZACION'::public.tipo_cambio, 'carrera_id', to_jsonb(old.carrera_id), to_jsonb(new.carrera_id), null);
|
|
end if;
|
|
|
|
if (new.estructura_id is distinct from old.estructura_id) then
|
|
insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(),
|
|
'ACTUALIZACION'::public.tipo_cambio, 'estructura_id', to_jsonb(old.estructura_id), to_jsonb(new.estructura_id), null);
|
|
end if;
|
|
|
|
if (new.tipo_origen is distinct from old.tipo_origen) then
|
|
insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(),
|
|
'ACTUALIZACION'::public.tipo_cambio, 'tipo_origen', to_jsonb(old.tipo_origen), to_jsonb(new.tipo_origen), null);
|
|
end if;
|
|
|
|
|
|
if (new.conversation_id is distinct from old.conversation_id) then
|
|
insert into public.cambios_plan values (gen_random_uuid(), new.id, new.actualizado_por, now(),
|
|
'ACTUALIZACION'::public.tipo_cambio, 'conversation_id', to_jsonb(old.conversation_id), to_jsonb(new.conversation_id), null);
|
|
end if;
|
|
|
|
-- 🔥 consumirlo para que NO se guarde en planes_estudio
|
|
if v_response_id is not null then
|
|
new.meta_origen := new.meta_origen - 'response_id';
|
|
end if;
|
|
|
|
return new;
|
|
end;$function$
|
|
;
|
|
|
|
CREATE TRIGGER "agregar-conversation_id-asignaturas" AFTER INSERT ON public.asignaturas FOR EACH ROW EXECUTE FUNCTION supabase_functions.http_request('https://exdkssurzmjnnhgtiama.supabase.co/functions/v1/create-chat-conversation', 'POST', '{"Content-type":"application/json","Authorization":"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImV4ZGtzc3Vyem1qbm5oZ3RpYW1hIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTc0MTM3ODYzMiwiZXhwIjoyMDU2OTU0NjMyfQ.s-GHuwnYbIYoMZN9dFbAKgxNyAtQllRCRPLy-GIRaro"}', '{}', '5000');
|
|
|
|
CREATE TRIGGER "agregar-conversation_id-planes_estudio" AFTER INSERT ON public.planes_estudio FOR EACH ROW EXECUTE FUNCTION supabase_functions.http_request('https://exdkssurzmjnnhgtiama.supabase.co/functions/v1/create-chat-conversation', 'POST', '{"Content-type":"application/json","Authorization":"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImV4ZGtzc3Vyem1qbm5oZ3RpYW1hIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTc0MTM3ODYzMiwiZXhwIjoyMDU2OTU0NjMyfQ.s-GHuwnYbIYoMZN9dFbAKgxNyAtQllRCRPLy-GIRaro"}', '{}', '5000');
|
|
|
|
CREATE TRIGGER trg_planes_estudio_log_cambios AFTER INSERT OR DELETE OR UPDATE ON public.planes_estudio FOR EACH ROW EXECUTE FUNCTION public.fn_log_cambios_planes_estudio();
|
|
|
|
|