Drift (önceden Moor) Flutter ve Dart için, SQLite üzerine kendi DSL'i ile inşa edilmiş reaktif bir ORM'dir. Geleneksel ORM'lerin aksine Drift, Dart sorgularını derleme zamanında SQL'e derleyerek çalışma zamanı hatalarını ortadan kaldırır. Drift Docs, 2024'e göre Drift, manuel SQL sorgularından %40 daha fazla kod üretir ancak manuel SQL yazmayı tamamen ortadan kaldırarak yerine tür güvenli Dart sözdizimi koyar.
Önemli noktalar
Drift Dart ve Flutter için bir ORM'dir, eskiden Moor olarak bilinirdi. 2019'da Simon Binder tarafından geliştirilmiştir ve o zamandan beri birkaç ana sürüm geçirmiştir. Drift, drift_dev ve build_runner kullanarak derleme zamanında Dart sorgularını SQL'e derler, tam tür güvenliği sağlar ve çalışma zamanında SQL sözdizimi hatalarını ortadan kaldırır.
Floor'un aksine Drift, sorguları oluşturmak için kendi DSL'ini (Alan Adına Özgü Dil) kullanır — geliştirici Dart'ta yazar ve üretici bunu SQL'e çevirir. Bu, IDE'nin sözdizimini kontrol etmesine, tablo alanlarını otomatik tamamlamasına ve sorguları bozma korkusu olmadan veri modelini yeniden düzenlemesine olanak tanır.
Drift (2024)'e göre, kütüphane 8000'den fazla Flutter projesinde kullanılmaktadır. Tüm popüler platformları destekler: Android sqflite ile, iOS sqflite ile, web sqlite3 WASM ile, masaüstü sqlite3 yerel sürücüsüyle.
Moor, sürüm 2.0'da (2022) Drift olarak yeniden adlandırıldı. Nedeni, diğer projelerle ad çakışması ve eski koddan uzaklaşma isteğiydi. API uyumlu kaldı: geçiş yapmak için import'u moor'dan drift'e değiştirin ve bağımlılıkları güncelleyin.
Drift şunları sağlar: veri değiştiğinde otomatik güncellemeli yerleşik Stream sorguları, geri alma destekli işlem desteği, rawQuery aracılığıyla özel SQL sorguları, mantık kapsüllemesi için DAO deseni, platformlar arası geçişler ve drift_riverpod ile drift_bloc paketleri aracılığıyla Riverpod ve BLoC ile entegrasyon.
Drift derleme zamanında kod oluşturma kullanır. Geliştirici, @DataClass ek açıklamaları veya Table'ı genişleten Dart sınıfları aracılığıyla tabloları tanımlar. Oluşturucu yardımcı sınıflar oluşturur: Companion (ekleme/güncelleme sırasında null yapılabilir alanlar için), DriftDatabase (giriş noktası) ve DAO uygulamaları.
Drift, SQLite sorgularını doğrudan yürütmez. Bunun yerine, geliştirici Dart'ta şöyle yazar: select(tasks).where(tasks.priority.greaterThan(3)).build(). Oluşturucu bunu SQL'e çevirir ve çalışma zamanında Drift hazır SQL sorgusunu SQLite'a gönderir. Bu, Dart sözdiziminin rahatlığını yerel SQL performansıyla birleştirir.
Drift iki sorgu modunu destekler: DSL (önerilen) ve ham SQL. DSL sorguları yazması daha güvenlidir — derleyici alan adlarını, türleri ve uyumluluğu kontrol eder. Ham SQL, DSL tarafından kapsanmayan karmaşık sorgular için gereklidir: pencere işlevleri, özyinelemeli CTE'ler, belirli SQLite uzantıları.
Drift sorgu yazmak için iki yol sunar: Dart DSL (yerel) ve ham SQL (karmaşık durumlar için). DSL, senaryoların %90'ı için tercih edilir: daha güvenlidir, daha okunabilirdir ve yeniden düzenlemeyi destekler. Ham SQL yalnızca DSL gerekli yapıyı kapsamadığında kullanılır.
| Yön | Drift DSL | Drift'te ham SQL |
|---|---|---|
| Tür güvenliği | Tam (derleme) | Hayır (çalışma zamanı) |
| Otomatik tamamlama | Evet (IDE) | Yalnızca sql dosyalarında |
| Yeniden düzenleme | Otomatik | Manuel dize arama |
| Karmaşık JOIN'ler | Desteklenir | Tam özgürlük |
| Pencere işlevleri | Sınırlı | Tam destek |
| Tepkisellik | Yerleşik (Stream) | .watch() aracılığıyla |
Drift DSL ana çalışma şeklidir. SELECT, INSERT, UPDATE, DELETE, WHERE, ORDER BY, LIMIT, JOIN ve gruplamayı kapsar. Tüm tipik CRUD sorguları için DSL kullanın: daha kısa, daha güvenlidir ve değişikliklerde Stream'i otomatik olarak günceller.
Drift'te ham SQL şunlar için gereklidir: özel SQLite işlevleri (FTS5, JSON1), EXISTS ile karmaşık alt sorgular, INSERT OR REPLACE, CASE ile toplu UPDATE ve performansın kritik olduğu ve DSL'nin en uygun yürütme planını üretmediği sorgular. Ham SQL, drift_dev aracılığıyla tür desteğiyle .sql dosyalarına yazılabilir.
Drift Table'ı genişleten sınıfları veya @DataClass ek açıklamasını kullanır. Aşağıda DSL, ham SQL ve reaktif güncelleme yoluyla sorgular içeren Task modelinin tam bir örneği verilmiştir. build_runner çalıştırıldıktan sonra oluşturulan tüm sınıflar hazırdır.
Tasks sınıfı Table'ı genişletir ve sütunları tanımlar. Her sütun Column<T> türünde bir ifadedir. Parametreler: withDefault() varsayılan bir değer belirler, autoIncrement() otomatik artışı belirler. Veritabanı, $DriftDatabase'i genişleten soyut bir sınıftır.
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);
}
Drift, tablolar için into(tasks).insert(), select(tasks), update(tasks) ve delete(tasks) yöntemlerini oluşturur. Tüm işlemler Future döndürür — SQLite ile çalışmak eş zamansızdır. Değişiklikleri izlemek için .get() yerine .watch() kullanın.
// Ekle
await into(tasks).insert(TasksCompanion.insert(
title: Value('Bakkal alışverişi yap'),
priority: Value(3),
));
// Filtreyle okuma
final highPriority = await (select(tasks)
..where((t) => t.priority.greaterThan(2))
..orderBy([(t) => OrderingTerm(expression: t.priority, mode: OrderingMode.desc)]))
.get();
// Reaktif izleme
select(tasks).watch().listen((tasksList) {
// tasksList — List, tablo her değiştiğinde güncellenir
updateUi(tasksList);
});
Karmaşık sorgular için Drift, türlemeyi korurken ham SQL yazmaya izin verir. customSelect yöntemi bir sorgu dizesi alır ve kod oluşturucu aracılığıyla türlenmiş bir sonuç döndürür. Bu yaklaşım, SQL esnekliğini Drift tür güvenliğiyle birleştirir.
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")}');
}
Drift hem otomatik geçişleri (basit değişiklikler için) hem de manuel geçişleri (karmaşık dönüşümler için) destekler. Veritabanı sürümü AppDatabase yapıcısında ayarlanır. Sürüm eşleşmezse Drift, bekleyen tüm geçişleri sırayla uygular.
Varsayılan değere sahip bir sütun eklemek için Drift, MigrationStrategy aracılığıyla otomatik olarak bir geçiş oluşturabilir. Değişiklik mevcut verileri bozmuyorsa (null yapılabilir alan ekleme), sürüm kontrolü ve ALTER TABLE yürütmesiyle beforeOpen kullanabilirsiniz.
Karmaşık değişiklikler (tabloyu yeniden adlandırma, verileri birleştirme, sütun türünü değiştirme) için Drift, manuel SQL geçişi gerektirir. Geçişler, veritabanı sınıfındaki migrations parametresi aracılığıyla belirtilir. Her geçiş, from/to numaraları ve SQL sorguları olan bir nesnedir.
Drift, NativeDatabase.memory() aracılığıyla test modunda çalışmayı destekler. Bellek içi veritabanı her testten önce sıfırdan oluşturulur ve sonra yok edilir. Taklit için, taklit edilmiş bir QueryExecutor ile mocktail paketini kullanın. Drift ayrıca geçiş ve sorgu doğrulamasıyla entegrasyon testleri için DatabaseTestHelper sağlar.
Drift, @DriftAccessor ek açıklamasıyla soyut sınıflar aracılığıyla DAO'yu (Veri Erişim Nesnesi) destekler. DAO, bir veya daha fazla tabloya yönelik sorguları kapsüller ve veritabanından ayrı olarak test edilebilir. Database aracılığıyla doğrudan sorguların aksine DAO, sorgu mantığını uygulamanın farklı bölümleri arasında yeniden kullanmaya olanak tanır ve birim testlerini basitleştirir.
@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);
}));
}
}
Sıkça sorulan sorular
Drift, SQL dizeleri yerine kendi DSL'ini kullanarak tam tür güvenliği ve IDE'de otomatik tamamlama sağlar. Floor, @Query ek açıklamasında SQL dizeleri kullanır. Drift ayrıca daha fazla platformu (web dahil) destekler ve Stream aracılığıyla yerleşik tepkiselliğe sahiptir, oysa Floor'da Stream'in manuel olarak bildirilmesi gerekir.
Evet, Drift veri korumalı geçişleri destekler. Sütun eklemek için Migration'da addColumn kullanın. Karmaşık dönüşümler (yeniden adlandırma, birleştirme) için geçişin içine ham SQL yazın. Hiçbir geçiş belirtilmezse Drift, şema eşleşmediğinde veritabanını veri kaybıyla yeniden oluşturur.
Drift, build_runner ve drift_dev aracılığıyla kod oluşturma gerektirir. Oluşturma olmadan türlenmiş sorgular oluşturmak imkansızdır. Ancak küçük projeler için Drift, sqlparser'ı destekler — otomatik türlemeyle manuel SQL dosyası yazma, ancak bu yine de bir oluşturma adımı gerektirir.
Riverpod ile entegrasyon için drift_riverpod paketini kullanın. Database, DAO ve Stream sorguları için sağlayıcılar sunar. Örnek: final tasksProvider = databaseProvider.select((db) => db.select(db.tasks).watch()) — veri değiştiğinde UI otomatik olarak yeniden oluşturulur.
Drift yerleşik şifrelemeye sahip değildir, ancak SEE (SQLite Encryption Extension) ile özel sqlite3 kütüphanelerini bağlamayı destekler. Mobil platformlar için QueryExecutor olarak sqflite_sqlcipher kullanın — Drift, soyut QueryExecutor aracılığıyla herhangi bir SQLite uygulamasıyla çalışır.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun