Drift (Moor) — apa itu, ORM reaktif dan bekerja dengan database

Penulis: IT Sectr Diterbitkan: 2026-03-13 Waktu membaca: 9 mnt

Drift (sebelumnya Moor) — ORM reaktif untuk Flutter dan Dart, dibangun di atas SQLite dengan DSL sendiri untuk query. Berbeda dengan ORM tradisional, Drift mengkompilasi query Dart ke SQL pada tahap build, menghilangkan kesalahan runtime. Menurut Drift Docs, 2024, Drift menghasilkan hingga 40% lebih banyak kode daripada query SQL manual, tetapi sepenuhnya menghilangkan penulisan SQL manual, menggantikannya dengan sintaks Dart yang type-safe.

Utama

  • Drift — ORM reaktif dengan kompilasi query ke SQL pada tahap build
  • DSL-query — antarmuka fluent di Dart tanpa menulis string SQL
  • Reaktivitas — Stream dan query auto-updating untuk pembaruan UI real-time
  • Lintas platform — Android, iOS, Web, macOS, Linux, Windows
  • Migrasi — versioning otomatis dan migrasi manual melalui SQL

Apa itu Drift?

Drift — ORM untuk Dart dan Flutter, sebelumnya dikenal sebagai Moor. Dikembangkan oleh Simon Binder pada tahun 2019 dan telah melalui beberapa versi utama. Drift mengkompilasi query Dart ke SQL pada tahap build menggunakan drift_dev dan build_runner, memberikan keamanan tipe penuh dan menghilangkan kesalahan sintaks SQL saat runtime.

Berbeda dengan Floor, Drift menggunakan DSL (Domain-Specific Language) sendiri untuk membangun query — pengembang menulis di Dart, dan generator menerjemahkannya ke SQL. Ini memungkinkan IDE memeriksa sintaks, melengkapi otomatis field tabel, dan merefaktor model data tanpa takut merusak query.

Menurut Drift (2024), library ini digunakan di lebih dari 8000 proyek Flutter. Mendukung semua platform populer: Android melalui sqflite, iOS melalui sqflite, web melalui sqlite3 WASM, desktop melalui driver sqlite3 native.

Sejarah perubahan nama: Moor → Drift

Moor diganti nama menjadi Drift pada versi 2.0 (2022). Alasan — konflik nama dengan proyek lain dan keinginan untuk menjauh dari kode lama. API tetap kompatibel: untuk migrasi cukup mengganti import dari moor ke drift dan memperbarui dependensi.

Fitur utama

Drift menyediakan: query Stream bawaan dengan pembaruan otomatis saat data berubah, dukungan transaksi dengan rollback, query SQL kustom melalui rawQuery, pola DAO untuk enkapsulasi logika, migrasi lintas platform, dan integrasi dengan Riverpod dan BLoC melalui paket drift_riverpod dan drift_bloc.

Bagaimana cara kerja Drift?

Drift menggunakan generasi kode pada tahap kompilasi. Pengembang mendeskripsikan tabel melalui anotasi @DataClass atau kelas Dart yang memperluas Table. Generator membuat kelas pembantu: Companion (untuk field nullable saat insert/update), DriftDatabase (titik masuk) dan implementasi DAO.

Query SQLite tidak dijalankan langsung oleh Drift. Sebagai gantinya, pengembang menulis di Dart: select(tasks).where(tasks.priority.greaterThan(3)).build(). Generator menerjemahkan ini ke SQL, dan saat eksekusi Drift hanya mengirim query SQL yang sudah siap ke SQLite. Ini menggabungkan kenyamanan sintaks Dart dengan performa SQL native.

Arsitektur query

Drift mendukung dua mode query: DSL (direkomendasikan) dan raw SQL. Query DSL lebih aman — kompiler memeriksa nama field, tipe, dan kompatibilitas. Raw SQL diperlukan untuk query kompleks yang tidak dicakup oleh DSL: fungsi window, CTE rekursif, ekstensi SQLite spesifik.

