Drift (Moor) — Ano Ito, Reactive ORM at Paggawa gamit ang mga Database

May-akda: IT Sectr Nai-publish: 2026-03-13 Oras ng pagbabasa: 9 min

Drift (dating Moor) — reactive ORM para sa Flutter at Dart, na binuo sa ibabaw ng SQLite na may sariling DSL para sa mga query. Hindi tulad ng tradisyonal na ORM, ang Drift ay nagko-compile ng Dart queries sa SQL sa build time, na inaalis ang runtime errors. Ayon sa Drift Docs, 2024, ang Drift ay bumubuo ng hanggang 40% na mas maraming code kaysa sa manu-manong SQL queries, ngunit ganap nitong inaalis ang manu-manong pagsulat ng SQL, pinapalitan ito ng type-safe Dart syntax.

Mga Pangunahing Punto

  • Drift — reactive ORM na may compilation ng queries sa SQL sa build time
  • DSL queries — fluent interface sa Dart nang hindi nagsusulat ng SQL strings
  • Reactivity — Stream at auto-updating queries para sa real-time na UI updates
  • Cross-platform — Android, iOS, Web, macOS, Linux, Windows
  • Migrations — awtomatikong versioning at manual migrations sa pamamagitan ng SQL

Ano ang Drift?

Drift — ORM para sa Dart at Flutter, dating kilala bilang Moor. Binuo ni Simon Binder noong 2019 at dumaan sa ilang major versions mula noon. Nagko-compile ang Drift ng Dart queries sa SQL sa build time gamit ang drift_dev at build_runner, na nagbibigay ng kumpletong type-safety at inaalis ang syntax errors ng SQL sa runtime.

Hindi tulad ng Floor, gumagamit ang Drift ng sarili nitong DSL (Domain-Specific Language) para sa paggawa ng queries — ang developer ay nagsusulat sa Dart, at ang generator ay nagti-translate nito sa SQL. Ito ay nagpapahintulot sa IDE na suriin ang syntax, i-autocomplete ang mga table fields, at i-refactor ang data model nang walang takot na masira ang query.

Ayon sa Drift (2024), ang library ay ginagamit sa mahigit 8000 Flutter projects. Sinusuportahan nito ang lahat ng sikat na platform: Android sa pamamagitan ng sqflite, iOS sa pamamagitan ng sqflite, web sa pamamagitan ng sqlite3 WASM, desktop sa pamamagitan ng sqlite3 native driver.

Kasaysayan ng pagpapalit ng pangalan: Moor → Drift

Moor ay pinalitan ng pangalan sa Drift sa version 2.0 (2022). Dahilan — conflict ng pangalan sa iba pang proyekto at pagnanais na lumayo sa lumang code. Ang API ay nanatiling compatible: para sa migration, sapat na ang palitan ang import mula moor tungo sa drift at i-update ang dependencies.

Mga pangunahing kakayahan

Drift ay nagbibigay ng: built-in Stream queries na may awtomatikong pag-update kapag nagbago ang data, suporta sa transactions na may rollback, custom SQL queries sa pamamagitan ng rawQuery, DAO pattern para sa encapsulation ng logic, cross-platform migrations at integration sa Riverpod at BLoC sa pamamagitan ng drift_riverpod at drift_bloc packages.

Paano gumagana ang Drift?

Drift ay gumagamit ng code generation sa compile time. Inilalarawan ng developer ang mga table sa pamamagitan ng @DataClass annotations o Dart classes na nag-e-extend ng Table. Ang generator ay lumilikha ng mga helper classes: Companion (para sa nullable fields sa insert/update), DriftDatabase (entry point) at DAO implementations.

Ang SQLite queries ay hindi direktang ginagawa ng Drift. Sa halip, ang developer ay nagsusulat sa Dart: select(tasks).where(tasks.priority.greaterThan(3)).build(). Ang generator ay nagti-translate nito sa SQL, at sa runtime ang Drift ay nagpapadala lang ng handa nang SQL query sa SQLite. Ito ay pinagsasama ang convenience ng Dart syntax sa performance ng native SQL.

Arkitektura ng mga query

Drift ay sumusuporta sa dalawang mode ng query: DSL (inirerekomenda) at raw SQL. Ang DSL queries ay mas ligtas isulat — sinusuri ng compiler ang field names, types at compatibility. Ang Raw SQL ay kailangan para sa mga kumplikadong query na hindi sakop ng DSL: window functions, recursive CTE, specific SQLite extensions.

