Drift (Moor) — Co to je, reaktivní ORM a práce s databázemi

Autor: IT Sectr Publikováno: 2026-03-13 Doba čtení: 9 min

Drift (dříve Moor) — reaktivní ORM pro Flutter a Dart, postavené nad SQLite s vlastním DSL pro dotazy. Na rozdíl od tradičních ORM Drift kompiluje Dart dotazy do SQL během fáze sestavení, čímž eliminuje runtime chyby. Podle Drift Docs, 2024 generuje Drift až o 40 % více kódu než ruční SQL dotazy, ale zcela eliminuje ruční psaní SQL a nahrazuje ho typově bezpečnou Dart syntaxí.

Hlavní body

  • Drift — reaktivní ORM s kompilací dotazů do SQL v době sestavení
  • DSL dotazy — fluent rozhraní v Dartu bez psaní SQL řetězců
  • Reaktivita — Stream a auto-updating dotazy pro aktualizace UI v reálném čase
  • Multiplatformnost — Android, iOS, Web, macOS, Linux, Windows
  • Migrace — automatické verzování a ruční migrace přes SQL

Co je Drift?

Drift — ORM pro Dart a Flutter, dříve známé jako Moor. Vyvinul ho Simon Binder v roce 2019 a od té doby prošlo několika major verzemi. Drift kompiluje Dart dotazy do SQL v době sestavení pomocí drift_dev a build_runner, což poskytuje úplnou typovou bezpečnost a eliminuje syntaktické chyby SQL za běhu.

Na rozdíl od Floor používá Drift vlastní DSL (Domain-Specific Language) pro vytváření dotazů — vývojář píše v Dartu a generátor to překládá do SQL. To umožňuje IDE kontrolovat syntaxi, automaticky doplňovat pole tabulek a refaktorovat datový model bez strachu z rozbití dotazu.

Podle Drift (2024) je knihovna používána ve více než 8000 Flutter projektech. Podporuje všechny populární platformy: Android přes sqflite, iOS přes sqflite, web přes sqlite3 WASM, desktop přes nativní ovladač sqlite3.

Historie přejmenování: Moor → Drift

Moor byl přejmenován na Drift ve verzi 2.0 (2022). Důvodem byl konflikt názvů s jinými projekty a touha distancovat se od starého kódu. API zůstalo kompatibilní: pro migraci stačí změnit import z moor na drift a aktualizovat závislosti.

Klíčové možnosti

Drift poskytuje: vestavěné Stream dotazy s automatickou aktualizací při změně dat, podporu transakcí s vrácením zpět, vlastní SQL dotazy přes rawQuery, DAO vzor pro zapouzdření logiky, multiplatformní migrace a integraci s Riverpod a BLoC přes balíčky drift_riverpod a drift_bloc.

Jak Drift funguje?

Drift používá generování kódu v době kompilace. Vývojář popisuje tabulky pomocí @DataClass anotací nebo Dart tříd rozšiřujících Table. Generátor vytváří pomocné třídy: Companion (pro nullable pole při vkládání/aktualizaci), DriftDatabase (vstupní bod) a implementace DAO.

SQLite dotazy nejsou Driftem prováděny přímo. Místo toho vývojář píše v Dartu: select(tasks).where(tasks.priority.greaterThan(3)).build(). Generátor to překládá do SQL a za běhu Drift jednoduše odešle hotový SQL dotaz do SQLite. To kombinuje pohodlí Dart syntaxe s výkonem nativního SQL.

Architektura dotazů

Drift podporuje dva režimy dotazů: DSL (doporučený) a raw SQL. DSL dotazy jsou bezpečnější — kompilátor kontroluje názvy polí, typy a kompatibilitu. Raw SQL je potřeba pro složité dotazy nepokryté DSL: okenní funkce, rekurzivní CTE, specifická SQLite rozšíření.

Drift DSL vs SQL: srovnání přístupů

Drift nabízí dva způsoby psaní dotazů: Dart DSL (nativní) a raw SQL (pro složité případy). DSL je preferovaný pro 90 % scénářů: je bezpečnější, čitelnější a podporuje refaktorování. Raw SQL se používá pouze když DSL nepokrývá požadovanou konstrukci.

AspektDrift DSLRaw SQL v Drift
Typová bezpečnostPlná (kompilace)Ne (runtime)
Automatické doplňováníAno (IDE)Pouze v .sql souborech
RefaktorováníAutomatickéRuční vyhledávání v řetězcích
Složité JOINPodporovanéPlná svoboda
Okenní funkceOmezenéPlná podpora
ReaktivitaVestavěná (Stream)Přes .watch()

Kdy použít DSL

Drift DSL — hlavní způsob práce. Pokrývá SELECT, INSERT, UPDATE, DELETE, WHERE, ORDER BY, LIMIT, JOIN a seskupování. Pro všechny typické CRUD dotazy použijte DSL: je kratší, bezpečnější a automaticky aktualizuje Stream při změnách.

Kdy použít raw SQL

Raw SQL v Drift je potřeba pro: vlastní SQLite funkce (FTS5, JSON1), složité poddotazy s EXISTS, INSERT OR REPLACE, hromadné UPDATE s CASE a pro dotazy kde je výkon kritický a DSL negeneruje optimální plán provádění. Raw SQL lze psát v .sql souborech s podporou typizace přes drift_dev.

Příklady kódu s Drift

Drift používá třídy rozšiřující Table nebo anotaci @DataClass. Níže je kompletní příklad modelu Task s dotazy přes DSL, raw SQL a reaktivní aktualizací. Po spuštění build_runner jsou všechny vygenerované třídy připraveny.

Definice tabulky a databáze