Drift DSL vs SQL: perbandingan pendekatan

Drift menawarkan dua cara menulis query: Dart DSL (native) dan raw SQL (untuk kasus kompleks). DSL lebih disukai dalam 90% skenario: lebih aman, lebih mudah dibaca, dan mendukung refactoring. Raw SQL hanya digunakan ketika DSL tidak mencakup konstruksi yang diperlukan.

AspekDrift DSLRaw SQL di Drift
Keamanan tipePenuh (kompilasi)Tidak (runtime)
Auto-completeYa (IDE)Hanya di file sql
RefactoringOtomatisPencarian manual di string
JOIN kompleksDidukungKebebasan penuh
Fungsi windowTerbatasDukungan penuh
ReaktivitasBawaan (Stream)Melalui .watch()

Kapan menggunakan DSL

Drift DSL — cara kerja utama. Mencakup SELECT, INSERT, UPDATE, DELETE, WHERE, ORDER BY, LIMIT, JOIN dan pengelompokan. Untuk semua query CRUD tipikal, gunakan DSL: lebih pendek, lebih aman, dan secara otomatis memperbarui Stream saat ada perubahan.

Kapan menggunakan raw SQL

Raw SQL di Drift diperlukan untuk: fungsi SQLite kustom (FTS5, JSON1), subquery kompleks dengan EXISTS, INSERT OR REPLACE, UPDATE massal dengan CASE, serta query dimana performa kritis dan DSL tidak menghasilkan rencana eksekusi optimal. Raw SQL dapat ditulis di file .sql dengan dukungan typing melalui drift_dev.

Contoh kode dengan Drift

Drift menggunakan kelas yang memperluas Table atau anotasi @DataClass. Di bawah ini — contoh lengkap model Task dengan query melalui DSL, raw SQL dan pembaruan reaktif. Setelah menjalankan build_runner, semua kelas yang dihasilkan siap digunakan.

Mendefinisikan tabel dan database

Kelas Tasks memperluas Table dan mendefinisikan kolom. Setiap kolom adalah ekspresi bertipe Column. Parameter: withDefault() menetapkan nilai default, autoIncrement() menyediakan kenaikan otomatis. Database adalah kelas abstrak yang memperluas $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 operasi melalui DSL

Drift menghasilkan metode into(tasks).insert(), select(tasks), update(tasks) dan delete(tasks) untuk tabel. Semua operasi mengembalikan Future — bekerja dengan SQLite bersifat asinkron. Untuk melacak perubahan, gunakan .watch() sebagai ganti .get().

dart
// Menulis
await into(tasks).insert(TasksCompanion.insert(
    title: Value('Beli produk'),
    priority: Value(3),
));

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

// Pengamatan reaktif
select(tasks).watch().listen((tasksList) {
    // tasksList — List, diperbarui setiap kali tabel berubah
    updateUi(tasksList);
});

Raw SQL dengan hasil yang diketik

Untuk query kompleks, Drift memungkinkan menulis raw SQL sambil mempertahankan typing. Metode customSelect menerima string query dan mengembalikan hasil yang diketik melalui generator kode. Pendekatan ini menggabungkan fleksibilitas SQL dengan keamanan tipe 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")}');
}

Migrasi dan versioning di Drift

Drift mendukung migrasi otomatis (untuk perubahan sederhana) dan manual (untuk transformasi kompleks). Versi database diatur di konstruktor AppDatabase. Ketika versi tidak cocok, Drift menerapkan semua migrasi yang belum ditutup secara berurutan.

Migrasi otomatis

Untuk menambahkan kolom dengan nilai default, Drift dapat menghasilkan migrasi otomatis melalui MigrationStrategy. Jika perubahan tidak melanggar data yang ada (menambahkan field nullable), beforeOpen dapat digunakan dengan pemeriksaan versi dan eksekusi ALTER TABLE.

Migrasi manual

