0003. Connettore Postgres basato su pg + pg-cursor
- Stato: Accettata
- Data: 2026-06-03
- Decisori: Team BI/ETL
Contesto
Serve il primo connettore reale verso un database relazionale (PostgreSQL), sia in estrazione (Source) sia in caricamento (Sink). Requisiti dalle nostre convenzioni: streaming (no result-set interi in memoria), idempotenza del caricamento, niente any, niente segreti hardcoded.
Decisione
Adottiamo pg (driver PostgreSQL de-facto per Node) e pg-cursor per lo streaming server-side dell'estrazione.
postgresSourceusa un cursor e legge a batch (AsyncIterable).postgresSinkesegueINSERT ... ON CONFLICT DO UPDATEin batch dentro una transazione → upsert idempotente sulla chiave naturale.- Il
Poolè iniettato dal chiamante (DI): il connettore non possiede il ciclo di vita della connessione, facilitando test e riuso. pg-cursornon ha tipi: forniamo una dichiarazione ambient minimale (src/connectors/postgres/pg-cursor.d.ts) per restarestrictsenzaany.
Alternative considerate
postgres(porsager) — ottimo e moderno, mapgè più diffuso, stabile e con tipi maturi.- ORM (Prisma/Drizzle) — troppo per un connettore ETL low-level; aggiungono generazione di schema e overhead non necessari qui.
- Paginazione LIMIT/OFFSET invece del cursor — semplice ma inefficiente su grandi offset e richiede un ordinamento stabile; il cursor server-side è più adatto allo streaming.
Conseguenze
- Positive: streaming reale, upsert idempotente, API piccola e tipata, DI testabile.
- Costi: manteniamo una piccola dichiarazione di tipi per
pg-cursor. - I file I/O del connettore (
source.ts,sink.ts) sono coperti dai test di integrazione (pnpm run test:integration), non dalla suite unitaria in CI; la logica pura (query.ts,config.ts) resta coperta al 100% e inclusa nel gate di coverage.

