Files
MineGeo/supabase/migrations/20261004075155_transactional_processing.sql

36 lines
3.2 KiB
PL/PgSQL

-- Queue transitions commit together, so a restarted worker cannot strand a draft.
create function public.finalize_upload(p_dataset uuid,p_owner uuid) returns text language plpgsql security invoker set search_path='' as $$
declare d public.datasets; begin
select * into d from public.datasets where id=p_dataset and owner_id=p_owner for update;
if not found then raise exception 'Dataset not found'; end if;
if d.state in ('processing','draft','review','published') then return d.state; end if;
if d.state<>'uploading' then raise exception 'Dataset cannot be finalized'; end if;
insert into public.upload_jobs(dataset_id) values(p_dataset) on conflict(dataset_id) do nothing;
update public.datasets set state='processing',updated_at=now() where id=p_dataset;
return 'processing'; end; $$;
create function public.complete_job(p_job uuid,p_worker text,p_count integer,p_cover text) returns void language plpgsql security invoker set search_path='' as $$
declare j public.upload_jobs; begin
select * into j from public.upload_jobs where id=p_job and lease_owner=p_worker and state='running' and lease_until>now() for update;
if not found then raise exception 'Worker lease lost'; end if;
if p_count<5 then raise exception 'Five locations required'; end if;
update public.datasets set state='draft',panorama_count=p_count,map_path=j.dataset_id::text||'/map.webp',cover_path=j.dataset_id::text||'/'||p_cover||'/preview.webp',updated_at=now() where id=j.dataset_id and state='processing';
if not found then raise exception 'Dataset processing cancelled'; end if;
update public.dataset_inputs set validated=true where dataset_id=j.dataset_id;
update public.upload_jobs set state='complete',progress=100,lease_until=null,error=null,updated_at=now() where id=p_job;
end; $$;
create function public.approve_pairing(p_code text,p_owner uuid,p_token text,p_hash text) returns void language plpgsql security invoker set search_path='' as $$
begin
update public.pairing_codes set owner_id=p_owner,token_value=p_token where user_code=p_code and owner_id is null and expires_at>now();
if not found then raise exception 'Pairing code expired or already approved'; end if;
insert into public.contributor_tokens(owner_id,token_hash,label) values(p_owner,p_hash,'Fabric capture client');
end; $$;
create function public.prevent_revision_mutation() returns trigger language plpgsql security invoker set search_path='' as $$
begin raise exception 'Published revisions are immutable'; end; $$;
create trigger revisions_immutable before update or delete on public.revisions for each row execute function public.prevent_revision_mutation();
create index game_sessions_owner_created on public.game_sessions(owner_id,created_at desc);
create index datasets_owner_created on public.datasets(owner_id,created_at desc);
create index datasets_catalog on public.datasets(state,server_id);
create index reports_open on public.reports(state,created_at);
revoke execute on function public.finalize_upload(uuid,uuid),public.complete_job(uuid,text,integer,text),public.approve_pairing(text,uuid,text,text),public.prevent_revision_mutation() from public,anon,authenticated;
grant execute on function public.finalize_upload(uuid,uuid),public.complete_job(uuid,text,integer,text),public.approve_pairing(text,uuid,text,text) to service_role;