Drift (Moor) — ce que c’est, ORM réactif et travail avec les bases de données

Auteur : IT Sectr Publié le : 2026-03-13 Temps de lecture : 9 min

Drift (anciennement Moor) est un ORM réactif pour Flutter et Dart, construit sur SQLite avec son propre DSL pour les requêtes. Contrairement aux ORM traditionnels, Drift compile les requêtes Dart en SQL au moment de la construction, éliminant les erreurs d’exécution. Selon Drift Docs, 2024, Drift génère jusqu’à 40% plus de code que les requêtes SQL manuelles, mais élimine complètement l’écriture manuelle de SQL, en la remplaçant par une syntaxe Dart sûre pour les types.

Points clés

  • Drift — ORM réactif avec compilation des requêtes en SQL à la construction
  • Requêtes DSL — interface fluide en Dart sans écrire de chaînes SQL
  • Réactivité — Stream et requêtes à mise à jour automatique pour l’UI en temps réel
  • Multiplateforme — Android, iOS, Web, macOS, Linux, Windows
  • Migrations — versionnement automatique et migrations manuelles via SQL

Qu’est-ce que Drift ?

Drift est un ORM pour Dart et Flutter, anciennement connu sous le nom de Moor. Il a été développé par Simon Binder en 2019 et a depuis connu plusieurs versions majeures. Drift compile les requêtes Dart en SQL au moment de la construction en utilisant drift_dev et build_runner, offrant une sécurité totale des types et éliminant les erreurs de syntaxe SQL à l’exécution.

Contrairement à Floor, Drift utilise son propre DSL (langage spécifique au domaine) pour construire les requêtes — le développeur écrit en Dart, et le générateur le traduit en SQL. Cela permet à l’IDE de vérifier la syntaxe, d’autocompléter les champs de table et de refactoriser le modèle de données sans crainte de casser les requêtes.

Selon Drift (2024), la bibliothèque est utilisée dans plus de 8000 projets Flutter. Elle prend en charge toutes les plateformes populaires : Android via sqflite, iOS via sqflite, web via sqlite3 WASM, bureau via le pilote natif sqlite3.

Historique du changement de nom : Moor → Drift

Moor a été renommé en Drift dans la version 2.0 (2022). La raison était un conflit de noms avec d’autres projets et le souhait de se distancer de l’ancien code. L’API est restée compatible : pour migrer, il suffit de remplacer l’import de moor à drift et de mettre à jour les dépendances.

Fonctionnalités clés

Drift fournit : des requêtes Stream intégrées avec mise à jour automatique lors des changements de données, la prise en charge des transactions avec rollback, des requêtes SQL personnalisées via rawQuery, le modèle DAO pour l’encapsulation de la logique, des migrations multiplateformes et l’intégration avec Riverpod et BLoC via les paquets drift_riverpod et drift_bloc.

Comment fonctionne Drift ?

Drift utilise la génération de code au moment de la compilation. Le développeur décrit les tables via des annotations @DataClass ou des classes Dart étendant Table. Le générateur crée des classes d’assistance : Companion (pour les champs nullable lors de l’insertion/mise à jour), DriftDatabase (point d’entrée) et des implémentations DAO.

Drift n’exécute pas les requêtes SQLite directement. Au lieu de cela, le développeur écrit en Dart : select(tasks).where(tasks.priority.greaterThan(3)).build(). Le générateur traduit cela en SQL, et à l’exécution, Drift envoie simplement la requête SQL prête à SQLite. Cela combine la commodité de la syntaxe Dart avec les performances du SQL natif.

Architecture des requêtes

Drift prend en charge deux modes de requête : DSL (recommandé) et SQL brut. Les requêtes DSL sont plus sûres à écrire — le compilateur vérifie les noms de champs, les types et la compatibilité. Le SQL brut est nécessaire pour les requêtes complexes non couvertes par le DSL : fonctions de fenêtre, CTE récursives, extensions SQLite spécifiques.

Drift DSL vs SQL : comparaison des approches

Drift offre deux façons d’écrire des requêtes : Dart DSL (natif) et SQL brut (pour les cas complexes). Le DSL est préférable pour 90% des scénarios : il est plus sûr, plus lisible et prend en charge le refactoring. Le SQL brut est utilisé uniquement lorsque le DSL ne couvre pas la construction nécessaire.

