Référence de l'API

PersistQoraClient

Sous-classe de QoraClient qui persiste les résultats des requêtes dans un StorageAdapter et les restaure au démarrage via hydrate().

PersistQoraClient étend QoraClient. Toutes les méthodes du client de base fonctionnent sans modification. Cette page documente l'API de persistance supplémentaire.

Voir le guide de persistance pour un walkthrough avec des exemples complets.


PersistQoraClient

Constructeur

PersistQoraClient({
  required StorageAdapter storage,
  Duration persistDuration = const Duration(days: 7),
  QoraClientConfig? config,
  QoraTracker? tracker,
})
ParamètreDescription
storageLe backend de stockage. Doit être initialisé via StorageAdapter.init() avant d'appeler hydrate().
persistDurationTTL par défaut pour les entrées persistées. Si null, les entrées sont persistées indéfiniment. Passer Duration.zero pour désactiver la persistance (expire immédiatement).
configTransmis à QoraClient.
trackerTransmis à QoraClient.
main.dart
final client = PersistQoraClient(
  storage: InMemoryStorageAdapter(),
  persistDuration: const Duration(days: 7),
  config: const QoraClientConfig(
    defaultOptions: QoraOptions(staleTime: Duration(minutes: 5)),
    debugMode: true,
  ),
);

registerSerializer

void registerSerializer<T>(
  QoraSerializer<T> serializer, {
  String? name,
})

Enregistre un QoraSerializer pour le type T.

ParamètreDescription
serializerFournit les convertisseurs toJson/fromJson pour T.
nameL'identifiant chaîne stable stocké comme discriminant de type sur disque. Par défaut T.toString(). Passer une valeur explicite sur Flutter Web ou quand --obfuscate est actif.
  • Appeler registerSerializer deux fois pour le même T ou le même name remplace l'entrée précédente.
  • Doit être appelé avant hydrate().
main.dart
client.registerSerializer<User>(
  QoraSerializer(toJson: (u) => u.toJson(), fromJson: User.fromJson),
  name: 'User',
);

client.registerSerializer<List<Post>>(
  QoraSerializer(
    toJson: (posts) => posts.map((p) => p.toJson()).toList(),
    fromJson: (json)  => (json as List).map((e) => Post.fromJson(e)).toList(),
  ),
  name: 'List<Post>',
);

hydrate

Future<void> hydrate()

Charge toutes les entrées persistées valides depuis StorageAdapter dans une file d'hydratation en attente.

Les entrées sont injectées dans le cache typé paresseusement : au premier appel à fetchQuery<T>, watchQuery<T>, getQueryData<T>, etc., pour cette clé. L'état Success restauré porte le persistedAt original comme updatedAt, de sorte que staleTime évalue correctement la fraîcheur.

Comportement par entrée :

ConditionAction
Échec de décodage JSONSupprimer du stockage, ignorer
TTL expiréSupprimer du stockage, ignorer
Aucun sérialiseur enregistré pour le typeJournaliser (si debugMode), ignorer
fromJson lèveSupprimer du stockage, journaliser, ignorer
ValideMettre en file dans la map d'hydratation en attente

Appeler une seule fois au démarrage, après l'enregistrement de tous les sérialiseurs et avant runApp :

main.dart
await storage.init();
client.registerSerializer<User>(...);
await client.hydrate(); // ← avant runApp
runApp(...);

persistQuery

Future<void> persistQuery<T>(Object key, {Duration? ttl})

Force la persistance de la valeur actuellement en cache pour key. Sans effet si la requête n'est pas à l'état Success ou si T n'a pas de sérialiseur enregistré.

ttl remplace persistDuration pour cette entrée spécifique.

main.dart
// Persister avec un TTL court (ex. pour les données sensibles)
await client.persistQuery<User>(['users', userId], ttl: const Duration(hours: 1));

evictFromStorage

Future<void> evictFromStorage(Object key)

Supprime l'entrée persistée pour key du StorageAdapter. Le cache en mémoire n'est pas affecté.

Utiliser removeQuery pour supprimer à la fois du cache et du stockage simultanément.

main.dart
await client.evictFromStorage(['users', userId]);

clearStorage

Future<void> clearStorage()

Supprime toutes les entrées que Qora a écrites dans le StorageAdapter. Les clés que Qora n'a pas écrites (des réglages de l'app dans une box Hive partagée, par exemple) ne sont pas touchées ; appelez clear() sur l'adapter lui-même pour tout effacer. Le cache en mémoire n'est pas affecté.

Utiliser clear() pour vider à la fois le cache en mémoire et le stockage simultanément.


removeQuery (override)

Appelle super.removeQuery(key) et supprime l'entrée du StorageAdapter.

