Cache

IndexedDBStore

Wrapper low-level type-safe sopra IndexedDB con operazioni CRUD asincrone, transazioni gestite e supporto indici secondari. Usato internamente da IndexedDBCacheStrategy.

Cosa fa

IndexedDBStore<T> e un'astrazione low-level type-safe sopra IndexedDB: incapsula apertura DB, transazioni, gestione errori e callback onupgradeneeded dietro un'API Promise-based con generics.

E utilizzata internamente da IndexedDBCacheStrategy — di norma non serve usarla direttamente. Casi d'uso diretti:

  • Persistenza di dati di dominio (non solo cache HTTP)
  • Pattern offline-first con sincronizzazione manuale
  • Store applicativi paralleli alla cache HTTP

Costruttore

class IndexedDBStore<T extends Record<string, unknown>> {
  constructor(
    dbName: string,
    storeName: string,
    config: StoreConfig,
    version?: number
  )
}
ParametroTipoDefaultDescrizione
dbNamestringNome del database IndexedDB
storeNamestringNome dell'object store nel database
configStoreConfigConfigurazione store (keyPath, indici)
versionnumber1Versione DB. Incrementare per migrazioni schema

StoreConfig

interface StoreConfig {
  keyPath: string
  autoIncrement?: boolean
  indexes?: Array<{
    name: string
    keyPath: string | string[]
    options?: { unique?: boolean; multiEntry?: boolean }
  }>
}

API CRUD

MetodoDescrizione
add(item)Inserisce. Throw se la chiave esiste gia. Ritorna la chiave generata
addOrUpdate(item)Upsert. Inserisce se assente, aggiorna se presente (per primary key)
get(key)Recupera per chiave primaria. Ritorna undefined se assente
getAll()Recupera tutti i record. Costoso su store grandi
update(key, partial)Merge parziale con il record esistente
delete(key)Rimuove per chiave primaria. Non throw se assente
getByIndex(name, key)Recupera tramite indice secondario

Tutte le operazioni:

  • Sono async (Promise)
  • Aprono il DB automaticamente al primo uso (initDB() interno)
  • Gestiscono la transazione (readonly per le letture, readwrite per scritture)
  • Throw Error con messaggio derivato da request.error?.message

Esempio

import { IndexedDBStore } from '@pzeta/postgrest'

interface User extends Record<string, unknown> {
  userId?: number
  email: string
  name: string
  createdAt: number
}

const userStore = new IndexedDBStore<User>('myApp', 'users', {
  keyPath: 'userId',
  autoIncrement: true,
  indexes: [
    { name: 'email', keyPath: 'email', options: { unique: true } },
    { name: 'createdAt', keyPath: 'createdAt' },
  ],
})

// Inserimento
const key = await userStore.add({
  email: 'mario@example.com',
  name: 'Mario',
  createdAt: Date.now(),
})

// Lookup per indice secondario
const user = await userStore.getByIndex('email', 'mario@example.com')

// Update parziale
await userStore.update(1, { name: 'Mario Rossi' })

Migrazioni schema

Per modificare lo schema (aggiungere indici, store), incrementare version. Il callback onupgradeneeded viene rieseguito.

Lo store viene creato solo se non esiste (!db.objectStoreNames.contains(storeName)). Modifiche a indici di uno store esistente richiedono logica di migrazione custom: questa classe non gestisce migrazioni complesse.

Quando NON usarla

  • Per cache HTTP: usa IndexedDBCacheStrategy tramite CacheService
  • Per dati strutturati complessi con query relazionali: valuta soluzioni dedicate (Dexie, idb)
  • Quando IndexedDB non e disponibile (vecchi browser, SSR): usa MemoryCacheStrategy

Vedi anche