Getting Started

Quick Start

Tre approcci per iniziare con @pzeta/postgrest - facade PostgRESTClient (semplice), setup manuale con EnhancedPostgRESTRepository (controllo), service pattern con BasePostgrestService (consigliato per progetti strutturati).

Tre approcci

@pzeta/postgrest espone tre punti di ingresso, dal più semplice al più strutturato. Scegli in base alla complessità del progetto:

ApproccioQuando
Opzione 1 — Facade PostgRESTClientPrototipi, app piccole, script
Opzione 2 — EnhancedPostgRESTRepository manualeControllo fine, repository singolo, configurazione custom di HTTP/auth/cache
Opzione 3 — BasePostgrestService (consigliato)Progetti enterprise, DDD, dependency injection

Definiamo prima il tipo di dominio usato negli esempi:

interface User {
  iduser: number
  nome: string
  email: string
  datacreazione: string
}

Opzione 1 — Facade PostgRESTClient

import { PostgRESTClient } from '@pzeta/postgrest'

const client = new PostgRESTClient({
  apiUrl: 'https://api.example.com',
  schema: 'public',
})
await client.init() // obbligatorio prima dell'uso

// Login
await client.login({
  email: 'mario@example.com',
  password: 'password123',
})

// Repository factory: lega tipo + path + chiave primaria
const userRepo = client.repository<User, number>('/users', 'iduser')

// CRUD
const utenti = await userRepo.readAll()
const utente = await userRepo.read(1)
const nuovo = await userRepo.create({
  nome: 'Mario Rossi',
  email: 'mario@example.com',
})
const aggiornato = await userRepo.update(1, { nome: 'Mario R.' })
await userRepo.delete(1)

// Logout
await client.logout()

// Cleanup OBBLIGATORIO (ferma timer cache, previene memory leak)
client.destroy()

Filtering avanzato con FilterCriteria

import type { FilterCriteria } from '@pzeta/postgrest'

const filters: FilterCriteria<User> = {
  nome: { operator: 'ilike', value: '%mario%' },
  iduser: { operator: 'gte', value: 100 },
  sort: { field: 'datacreazione', direction: 'desc' },
  pagination: { limit: 20, offset: 0 },
}

const risultato = await userRepo.readPaginated(filters)
console.log('Records:', risultato.data)
console.log('Totale:', risultato.totalCount)

Operatori supportati: eq, neq, in, gt, lt, gte, lte, like, ilike, is, not, fts, plfts, phfts, cs, cd, sl, sr, nxl, nxr, adj, between.

Configurazione facade

import {
  PostgRESTClient,
  AuthStrategyType,
  CacheStrategyType,
  HttpClientType,
} from '@pzeta/postgrest'

const client = new PostgRESTClient({
  apiUrl: 'https://api.example.com',
  schema: 'api',                            // schema PostgreSQL (default: 'public')
  httpClientType: HttpClientType.FETCH,     // FETCH (default) | AXIOS
  authType: AuthStrategyType.JWT,           // JWT (default) | COOKIE | API_KEY | NONE
  cacheType: CacheStrategyType.INDEXEDDB,   // INDEXEDDB (default, auto-fallback)
  cacheTTL: 3_600_000,                      // 1 ora in ms (default)
  timeout: 10_000,                          // 10 secondi (default)
})

Override per repository

// Repository senza cache (dati sempre freschi) e senza auth
const logRepo = client.repository<LogEntry, string>('/logs', 'idlog', {
  useCache: false,
  isAuthRequired: false,
})

// Repository con schema diverso da quello globale del client
const adminRepo = client.repository<AdminUser, number>('/users', 'iduser', {
  schema: 'admin',
})

Opzione 2 — EnhancedPostgRESTRepository manuale

Salta il facade e costruisci direttamente il repository. Utile per casi mono-tabella o test isolati.

import { EnhancedPostgRESTRepository } from '@pzeta/postgrest'

const userRepo = new EnhancedPostgRESTRepository<User, number>({
  baseUrl: 'https://api.example.com',
  path: '/users',
  keyName: 'iduser',
  isAuthRequired: true,
  useCache: true,
  cacheTTL: 3_600_000,
  useBackgroundRefresh: true,
})

const utenti = await userRepo.readAll({
  email: { operator: 'ilike', value: '%@example.com' },
})

Per scenari multi-repository con auth/cache condivisi, l'EnhancedPostgRESTRepository manuale non condivide il CacheService singleton con un eventuale facade: in quel caso usa il facade.

Opzione 3 — BasePostgrestService (consigliato)

Pattern di adozione canonico nei progetti PZeta. Estendi BasePostgrestService per ogni entità di dominio: la classe figlia incapsula il repository, espone CRUD omogeneo con error messages italiani e può aggiungere metodi business + chiamate RPC.

import { BasePostgrestService, type PostgRESTClient } from '@pzeta/postgrest'

interface Cliente {
  idcliente: number
  ragionesociale: string
  email: string
  codicefiscale: string
}

class ClientiService extends BasePostgrestService<Cliente, number> {
  constructor(client: PostgRESTClient) {
    super(client, '/clienti', 'idcliente', 'Cliente')
  }

  // Metodo di dominio aggiuntivo
  async cercaPerRagioneSociale(ragione: string): Promise<Cliente[]> {
    return this.getAll({
      ragionesociale: { operator: 'ilike', value: `%${ragione}%` },
    })
  }

  // RPC PostgREST tipizzata (stored procedure)
  async aggiornaSaldo(idcliente: number, importo: number): Promise<number> {
    return this.callRpc<number>('/rpc/aggiorna_saldo_cliente', {
      p_idcliente: idcliente,
      p_importo: importo,
    })
  }
}

// Uso
const service = new ClientiService(client)
const elenco = await service.getAll()
const cliente = await service.getById(1) // throw se non trovato
const nuovo = await service.create({ ragionesociale: 'Acme S.r.l.' })
await service.update(1, { email: 'info@acme.it' })
await service.delete(1)
const nuovoSaldo = await service.aggiornaSaldo(1, 150.50)

Vedi la guida completa al Service Pattern per integrazione con Inversify DI, override dei metodi e pattern multi-progetto.

Prossimi passi