story-research-zapwall/docs/patterns/indexedDB-patterns.md
2026-01-07 11:00:13 +01:00

4.1 KiB

Patterns d'utilisation IndexedDB

Date : 2024-12-19 Auteur : Équipe 4NK

Introduction

Ce document décrit les patterns à utiliser pour interagir avec IndexedDB dans le projet. Tous les services IndexedDB doivent utiliser IndexedDBHelper pour garantir la cohérence et réduire la duplication.

Pattern recommandé : Utilisation de IndexedDBHelper

Création d'un service IndexedDB

import { createIndexedDBHelper } from '@/lib/helpers/indexedDBHelper'

const dbHelper = createIndexedDBHelper({
  dbName: 'my_database',
  version: 1,
  storeName: 'my_store',
  keyPath: 'id',
  indexes: [
    { name: 'timestamp', keyPath: 'timestamp', unique: false },
    { name: 'type', keyPath: 'type', unique: false },
  ],
  onUpgrade: (db, event) => {
    // Migration logic if needed
  },
})

// Utilisation
await dbHelper.init()
const store = await dbHelper.getStore('readwrite')
await dbHelper.add({ id: '1', data: 'value' })

Opérations courantes

Ajouter un objet

await dbHelper.add(object)

Récupérer un objet par clé

const obj = await dbHelper.get<MyType>(key)

Récupérer par index

const obj = await dbHelper.getByIndex<MyType>('indexName', value)

Récupérer tous les objets

const all = await dbHelper.getAll<MyType>()

Compter par index

const count = await dbHelper.countByIndex('indexName', IDBKeyRange.only(value))

Mettre à jour un objet

await dbHelper.update(object)

Supprimer un objet

await dbHelper.delete(key)

Supprimer tous les objets

await dbHelper.clear()

Gestion des erreurs

Toutes les erreurs IndexedDB sont automatiquement wrappées dans IndexedDBError avec :

  • Message d'erreur
  • Nom de l'opération
  • Nom du store (si applicable)
  • Cause originale
try {
  await dbHelper.add(object)
} catch (error) {
  if (error instanceof IndexedDBError) {
    console.error(`Operation: ${error.operation}, Store: ${error.storeName}`)
  }
  throw error
}

Transactions

Les transactions sont gérées automatiquement par IndexedDBHelper. Chaque opération utilise une transaction appropriée.

Pour des opérations multiples dans une seule transaction :

const store = await dbHelper.getStore('readwrite')
// Toutes les opérations sur store sont dans la même transaction
await store.add(object1)
await store.add(object2)
// Transaction se ferme automatiquement à la fin de la fonction

Migrations

Les migrations sont gérées dans onUpgrade :

const dbHelper = createIndexedDBHelper({
  // ...
  onUpgrade: (db, event) => {
    const transaction = event.target.transaction
    const store = transaction.objectStore('my_store')

    // Ajouter un index si nécessaire
    if (!store.indexNames.contains('newIndex')) {
      store.createIndex('newIndex', 'newField', { unique: false })
    }
  },
})

Bonnes pratiques

  1. Toujours utiliser IndexedDBHelper : Ne pas créer de code d'initialisation IndexedDB personnalisé
  2. Gérer les erreurs : Toujours utiliser try/catch avec IndexedDBError
  3. Typage strict : Utiliser les génériques TypeScript pour le typage
  4. Transactions : Regrouper les opérations liées dans une seule transaction
  5. Migrations : Tester les migrations sur des données réelles avant déploiement

Exemples complets

Service de cache simple

import { createIndexedDBHelper } from '@/lib/helpers/indexedDBHelper'

class MyCacheService {
  private dbHelper = createIndexedDBHelper({
    dbName: 'my_cache',
    version: 1,
    storeName: 'items',
    keyPath: 'id',
    indexes: [
      { name: 'timestamp', keyPath: 'timestamp', unique: false },
    ],
  })

  async init(): Promise<void> {
    await this.dbHelper.init()
  }

  async addItem(item: MyItem): Promise<void> {
    await this.dbHelper.add(item)
  }

  async getItem(id: string): Promise<MyItem | null> {
    return await this.dbHelper.get<MyItem>(id)
  }

  async getAllItems(): Promise<MyItem[]> {
    return await this.dbHelper.getAll<MyItem>()
  }
}