175 lines
5.7 KiB
PL/PgSQL
175 lines
5.7 KiB
PL/PgSQL
/*
|
|
patient_groups_setup.sql
|
|
Setup completo para:
|
|
- public.patient_groups
|
|
- public.patient_group_patient (tabela ponte)
|
|
- view public.v_patient_groups_with_counts
|
|
- índice único por owner + nome (case-insensitive)
|
|
- 3 grupos padrão do sistema (Crianças, Adolescentes, Idosos) NÃO editáveis / NÃO removíveis
|
|
- triggers de proteção
|
|
|
|
Observação (importante):
|
|
- Os grupos padrão são criados com owner_id = '00000000-0000-0000-0000-000000000000' (SYSTEM_OWNER),
|
|
para ficarem "globais" e não dependerem de auth.uid() em migrations.
|
|
- Se você quiser que os grupos padrão pertençam a um owner específico (tenant),
|
|
basta trocar o SYSTEM_OWNER abaixo por esse UUID.
|
|
*/
|
|
|
|
begin;
|
|
|
|
-- ===========================
|
|
-- 0) Constante de "dono do sistema"
|
|
-- ===========================
|
|
-- Troque aqui se você quiser que os grupos padrão pertençam a um owner específico.
|
|
-- Ex.: '816b24fe-a0c3-4409-b79b-c6c0a6935d03'
|
|
do $$
|
|
begin
|
|
-- só para documentar; não cria nada
|
|
end $$;
|
|
|
|
-- ===========================
|
|
-- 1) Tabela principal: patient_groups
|
|
-- ===========================
|
|
create table if not exists public.patient_groups (
|
|
id uuid primary key default gen_random_uuid(),
|
|
name text not null,
|
|
description text,
|
|
color text,
|
|
is_active boolean not null default true,
|
|
is_system boolean not null default false,
|
|
owner_id uuid not null,
|
|
created_at timestamptz not null default now(),
|
|
updated_at timestamptz not null default now()
|
|
);
|
|
|
|
-- (Opcional, mas recomendado) Garante que name não seja só espaços
|
|
-- e evita nomes vazios.
|
|
alter table public.patient_groups
|
|
drop constraint if exists patient_groups_name_not_blank_check;
|
|
|
|
alter table public.patient_groups
|
|
add constraint patient_groups_name_not_blank_check
|
|
check (length(btrim(name)) > 0);
|
|
|
|
-- ===========================
|
|
-- 2) Tabela ponte: patient_group_patient
|
|
-- ===========================
|
|
-- Se você já tiver essa tabela com FKs, ajuste aqui conforme seu schema.
|
|
create table if not exists public.patient_group_patient (
|
|
patient_group_id uuid not null references public.patient_groups(id) on delete cascade,
|
|
patient_id uuid not null references public.patients(id) on delete cascade,
|
|
created_at timestamptz not null default now()
|
|
);
|
|
|
|
-- Evita duplicar vínculo paciente<->grupo
|
|
create unique index if not exists patient_group_patient_unique
|
|
on public.patient_group_patient (patient_group_id, patient_id);
|
|
|
|
-- ===========================
|
|
-- 3) View com contagem
|
|
-- ===========================
|
|
create or replace view public.v_patient_groups_with_counts as
|
|
select
|
|
g.*,
|
|
coalesce(count(distinct pgp.patient_id), 0)::int as patients_count
|
|
from public.patient_groups g
|
|
left join public.patient_group_patient pgp
|
|
on pgp.patient_group_id = g.id
|
|
group by g.id;
|
|
|
|
-- ===========================
|
|
-- 4) Índice único: não permitir mesmo nome por owner (case-insensitive)
|
|
-- ===========================
|
|
-- Atenção: se já existirem duplicados, este índice pode falhar ao criar.
|
|
create unique index if not exists patient_groups_owner_name_unique
|
|
on public.patient_groups (owner_id, (lower(name)));
|
|
|
|
-- ===========================
|
|
-- 5) Triggers de proteção: system não edita / não remove
|
|
-- ===========================
|
|
create or replace function public.prevent_system_group_changes()
|
|
returns trigger
|
|
language plpgsql
|
|
as $$
|
|
begin
|
|
if old.is_system = true then
|
|
raise exception 'Grupos padrão do sistema não podem ser alterados ou excluídos.';
|
|
end if;
|
|
|
|
if tg_op = 'DELETE' then
|
|
return old;
|
|
end if;
|
|
|
|
return new;
|
|
end;
|
|
$$;
|
|
|
|
drop trigger if exists trg_prevent_system_group_changes on public.patient_groups;
|
|
|
|
create trigger trg_prevent_system_group_changes
|
|
before update or delete on public.patient_groups
|
|
for each row
|
|
execute function public.prevent_system_group_changes();
|
|
|
|
-- Impede "promover" um grupo comum para system
|
|
create or replace function public.prevent_promoting_to_system()
|
|
returns trigger
|
|
language plpgsql
|
|
as $$
|
|
begin
|
|
if new.is_system = true and old.is_system is distinct from true then
|
|
raise exception 'Não é permitido transformar um grupo comum em grupo do sistema.';
|
|
end if;
|
|
return new;
|
|
end;
|
|
$$;
|
|
|
|
drop trigger if exists trg_prevent_promoting_to_system on public.patient_groups;
|
|
|
|
create trigger trg_prevent_promoting_to_system
|
|
before update on public.patient_groups
|
|
for each row
|
|
execute function public.prevent_promoting_to_system();
|
|
|
|
-- ===========================
|
|
-- 6) Inserir 3 grupos padrão (imutáveis)
|
|
-- ===========================
|
|
-- Dono "global" do sistema (mude se quiser):
|
|
-- 00000000-0000-0000-0000-000000000000
|
|
with sys_owner as (
|
|
select '00000000-0000-0000-0000-000000000000'::uuid as owner_id
|
|
)
|
|
insert into public.patient_groups (name, description, color, is_active, is_system, owner_id)
|
|
select v.name, v.description, v.color, v.is_active, v.is_system, s.owner_id
|
|
from sys_owner s
|
|
join (values
|
|
('Crianças', 'Grupo padrão do sistema', null, true, true),
|
|
('Adolescentes', 'Grupo padrão do sistema', null, true, true),
|
|
('Idosos', 'Grupo padrão do sistema', null, true, true)
|
|
) as v(name, description, color, is_active, is_system)
|
|
on true
|
|
where not exists (
|
|
select 1
|
|
from public.patient_groups g
|
|
where g.owner_id = s.owner_id
|
|
and lower(g.name) = lower(v.name)
|
|
);
|
|
|
|
commit;
|
|
|
|
/*
|
|
Testes rápidos:
|
|
1) Ver tudo:
|
|
select * from public.v_patient_groups_with_counts order by is_system desc, name;
|
|
|
|
2) Tentar editar um system (deve falhar):
|
|
update public.patient_groups set name='X' where name='Crianças';
|
|
|
|
3) Tentar deletar um system (deve falhar):
|
|
delete from public.patient_groups where name='Crianças';
|
|
|
|
4) Tentar duplicar nome no mesmo owner (deve falhar por índice único):
|
|
insert into public.patient_groups (name, is_active, is_system, owner_id)
|
|
values ('teste22', true, false, '816b24fe-a0c3-4409-b79b-c6c0a6935d03');
|
|
*/
|