caterium-app/ops/sql/SUPABASE-V17.7.3-CLIENTS-SERVER-READ.sql
pavlov346346-source 4aa66d0a56
Caterium v17.7.3 — clients server read
Server-preferred normalized client profiles with legacy fallback, canonical snapshot RPC, preserved order metrics, release metadata and tests.
2026-09-09 12:07:37 +03:00

59 lines
2.7 KiB
PL/PgSQL

-- Caterium v17.7.3 — canonical client server-read snapshot
-- Read-only/additive migration. Existing p:/n:/o: rows are preserved.
create or replace function public.sun_v17_clients_snapshot_v1773(p_workspace uuid)
returns table(
client_key text,
name text,
phone text,
latest_address text,
data jsonb,
version bigint,
updated_at timestamptz,
source_keys text[],
source_count bigint,
canonical_row_present boolean
)
language plpgsql
security definer
set search_path = public
as $function$
begin
if public.sun_member_role(p_workspace) is null then
raise exception 'Access denied';
end if;
if not public.sun_workspace_has_feature(p_workspace,'clients') then
raise exception 'Клиенты недоступны';
end if;
return query
with prepared as (
select c.*,
regexp_replace(coalesce(nullif(trim(c.phone),''),nullif(trim(c.data#>>'{identity,phone}'),''),nullif(trim(c.data->>'phone'),''),''),'[^0-9]','','g') as phone_digits,
lower(regexp_replace(coalesce(nullif(trim(c.name),''),nullif(trim(c.data#>>'{identity,name}'),''),nullif(trim(c.data->>'name'),''),''),'[[:space:]]+',' ','g')) as name_norm
from public.sun_v17_clients c
where c.workspace_id=p_workspace
), canonical as (
select p.*,case when p.phone_digits<>'' then 'p:'||p.phone_digits when p.name_norm<>'' then 'n:'||p.name_norm else p.client_key end as canonical_key
from prepared p
), ranked as (
select c.*,row_number() over(partition by c.canonical_key order by (c.client_key=c.canonical_key) desc,c.updated_at desc,c.version desc,c.client_key) as rn
from canonical c
), grouped as (
select c.canonical_key,array_agg(c.client_key order by (c.client_key=c.canonical_key) desc,c.updated_at desc,c.client_key) as source_keys,count(*)::bigint as source_count,bool_or(c.client_key=c.canonical_key) as canonical_row_present
from canonical c group by c.canonical_key
)
select r.canonical_key,
coalesce(nullif(trim(r.name),''),nullif(trim(r.data#>>'{identity,name}'),''),nullif(trim(r.data->>'name'),'')),
coalesce(nullif(trim(r.phone),''),nullif(trim(r.data#>>'{identity,phone}'),''),nullif(trim(r.data->>'phone'),'')),
coalesce(nullif(trim(r.latest_address),''),nullif(trim(r.data#>>'{identity,latestAddress}'),''),nullif(trim(r.data->>'latestAddress'),'')),
coalesce(r.data,'{}'::jsonb),r.version,r.updated_at,g.source_keys,g.source_count,g.canonical_row_present
from ranked r join grouped g on g.canonical_key=r.canonical_key
where r.rn=1
order by r.updated_at desc,r.canonical_key;
end;
$function$;
revoke execute on function public.sun_v17_clients_snapshot_v1773(uuid) from public, anon;
grant execute on function public.sun_v17_clients_snapshot_v1773(uuid) to authenticated, service_role;