Référence de l'API

QoraKey

Clé de requête typée et immuable avec égalité structurelle. Supporte à la fois la syntaxe List brute et QoraKey.

Vue d'ensemble

Chaque requête Qora est identifiée par une clé. Qora accepte deux formats équivalents :

main.dart
// Liste brute : sans friction, pas d'import nécessaire
key: ['users', userId]

// Wrapper QoraKey : explicite, typé
key: QoraKey(['users', userId])
key: QoraKey.withId('users', userId)

Les deux sont normalisés vers la même représentation interne et comparés avec une égalité structurelle profonde. Ils sont entièrement interchangeables : on peut les mélanger entre appels vers la même requête logique.


Constructeurs

QoraKey(List<dynamic> parts)

Constructeur direct depuis une liste de parties.

main.dart
QoraKey(['users', userId])
QoraKey(['posts', {'status': 'published', 'page': 1}])

QoraKey.single(String key)

Raccourci pour une clé à segment unique.

main.dart
QoraKey.single('users')  // équivalent à QoraKey(['users'])

QoraKey.withId(String entity, dynamic id)

Raccourci pour une clé entité + ID.

main.dart
QoraKey.withId('users', userId)     // ['users', userId]
QoraKey.withId('posts', postId)     // ['posts', postId]

QoraKey.withFilter(String entity, Map<String, dynamic> filter)

Raccourci pour une clé entité + map de filtres.

main.dart
QoraKey.withFilter('posts', {'status': 'published', 'page': page})
// ['posts', {'status': 'published', 'page': page}]

QoraKey.from(List<dynamic> parts)

Constructeur factory qui convertit une liste brute en QoraKey.

main.dart
final key = QoraKey.from(['users', userId]);

Propriétés

parts

final List<dynamic> parts

Les segments bruts de la clé sous forme de liste non modifiable.

main.dart
final key = QoraKey.withId('users', 42);
print(key.parts); // [users, 42]

Égalité

QoraKey utilise une égalité structurelle profonde : deux clés sont égales si leurs parties sont récursivement égales :

main.dart
QoraKey(['users', 1]) == QoraKey(['users', 1])  // true
QoraKey(['users', 1]) == QoraKey(['users', 2])  // false

// Liste brute et QoraKey sont normalisés identiquement
['users', 1] == QoraKey(['users', 1])           // normalisé vers la même entrée de cache

Types supportés dans les parties de clé :

TypeSupport
int, double, boolÉgalité structurelle complète
StringÉgalité structurelle complète
nullSupporté comme partie de clé
ListComparaison récursive
MapComparaison récursive indépendante de l'ordre
Objets personnalisésDoivent surcharger operator == et hashCode
Utiliser des objets personnalisés (ex. UserFilter) dans les parties de clé sans surcharger operator == et hashCode crée une nouvelle entrée de cache à chaque appel. Utiliser des valeurs sérialisables en primitives ou implémenter l'égalité explicitement.

normalizeKey

List<dynamic> normalizeKey(Object key)

Fonction de niveau supérieur qui normalise toute entrée de clé valide en une List<dynamic> non modifiable :

  • Accepte QoraKey ou List<dynamic>
  • Valide que les parties sont sérialisables
  • Retourne une liste copiée en profondeur et non modifiable

Cela est appelé en interne par chaque méthode de QoraClient. L'appel direct est rarement nécessaire.

main.dart
final parts = normalizeKey(['users', 1]);   // [users, 1] (non modifiable)
final parts = normalizeKey(QoraKey.withId('users', 1));  // même résultat

Lève ArgumentError si la clé n'est pas une List ou un QoraKey.


Pattern Key Factories

Centraliser les définitions de clés pour éviter les fautes de frappe et simplifier l'invalidation :

lib/query_keys.dart
abstract class Keys {
  // Utilisateurs
  static List<dynamic> users() => ['users'];
  static List<dynamic> user(int id) => ['users', id];
  static List<dynamic> userPosts(int userId) => ['users', userId, 'posts'];

  // Posts
  static List<dynamic> posts(Map<String, dynamic> filters) => ['posts', filters];
  static List<dynamic> post(int id) => ['posts', id];
}

// Utilisation
await client.fetchQuery<User>(
  key: Keys.user(userId),
  fetcher: () => api.getUser(userId),
);

client.invalidateWhere((key) => equalsKey(key, Keys.users()));

Bonnes pratiques

A faire

main.dart
// Structure cohérente : entité en premier, puis ID/filtres
['users', userId]
['users', userId, 'posts']
['posts', {'status': 'published'}]

// Utiliser des primitives : toujours comparables
['users', userId.toString()]
['posts', {'page': page, 'limit': 20}]

A eviter

main.dart
// Ordre incohérent
['users', userId]
[userId, 'users']  // Entrée de cache différente

// Objets personnalisés sans égalité
['users', UserFilter(status: 'active')]  // Égalité d'identité : toujours un miss

// Valeurs calculées variant à chaque appel
['posts', DateTime.now().toIso8601String()]  // N'atteint jamais le cache
Copyright © 2026