Drift DSL vs SQL: paghahambing ng mga approach

Drift ay nag-aalok ng dalawang paraan ng pagsulat ng query: Dart DSL (native) at raw SQL (para sa mga kumplikadong kaso). Ang DSL ay mas mainam para sa 90% ng mga scenario: ito ay mas ligtas, mas nababasa at sumusuporta sa refactoring. Ang Raw SQL ay ginagamit lang kapag hindi sakop ng DSL ang kinakailangang construction.

AspektoDrift DSLRaw SQL sa Drift
Type-safetyKumpleto (compilation)Wala (runtime)
AutocompleteOo (IDE)Sa .sql files lang
RefactoringAwtomatikoManual na paghahanap sa strings
Complex JOINSinusuportahanGanap na kalayaan
Window functionsLimitadoGanap na suporta
ReactivityBuilt-in (Stream)Sa pamamagitan ng .watch()

Kailan gagamitin ang DSL

Drift DSL — ang pangunahing paraan ng paggawa. Sinasaklaw nito ang SELECT, INSERT, UPDATE, DELETE, WHERE, ORDER BY, LIMIT, JOIN at grouping. Para sa lahat ng tipikal na CRUD queries, gamitin ang DSL: ito ay mas maikli, mas ligtas at awtomatikong nag-a-update ng Stream kapag may pagbabago.

Kailan gagamitin ang raw SQL

Raw SQL sa Drift ay kailangan para sa: custom SQLite functions (FTS5, JSON1), complex subqueries na may EXISTS, INSERT OR REPLACE, mass UPDATE na may CASE, at para sa mga query kung saan kritikal ang performance at hindi nagge-generate ang DSL ng optimal execution plan. Ang Raw SQL ay maaaring isulat sa .sql files na may typing support sa pamamagitan ng drift_dev.

Mga halimbawa ng code gamit ang Drift

Drift ay gumagamit ng mga class na nag-e-extend ng Table, o @DataClass annotation. Nasa ibaba ang kumpletong halimbawa ng Task model na may queries sa pamamagitan ng DSL, raw SQL at reactive update. Pagkatapos ng build_runner, lahat ng generated classes ay handa na.

Pagdeklara ng table at database

Ang klase na Tasks ay nag-e-extend ng Table at nagde-deklara ng mga column. Ang bawat column ay expression ng uri Column<T>. Parameters: withDefault() ay nagtatakda ng default value, autoIncrement() — auto-increment. Ang database ay abstract class na nag-e-extend ng $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 operations sa pamamagitan ng DSL

Ang Drift ay bumubuo ng mga method na into(tasks).insert(), select(tasks), update(tasks) at delete(tasks) para sa mga table. Lahat ng operations ay nagre-return ng Future — ang paggawa sa SQLite ay asynchronous. Para sa pagsubaybay ng mga pagbabago, gamitin ang .watch() sa halip na .get().

dart
// Insert
await into(tasks).insert(TasksCompanion.insert(
    title: Value('Buy groceries'),
    priority: Value(3),
));

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

// Reactive observation
select(tasks).watch().listen((tasksList) {
    // tasksList — List, ina-update sa bawat pagbabago ng table
    updateUi(tasksList);
});

Raw SQL na may typed na resulta

Para sa mga kumplikadong query, pinapayagan ng Drift ang pagsulat ng raw SQL habang pinapanatili ang typing. Ang method na customSelect ay tumatanggap ng query string at nagre-return ng typed na resulta sa pamamagitan ng code generator. Ang ganitong approach ay pinagsasama ang flexibility ng SQL sa type safety ng 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 at versioning sa Drift

Drift ay sumusuporta sa parehong awtomatikong migrations (para sa simpleng pagbabago) at manual (para sa kumplikadong transformations). Ang version ng database ay itinakda sa constructor ng AppDatabase. Kapag hindi tugma ang version, ina-apply ng Drift ang lahat ng hindi pa naa-apply na migrations nang sunod-sunod.

Awtomatikong migrations

Para sa pagdagdag ng column na may default value, ang Drift ay maaaring bumuo ng migration awtomatiko sa pamamagitan ng MigrationStrategy. Kung ang pagbabago ay hindi makakaapekto sa existing data (pagdagdag ng nullable field), maaaring gamitin ang beforeOpen na may version check at pag-execute ng ALTER TABLE.

Manual na migrations