Untuk perubahan kompleks (mengganti nama tabel, menggabungkan data, mengubah tipe kolom) Drift memerlukan migrasi SQL manual. Migrasi ditentukan melalui parameter migrations di kelas database. Setiap migrasi adalah objek dengan nomor from/to dan query SQL.

Drift dan pengujian

Drift mendukung eksekusi dalam mode pengujian melalui NativeDatabase.memory(). Database dalam memori dibuat dari awal sebelum setiap pengujian dan dihancurkan setelahnya. Untuk mocking, gunakan paket mocktail dengan QueryExecutor yang di-mock. Drift juga menyediakan DatabaseTestHelper untuk pengujian integrasi dengan verifikasi migrasi dan query.

DAO pola DAO di Drift

Drift mendukung DAO (Data Access Object) melalui kelas abstrak dengan anotasi @DriftAccessor. DAO mengenkapsulasi query ke satu atau beberapa tabel dan dapat diuji terpisah dari database. Berbeda dengan query langsung melalui Database, DAO memungkinkan penggunaan kembali logika query antar bagian aplikasi yang berbeda dan menyederhanakan pengujian modular.

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

Pertanyaan yang sering diajukan

Apa perbedaan Drift dengan Floor?

Drift menggunakan DSL sendiri sebagai pengganti string SQL, memberikan keamanan tipe penuh dan auto-complete di IDE. Floor menggunakan string SQL dalam anotasi @Query. Drift juga mendukung lebih banyak platform (termasuk web) dan memiliki reaktivitas bawaan melalui Stream, sedangkan di Floor Stream harus dideklarasikan secara manual.

Apakah Drift mendukung migrasi tanpa kehilangan data?

Ya, Drift mendukung migrasi dengan mempertahankan data. Untuk menambahkan kolom, gunakan addColumn di Migration. Untuk transformasi kompleks (penggantian nama, penggabungan) tulis raw SQL di dalam migrasi. Jika migrasi tidak ditentukan, Drift membuat ulang database dengan kehilangan data saat ketidakcocokan skema.

Bisakah Drift digunakan tanpa build_runner?

Drift membutuhkan generasi kode melalui build_runner dan drift_dev. Tanpa generasi, query yang diketik tidak dapat dibuat. Namun, untuk proyek kecil Drift mendukung sqlparser — penulisan manual file SQL dengan typing otomatis, tetapi ini masih memerlukan tahap generasi.

Bagaimana cara mengintegrasikan Drift dengan Riverpod?

Untuk integrasi dengan Riverpod, gunakan paket drift_riverpod. Ini menyediakan provider untuk Database, DAO dan query Stream. Contoh: final tasksProvider = databaseProvider.select((db) => db.select(db.tasks).watch()) — UI secara otomatis dibangun ulang saat data berubah.

Apakah Drift mendukung enkripsi SQLite?

Drift tidak memiliki enkripsi bawaan, tetapi mendukung menghubungkan library sqlite3 kustom dengan SEE (SQLite Encryption Extension). Untuk platform mobile, gunakan sqflite_sqlcipher sebagai QueryExecutor — Drift bekerja dengan implementasi SQLite apa pun melalui QueryExecutor abstrak.

Ringkasan

  • Drift — ORM reaktif untuk Flutter dan Dart dengan kompilasi query ke SQL pada tahap build
  • Sintaks DSL — query Dart dengan keamanan tipe penuh dan auto-complete di IDE
  • Reaktivitas — Stream dan query auto-updating untuk pembaruan UI otomatis
  • Lintas platform — Android, iOS, Web (WASM), macOS, Linux, Windows
  • Migrasi — otomatis untuk perubahan sederhana dan SQL manual untuk yang kompleks
  • Ekosistem — integrasi dengan Riverpod (drift_riverpod) dan BLoC (drift_bloc)
  • Rekomendasi — pilih Drift untuk proyek di mana reaktivitas, keamanan tipe, dan dukungan untuk semua platform Flutter penting

Kami akan mengembangkan aplikasi seluler turnkey

IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.

Diskusikan proyek

Baca juga