-- ========================================================= -- pacientesIndexPage.sql -- Views + índices para a tela PatientsListPage -- ========================================================= -- 0) Extensões úteis create extension if not exists pg_trgm; -- 1) updated_at automático (se você quiser manter updated_at sempre correto) create or replace function public.set_updated_at() returns trigger language plpgsql as $$ begin new.updated_at = now(); return new; end; $$; drop trigger if exists trg_patients_set_updated_at on public.patients; create trigger trg_patients_set_updated_at before update on public.patients for each row execute function public.set_updated_at(); -- ========================================================= -- 2) Views de contagem (usadas em KPIs e telas auxiliares) -- ========================================================= -- 2.1) Grupos com contagem de pacientes create or replace view public.v_patient_groups_with_counts as select g.id, g.name, g.color, coalesce(count(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, g.name, g.color; -- 2.2) Tags com contagem de pacientes create or replace view public.v_tag_patient_counts as select t.id, t.name, t.color, coalesce(count(ppt.patient_id), 0)::int as patients_count from public.patient_tags t left join public.patient_patient_tag ppt on ppt.tag_id = t.id group by t.id, t.name, t.color; -- ========================================================= -- 3) View principal da Index (pacientes + grupos/tags agregados) -- ========================================================= create or replace view public.v_patients_index as select p.*, -- array JSON com os grupos do paciente coalesce(gx.groups, '[]'::jsonb) as groups, -- array JSON com as tags do paciente coalesce(tx.tags, '[]'::jsonb) as tags, -- contagens para UI/KPIs coalesce(gx.groups_count, 0)::int as groups_count, coalesce(tx.tags_count, 0)::int as tags_count from public.patients p left join lateral ( select jsonb_agg( distinct jsonb_build_object( 'id', g.id, 'name', g.name, 'color', g.color ) ) filter (where g.id is not null) as groups, count(distinct g.id) as groups_count from public.patient_group_patient pgp join public.patient_groups g on g.id = pgp.patient_group_id where pgp.patient_id = p.id ) gx on true left join lateral ( select jsonb_agg( distinct jsonb_build_object( 'id', t.id, 'name', t.name, 'color', t.color ) ) filter (where t.id is not null) as tags, count(distinct t.id) as tags_count from public.patient_patient_tag ppt join public.patient_tags t on t.id = ppt.tag_id where ppt.patient_id = p.id ) tx on true; -- ========================================================= -- 4) Índices recomendados (performance real na listagem/filtros) -- ========================================================= -- Patients create index if not exists idx_patients_owner_id on public.patients (owner_id); create index if not exists idx_patients_created_at on public.patients (created_at desc); create index if not exists idx_patients_status on public.patients (status); create index if not exists idx_patients_last_attended_at on public.patients (last_attended_at desc); -- Busca rápida (name/email/phone) create index if not exists idx_patients_name_trgm on public.patients using gin (name gin_trgm_ops); create index if not exists idx_patients_email_trgm on public.patients using gin (email gin_trgm_ops); create index if not exists idx_patients_phone_trgm on public.patients using gin (phone gin_trgm_ops); -- Pivot: grupos create index if not exists idx_pgp_patient_id on public.patient_group_patient (patient_id); create index if not exists idx_pgp_group_id on public.patient_group_patient (patient_group_id); -- Pivot: tags create index if not exists idx_ppt_patient_id on public.patient_patient_tag (patient_id); create index if not exists idx_ppt_tag_id on public.patient_patient_tag (tag_id);