AspectDrift DSLSQL brut dans Drift
Sécurité des typesComplète (compilation)Non (exécution)
AutocomplétionOui (IDE)Uniquement dans les fichiers sql
RefactoringAutomatiqueRecherche manuelle dans les chaînes
JOIN complexesPris en chargeLiberté totale
Fonctions de fenêtreLimitéPrise en charge complète
RéactivitéIntégrée (Stream)Via .watch()

Quand utiliser le DSL

Drift DSL est le mode de travail principal. Il couvre SELECT, INSERT, UPDATE, DELETE, WHERE, ORDER BY, LIMIT, JOIN et le regroupement. Pour toutes les requêtes CRUD typiques, utilisez le DSL : il est plus court, plus sûr et met automatiquement à jour le Stream lors des modifications.

Quand utiliser le SQL brut

SQL brut dans Drift est nécessaire pour : les fonctions SQLite personnalisées (FTS5, JSON1), les sous-requêtes complexes avec EXISTS, INSERT OR REPLACE, les UPDATE massifs avec CASE, ainsi que les requêtes où les performances sont critiques et le DSL ne génère pas le plan d’exécution optimal. Le SQL brut peut être écrit dans des fichiers .sql avec prise en charge du typage via drift_dev.

Exemples de code avec Drift

Drift utilise des classes qui étendent Table ou l’annotation @DataClass. Voici un exemple complet du modèle Task avec des requêtes via DSL, SQL brut et mise à jour réactive. Après avoir exécuté build_runner, toutes les classes générées sont prêtes.

Définition de la table et de la base de données

La classe Tasks étend Table et définit les colonnes. Chaque colonne est une expression de type Column<T>. Paramètres : withDefault() définit une valeur par défaut, autoIncrement() définit l’auto-incrémentation. La base de données est une classe abstraite qui étend $DriftDatabase.

dart
class Tasks extends Table {
    IntColumn get id => integer().autoIncrement();
    TextColumn get title => text().withDefault(const Constant(''))();
    BoolColumn get isCompleted => boolean().withDefault(const Constant(false))();
    IntColumn get priority => integer().withDefault(const Constant(0))();
}

@DriftDatabase(tables: [Tasks])
class AppDatabase extends $AppDatabase {
    AppDatabase(QueryExecutor e) : super(e);
}

Opérations CRUD via DSL

Drift génère les méthodes into(tasks).insert(), select(tasks), update(tasks) et delete(tasks) pour les tables. Toutes les opérations retournent Future — travailler avec SQLite est asynchrone. Pour suivre les changements, utilisez .watch() au lieu de .get().

dart
// Insérer
await into(tasks).insert(TasksCompanion.insert(
    title: Value('Acheter des courses'),
    priority: Value(3),
));

// Lecture avec filtre
final highPriority = await (select(tasks)
    ..where((t) => t.priority.greaterThan(2))
    ..orderBy([(t) => OrderingTerm(expression: t.priority, mode: OrderingMode.desc)]))
    .get();

// Observation réactive
select(tasks).watch().listen((tasksList) {
    // tasksList — List, mis à jour à chaque modification de la table
    updateUi(tasksList);
});

SQL brut avec résultat typé

Pour les requêtes complexes, Drift permet d’écrire du SQL brut tout en conservant le typage. La méthode customSelect prend une chaîne de requête et retourne un résultat typé via le générateur de code. Cette approche combine la flexibilité du SQL avec la sécurité des types de Drift.

dart
final result = await customSelect(
    'SELECT title, COUNT(*) as cnt FROM tasks GROUP BY title',
    readsFrom: { tasks },
).get();

for (final row in result) {
    print('${row.readString("title")}: ${row.readInt("cnt")}');
}

Migrations et versionnement dans Drift

Drift prend en charge les migrations automatiques (pour les changements simples) et manuelles (pour les transformations complexes). La version de la base de données est définie dans le constructeur d’AppDatabase. Si la version ne correspond pas, Drift applique toutes les migrations en attente séquentiellement.

Migrations automatiques

Pour ajouter une colonne avec une valeur par défaut, Drift peut générer automatiquement une migration via MigrationStrategy. Si le changement n’affecte pas les données existantes (ajout d’un champ nullable), vous pouvez utiliser beforeOpen avec vérification de version et exécution de ALTER TABLE.

