File size: 2,240 Bytes
28a08e7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
-- backend/migrations/p37_vfs_optimistic_lock.sql
-- GAP-VFS: aggiunge colonna version + trigger auto-bump a vfs_files.
--
-- OPZIONALE β€” il codice Python usa updated_at come token ottimistico
-- anche senza questa migration (backward compatible).
-- Eseguire nel SQL Editor di Supabase per abilitare il contatore version
-- esplicito (integer monotono, immune a clock skew).
--
-- Idempotente: safe da eseguire piΓΉ volte.
-- Prerequisito: tabella vfs_files esistente (vedi 20260601_vfs_and_semantic.sql).

-- ── Step 1: colonna version ───────────────────────────────────────────────────
-- DEFAULT 0 per righe esistenti. Il trigger la incrementerΓ  ad ogni UPDATE.
ALTER TABLE public.vfs_files
  ADD COLUMN IF NOT EXISTS version BIGINT NOT NULL DEFAULT 0;

-- ── Step 2: funzione trigger (CREATE OR REPLACE = idempotente) ────────────────
CREATE OR REPLACE FUNCTION public._vfs_bump_version()
RETURNS TRIGGER LANGUAGE plpgsql AS $$
BEGIN
  -- Incremento atomico server-side: Python non deve leggere la versione corrente
  NEW.version = OLD.version + 1;
  RETURN NEW;
END;
$$;

-- ── Step 3: trigger BEFORE UPDATE (DROP IF EXISTS + CREATE = idempotente) ────
DROP TRIGGER IF EXISTS trg_vfs_version ON public.vfs_files;
CREATE TRIGGER trg_vfs_version
  BEFORE UPDATE ON public.vfs_files
  FOR EACH ROW
  EXECUTE FUNCTION public._vfs_bump_version();

-- ── Step 4: index per conflict detection rapido ───────────────────────────────
CREATE INDEX IF NOT EXISTS vfs_files_version_idx
  ON public.vfs_files (id, version);

-- ── Note operative ────────────────────────────────────────────────────────────
-- Dopo questa migration, PUT /api/files/{id} accetta anche:
--   body: { ..., "expected_version": <N> }
-- Se version corrente != N β†’ HTTP 409 { error: "conflict", current_version, current_updated_at }
-- Il campo expected_updated_at (BIGINT ms) funziona allo stesso modo senza migration.