Files
ThothII/harness/scripts/create_vector_reader_rpc.sql
T

119 lines
4.5 KiB
PL/PgSQL

-- RPC reader per pgvector via Supabase/PostgREST (spec D11, §5.4).
-- Eseguire sul database Supabase centrale come owner dello schema `vectors`.
-- Prerequisiti:
-- - schema `vectors` con tabelle schema_records/evidence/memory
-- - colonne: record_key text unique, kind text, content_hash text, metadata jsonb,
-- embedding vector(N), indexed_at timestamptz
-- - ruolo/key PostgREST dedicato `vector_reader` (lettura: search_similar, list_tables)
--
-- A differenza del writer RPC (che era gia' nel repo), i reader RPC vivevano lato server
-- in Supabase e non erano mai stati versionati. Li si riporta qui per completezza del
-- modello dual-key: la key reader riceve solo EXECUTE su queste due funzioni, niente
-- SELECT raw sulle tabelle. Il cleanup/rebuild resta solo-server (vedi writer RPC).
create or replace function public._assert_vector_read_table(table_name text)
returns void
language plpgsql
stable
as $$
begin
if table_name not in ('schema_records', 'evidence', 'memory') then
raise sqlstate 'PGRST' using
message = json_build_object('message', 'Unsupported vector table')::text,
detail = json_build_object('status', 400)::text;
end if;
end;
$$;
create or replace function public.search_similar(
table_name text,
query_embedding vector,
limit_count integer,
kinds text[] default null,
metadata_filter jsonb default null
)
returns table(id bigint, similarity real, metadata jsonb)
language plpgsql
security definer
set search_path = public, vectors, extensions
as $$
begin
perform public._assert_vector_read_table(table_name);
if metadata_filter is not null and (
table_name <> 'evidence'
or not (metadata_filter ? 'vector_generation')
or not (metadata_filter ? 'document_ids')
or jsonb_object_length(metadata_filter) <> 2
or jsonb_typeof(metadata_filter->'document_ids') <> 'array'
) then
raise exception 'invalid Evidence metadata filter';
end if;
return query execute format(
'select t.id,
(1 - (t.embedding <=> $1))::real as similarity,
t.metadata
from vectors.%I t
where ($3 is null or t.kind = any ($3))
and ($4 is null or (
t.metadata->>''vector_generation'' = $4->>''vector_generation''
and t.metadata->>''document_id'' in (
select jsonb_array_elements_text($4->''document_ids'')
)
))
order by t.embedding <=> $1
limit $2',
table_name
) using query_embedding, limit_count, kinds, metadata_filter;
end;
$$;
create or replace function public.list_tables()
returns table(table_name text, vector_dimensions integer, record_count bigint)
language plpgsql
security definer
set search_path = public, vectors, extensions
as $$
begin
return query
select c.relname::text as table_name,
-- dimensione ricavata dalla colonna embedding (vector(N)) se presente
coalesce(
(select (regexp_matches(format_type(a.atttypid, a.atttypmod), 'vector\((\d+)\)'))[1])::int,
0
) as vector_dimensions,
c.reltuples::bigint as record_count
from pg_class c
join pg_namespace n on n.oid = c.relnamespace
left join pg_attribute a on a.attrelid = c.oid and a.attname = 'embedding'
where n.nspname = 'vectors'
and c.relkind in ('r', 'p')
and c.relname in ('schema_records', 'evidence', 'memory')
order by c.relname;
end;
$$;
revoke all on function public._assert_vector_read_table(text) from public;
revoke all on function public.search_similar(text, vector, integer, text[], jsonb) from public;
revoke all on function public.list_tables() from public;
-- Revoca dai ruoli client generici, poi abilita solo il reader dedicato
-- (e il writer, che usa existing_vector_hashes per l'upsert incrementale).
do $$
begin
if exists (select 1 from pg_roles where rolname = 'anon') then
revoke all on function public.search_similar(text, vector, integer, text[], jsonb) from anon;
revoke all on function public.list_tables() from anon;
end if;
if exists (select 1 from pg_roles where rolname = 'authenticated') then
revoke all on function public.search_similar(text, vector, integer, text[], jsonb) from authenticated;
revoke all on function public.list_tables() from authenticated;
end if;
if exists (select 1 from pg_roles where rolname = 'vector_reader') then
grant execute on function public.search_similar(text, vector, integer, text[], jsonb)
to vector_reader;
grant execute on function public.list_tables() to vector_reader;
end if;
end $$;
notify pgrst, 'reload schema';