Para sa kumplikadong pagbabago (pagpapalit ng pangalan ng table, pagsasama ng data, pagbabago ng column type), ang Drift ay nangangailangan ng manual SQL migration. Ang migrations ay itinakda sa pamamagitan ng parameter na migrations sa database class. Ang bawat migration ay object na may from/to numbers at SQL queries.

Drift at testing

Drift ay sumusuporta sa pagtakbo sa test mode sa pamamagitan ng NativeDatabase.memory(). Ang in-memory database ay nilikha mula sa simula bago ang bawat test at sinisira pagkatapos. Para sa mocking, gamitin ang mocktail package na may mocked QueryExecutor. Nagbibigay din ang Drift ng DatabaseTestHelper para sa integration tests na may checking ng migrations at queries.

DAO pattern sa Drift

Drift ay sumusuporta sa DAO (Data Access Object) sa pamamagitan ng abstract classes na may @DriftAccessor annotation. Ang DAO ay nag-e-encapsulate ng queries sa isa o maraming table at maaaring i-test nang hiwalay sa database. Hindi tulad ng direktang queries sa pamamagitan ng Database, pinapayagan ng DAO ang pag-reuse ng query logic sa iba't ibang bahagi ng application at pinapasimple ang unit testing.

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

Mga Madalas Itanong

Paano naiiba ang Drift sa Floor?

Drift ay gumagamit ng sarili nitong DSL sa halip na SQL strings, na nagbibigay ng kumpletong type-safety at autocomplete sa IDE. Ang Floor ay gumagamit ng SQL strings sa @Query annotation. Sinusuportahan din ng Drift ang mas maraming platform (kabilang ang web) at may built-in reactivity sa pamamagitan ng Stream, samantalang sa Floor ang Stream ay kailangang ideklara nang manu-mano.

Sinusuportahan ba ng Drift ang migrations nang walang pagkawala ng data?

Oo, Drift ay sumusuporta sa migrations na may pangangalaga ng data. Para sa pagdagdag ng columns, gamitin ang addColumn sa Migration. Para sa kumplikadong transformations (pagpapalit ng pangalan, pagsasama), sumulat ng raw SQL sa loob ng migration. Kung walang migration na tinukoy, ang Drift ay muling lilikha ng database na may pagkawala ng data kapag hindi tugma ang schema.

Maaari bang gamitin ang Drift nang walang build_runner?

Drift ay nangangailangan ng code generation sa pamamagitan ng build_runner at drift_dev. Kung walang generation, hindi posible na lumikha ng typed queries. Gayunpaman, para sa maliliit na proyekto, sinusuportahan ng Drift ang sqlparser — manual na pagsulat ng SQL files na may awtomatikong typing, ngunit ito ay nangangailangan pa rin ng generation stage.

Paano i-integrate ang Drift sa Riverpod?

Para sa integration sa Riverpod, gamitin ang drift_riverpod package. Nagbibigay ito ng mga provider para sa Database, DAO at Stream queries. Halimbawa: final tasksProvider = databaseProvider.select((db) => db.select(db.tasks).watch()) — awtomatikong nagre-rebuild ang UI kapag nagbago ang data.

Sinusuportahan ba ng Drift ang SQLite encryption?

Drift ay walang built-in encryption, ngunit sinusuportahan nito ang pag-connect ng custom sqlite3 libraries na may SEE (SQLite Encryption Extension). Para sa mobile platforms, gamitin ang sqflite_sqlcipher bilang QueryExecutor — gumagana ang Drift sa kahit anong SQLite implementation sa pamamagitan ng abstract QueryExecutor.

Buod

  • Drift — reactive ORM para sa Flutter at Dart na may compilation ng queries sa SQL sa build time
  • DSL syntax — Dart queries na may kumpletong type-safety at autocomplete sa IDE
  • Reactivity — Stream at auto-updating queries para sa awtomatikong UI updates
  • Cross-platform — Android, iOS, Web (WASM), macOS, Linux, Windows
  • Migrations — awtomatiko para sa simpleng pagbabago at manual SQL para sa kumplikado
  • Ecosystem — integration sa Riverpod (drift_riverpod) at BLoC (drift_bloc)
  • Rekomendasyon — piliin ang Drift para sa mga proyekto kung saan mahalaga ang reactivity, type-safety at suporta sa lahat ng Flutter platform

Gagawa kami ng mobile application na turnkey

Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.

Pag-usapan ang proyekto

Basahin din