PersistQoraClient
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ètre | Description |
|---|---|
storage | Le backend de stockage. Doit être initialisé via StorageAdapter.init() avant d'appeler hydrate(). |
persistDuration | TTL 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). |
config | Transmis à QoraClient. |
tracker | Transmis à QoraClient. |
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ètre | Description |
|---|---|
serializer | Fournit les convertisseurs toJson/fromJson pour T. |
name | L'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
registerSerializerdeux fois pour le mêmeTou le mêmenameremplace l'entrée précédente. - Doit être appelé avant
hydrate().
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 :
| Condition | Action |
|---|---|
| Échec de décodage JSON | Supprimer du stockage, ignorer |
| TTL expiré | Supprimer du stockage, ignorer |
| Aucun sérialiseur enregistré pour le type | Journaliser (si debugMode), ignorer |
fromJson lève | Supprimer du stockage, journaliser, ignorer |
| Valide | Mettre 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 :
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.
// 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.
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.
// À la suppression : retire du cache et du stockage
await api.deleteUser(userId);
client.removeQuery(['users', userId]);
clear (override)
Appelle super.clear() et appelle clearStorage().
// À 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).
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é | Type | Description |
|---|---|---|
toJson | dynamic Function(T) | Convertit T en une valeur encodable en JSON (Map, List, String, num, bool ou null). |
fromJson | T 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.
// 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éthode | Description |
|---|---|
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.
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é
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ération | Cache en mémoire | StorageAdapter |
|---|---|---|
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
- Guide de persistance : walkthrough étape par étape
- API QoraClient : référence du client de base
- QoraOptions :
staleTime,gcTimeet autres paramètres par requête
API Mutation
Référence complète de MutationController, MutationState, MutationOptions, MutationUpdate et l'observabilité des mutations sur QoraClient.
Requête infinie
Référence complète de InfiniteData, InfiniteQueryState, InfiniteQueryOptions, InfiniteQueryObserver, InfiniteQueryBuilder, InfiniteQueryController et les méthodes de requête infinie de QoraClient.