-- 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;