main.dart
// À la suppression : retire du cache et du stockage
await api.deleteUser(userId);
client.removeQuery(['users', userId]);

clear (override)

Appelle super.clear() et appelle clearStorage().

main.dart
// À la déconnexion : vide tout
client.clear();

hydrateQuery (depuis QoraClient)

void hydrateQuery<T>(Object key, T data, {DateTime? updatedAt})

Pré-peuple le cache avec une valeur. Insère un état Success<T> avec updatedAt (par défaut DateTime.now()). Sans effet si l'entrée est déjà dans un état non-Initial.

Utilisé en interne par PersistQoraClient mais disponible pour les cas d'utilisation avancés (ex. pré-chargement depuis une source personnalisée).

main.dart
client.hydrateQuery<User>(
  ['users', userId],
  cachedUser,
  updatedAt: DateTime.now().subtract(const Duration(minutes: 3)),
);

QoraSerializer<T>

class QoraSerializer<T> {
  const QoraSerializer({
    required dynamic Function(T value) toJson,
    required T Function(dynamic json) fromJson,
  });
}

Une paire de fonctions de conversion pour le type T.

PropriétéTypeDescription
toJsondynamic Function(T)Convertit T en une valeur encodable en JSON (Map, List, String, num, bool ou null).
fromJsonT Function(dynamic)Restaure T depuis la valeur précédemment produite par toJson.

Les deux fonctions utilisent dynamic (pas Map<String, dynamic>) pour que les primitives, listes et maps soient toutes supportées.

main.dart
// Objet
final userSerializer = QoraSerializer<User>(
  toJson: (u) => u.toJson(),       // retourne Map<String, dynamic>
  fromJson: User.fromJson,         // accepte Map<String, dynamic>
);

// Primitive
final intSerializer = QoraSerializer<int>(
  toJson: (n) => n,                // retourne int directement
  fromJson: (json) => json as int,
);

StorageAdapter

abstract interface class StorageAdapter {
  Future<void> init();
  Future<String?> read(String key);
  Future<void> write(String key, String value);
  Future<void> delete(String key);
  Future<List<String>> keys();
  Future<void> clear();
  Future<void> dispose();
}

Un contrat clé/valeur minimal. PersistQoraClient gère toute la sérialisation ; les adaptateurs ne manipulent que des chaînes JSON opaques.

MéthodeDescription
init()Ouvre le backend. Doit être appelé et attendu avant toute autre méthode.
read(key)Retourne la valeur pour key, ou null si absente.
write(key, value)Persiste value sous key, écrasant toute valeur existante.
delete(key)Supprime l'entrée. Sans effet si absente.
keys()Retourne toutes les clés stockées. L'ordre n'est pas spécifié.
clear()Supprime toutes les entrées.
dispose()Libère les ressources (handles de fichiers, connexions BD, etc.).

InMemoryStorageAdapter

class InMemoryStorageAdapter implements StorageAdapter

Un adaptateur soutenu par une Map. Toutes les opérations se complètent de façon synchrone (enveloppées dans des Future résolus). Les données sont perdues quand le processus se termine.

Utiliser pour les tests unitaires, les tests d'intégration et les environnements CI où aucun stockage réel n'est nécessaire.

test/persistence_test.dart
final adapter = InMemoryStorageAdapter();
await adapter.init();

final client = PersistQoraClient(storage: adapter);
client.registerSerializer<User>(userSerializer, name: 'User');
await client.hydrate(); // sans effet au premier lancement

// ... exécuter des requêtes ...

// Vérifier la persistance
final keys = await adapter.keys();
expect(keys, contains('["users",1]'));

Implémenter un adaptateur personnalisé

my_adapter.dart
import 'package:qora/qora.dart';

class MyAdapter implements StorageAdapter {
  @override
  Future<void> init() async {
    // Ouvrir la base de données / le fichier
  }

  @override
  Future<String?> read(String key) async {
    // Retourner la valeur stockée ou null
  }

  @override
  Future<void> write(String key, String value) async {
    // Persister la valeur sous la clé
  }

  @override
  Future<void> delete(String key) async {
    // Supprimer l'entrée, sans effet si absente
  }

  @override
  Future<List<String>> keys() async {
    // Retourner toutes les clés stockées
  }

  @override
  Future<void> clear() async {
    // Supprimer toutes les entrées
  }

  @override
  Future<void> dispose() async {
    // Libérer les ressources
  }
}

Référence d'éviction du stockage

OpérationCache en mémoireStorageAdapter
invalidate(key)Marque périméNon affecté
removeQuery(key)SuppriméSupprimé
clearCache()VidéNon affecté
clear()VidéVidé
evictFromStorage(key)Non affectéSupprimé
clearStorage()Non affectéVidé
persistQuery(key)Non affectéÉcrit

Voir aussi

Copyright © 2026