Třída Tasks rozšiřuje Table a definuje sloupce. Každý sloupec je výraz typu Column<T>. Parametry: withDefault() nastavuje výchozí hodnotu, autoIncrement() — autoinkrement. Databáze je abstraktní třída rozšiřující $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);
}

CRUD operace přes DSL

Drift generuje metody into(tasks).insert(), select(tasks), update(tasks) a delete(tasks) pro tabulky. Všechny operace vracejí Future — práce s SQLite je asynchronní. Pro sledování změn použijte .watch() místo .get().

dart
// Vložit
await into(tasks).insert(TasksCompanion.insert(
    title: Value('Koupit potraviny'),
    priority: Value(3),
));

// Čtení s filtrem
final highPriority = await (select(tasks)
    ..where((t) => t.priority.greaterThan(2))
    ..orderBy([(t) => OrderingTerm(expression: t.priority, mode: OrderingMode.desc)]))
    .get();

// Reaktivní pozorování
select(tasks).watch().listen((tasksList) {
    // tasksList — List, aktualizuje se při každé změně tabulky
    updateUi(tasksList);
});

Raw SQL s typovaným výsledkem

Pro složité dotazy Drift umožňuje psát raw SQL při zachování typizace. Metoda customSelect přijímá řetězec dotazu a vrací typovaný výsledek přes generátor kódu. Tento přístup kombinuje flexibilitu SQL s typovou bezpečností 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")}');
}

Migrace a verzování v Drift

Drift podporuje jak automatické migrace (pro jednoduché změny), tak ruční (pro složité transformace). Verze databáze se nastavuje v konstruktoru AppDatabase. Při neshodě verze Drift aplikuje všechny nevyřízené migrace postupně.

Automatické migrace

Pro přidání sloupce s výchozí hodnotou může Drift vygenerovat migraci automaticky přes MigrationStrategy. Pokud změna nenarušuje existující data (přidání nullable pole), lze použít beforeOpen s kontrolou verze a provedením ALTER TABLE.

Ruční migrace

Pro složité změny (přejmenování tabulky, sloučení dat, změna typu sloupce) Drift vyžaduje ruční SQL migraci. Migrace se nastavují přes parametr migrations ve třídě databáze. Každá migrace je objekt s čísly from/to a SQL dotazy.

Drift a testování

Drift podporuje spuštění v testovacím režimu přes NativeDatabase.memory(). Databáze v paměti je vytvořena od začátku před každým testem a zničena po něm. Pro mockování použijte balíček mocktail s zamockovaným QueryExecutor. Drift také poskytuje DatabaseTestHelper pro integrační testy s kontrolou migrací a dotazů.

DAO vzor v Drift

Drift podporuje DAO (Data Access Object) přes abstraktní třídy s anotací @DriftAccessor. DAO zapouzdřuje dotazy na jednu nebo více tabulek a lze jej testovat nezávisle na databázi. Na rozdíl od přímých dotazů přes Database umožňuje DAO znovupoužití logiky dotazů mezi různými částmi aplikace a zjednodušuje unit testování.

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);
        }));
    }
}

Často kladené otázky

Čím se Drift liší od Floor?

Drift používá vlastní DSL místo SQL řetězců, což poskytuje plnou typovou bezpečnost a automatické doplňování v IDE. Floor používá SQL řetězce v anotaci @Query. Drift také podporuje více platforem (včetně webu) a má vestavěnou reaktivitu přes Stream, zatímco v Floor je třeba Stream deklarovat ručně.

Podporuje Drift migrace bez ztráty dat?

Ano, Drift podporuje migrace se zachováním dat. Pro přidání sloupců použijte addColumn v Migration. Pro složité transformace (přejmenování, sloučení) pište raw SQL uvnitř migrace. Pokud migrace není zadána, Drift znovu vytvoří databázi se ztrátou dat při neshodě schématu.

Lze použít Drift bez build_runner?

Drift vyžaduje generování kódu přes build_runner a drift_dev. Bez generování nelze vytvořit typované dotazy. Pro malé projekty však Drift podporuje sqlparser — ruční psaní SQL souborů s automatickou typizací, ale stále to vyžaduje fázi generování.

Jak integrovat Drift s Riverpod?

Pro integraci s Riverpod použijte balíček drift_riverpod. Poskytuje providery pro Database, DAO a Stream dotazy. Příklad: final tasksProvider = databaseProvider.select((db) => db.select(db.tasks).watch()) — UI se automaticky přestaví při změně dat.

Podporuje Drift šifrování SQLite?

Drift nemá vestavěné šifrování, ale podporuje připojení vlastních sqlite3 knihoven s SEE (SQLite Encryption Extension). Pro mobilní platformy použijte sqflite_sqlcipher jako QueryExecutor — Drift funguje s jakoukoli implementací SQLite přes abstraktní QueryExecutor.

Shrnutí

  • Drift — reaktivní ORM pro Flutter a Dart s kompilací dotazů do SQL v době sestavení
  • DSL syntaxe — Dart dotazy s plnou typovou bezpečností a automatickým doplňováním v IDE
  • Reaktivita — Stream a auto-updating dotazy pro automatické aktualizace UI
  • Multiplatformnost — Android, iOS, Web (WASM), macOS, Linux, Windows
  • Migrace — automatické pro jednoduché změny a ruční SQL pro složité
  • Ekosystém — integrace s Riverpod (drift_riverpod) a BLoC (drift_bloc)
  • Doporučení — vyberte Drift pro projekty, kde je důležitá reaktivita, typová bezpečnost a podpora všech Flutter platforem

Vyvineme mobilní aplikaci na klíč

IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.

Prodiskutovat projekt

Přečtěte si také