Migrations manuelles

Pour les changements complexes (renommer une table, fusionner des données, modifier le type d’une colonne), Drift nécessite une migration SQL manuelle. Les migrations sont spécifiées via le paramètre migrations dans la classe de base de données. Chaque migration est un objet avec des numéros from/to et des requêtes SQL.

Drift et les tests

Drift prend en charge l’exécution en mode test via NativeDatabase.memory(). La base de données en mémoire est créée à partir de zéro avant chaque test et détruite après. Pour le mock, utilisez le paquet mocktail avec un QueryExecutor simulé. Drift fournit également DatabaseTestHelper pour les tests d’intégration avec vérification des migrations et des requêtes.

Modèle DAO dans Drift

Drift prend en charge DAO (Data Access Object) via des classes abstraites avec l’annotation @DriftAccessor. DAO encapsule les requêtes vers une ou plusieurs tables et peut être testé séparément de la base de données. Contrairement aux requêtes directes via Database, DAO permet de réutiliser la logique de requête entre différentes parties de l’application et simplifie les tests unitaires.

dart
@DriftDatabase(tables: [Tasks])
class AppDatabase extends $AppDatabase {
    AppDatabase(QueryExecutor e) : super(e) {
        migrations.add(Migration(1, 2, (m) async {
            await m.addColumn(tasks, tasks.dueDate);
            await m.createIndex(tasks.idxPriority);
        }));
    }
}

Foire aux questions

En quoi Drift diffère-t-il de Floor ?

Drift utilise son propre DSL au lieu de chaînes SQL, offrant une sécurité totale des types et l’autocomplétion dans l’IDE. Floor utilise des chaînes SQL dans l’annotation @Query. Drift prend également en charge plus de plateformes (y compris le web) et dispose d’une réactivité intégrée via Stream, tandis que dans Floor, le Stream doit être déclaré manuellement.

Drift prend-il en charge les migrations sans perte de données ?

Oui, Drift prend en charge les migrations avec préservation des données. Pour ajouter des colonnes, utilisez addColumn dans Migration. Pour les transformations complexes (renommage, fusion), écrivez du SQL brut dans la migration. Si aucune migration n’est spécifiée, Drift recrée la base de données avec perte de données lorsque le schéma ne correspond pas.

Peut-on utiliser Drift sans build_runner ?

Drift nécessite la génération de code via build_runner et drift_dev. Sans génération, il est impossible de créer des requêtes typées. Cependant, pour les petits projets, Drift prend en charge sqlparser — écriture manuelle de fichiers SQL avec typage automatique, mais cela nécessite tout de même une étape de génération.

Comment intégrer Drift avec Riverpod ?

Pour l’intégration avec Riverpod, utilisez le paquet drift_riverpod. Il fournit des providers pour Database, DAO et les requêtes Stream. Exemple : final tasksProvider = databaseProvider.select((db) => db.select(db.tasks).watch()) — l’UI se reconstruit automatiquement lorsque les données changent.

Drift prend-il en charge le chiffrement SQLite ?

Drift n’a pas de chiffrement intégré, mais il prend en charge la connexion de bibliothèques sqlite3 personnalisées avec SEE (SQLite Encryption Extension). Pour les plateformes mobiles, utilisez sqflite_sqlcipher comme QueryExecutor — Drift fonctionne avec toute implémentation SQLite via le QueryExecutor abstrait.

Résumé

  • Drift — un ORM réactif pour Flutter et Dart avec compilation des requêtes en SQL à la construction
  • Syntaxe DSL — requêtes Dart avec sécurité totale des types et autocomplétion dans l’IDE
  • Réactivité — Stream et requêtes à mise à jour automatique pour l’UI en temps réel
  • Multiplateforme — Android, iOS, Web (WASM), macOS, Linux, Windows
  • Migrations — automatiques pour les changements simples et SQL manuel pour les complexes
  • Écosystème — intégration avec Riverpod (drift_riverpod) et BLoC (drift_bloc)
  • Recommandation — choisissez Drift pour les projets où la réactivité, la sécurité des types et la prise en charge de toutes les plateformes Flutter sont importantes

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi