Drift (əvvəlki adı Moor) — SQLite üzərində qurulmuş və öz DSL-i ilə Flutter və Dart üçün reaktiv ORM. Ənənəvi ORM-lərdən fərqli olaraq, Drift Dart sorğularını qurulma mərhələsində SQL-ə kompilyasiya edir və runtime səhvlərini aradan qaldırır. Drift Docs, 2024-yə görə, Drift əl ilə yazılan SQL sorğularından 40% çox kod yaradır, lakin SQL-in əl ilə yazılmasını tamamilə aradan qaldıraraq onu tip-təhlükəsiz Dart sintaksisi ilə əvəz edir.
Əsas
Drift — Dart və Flutter üçün ORM, əvvəllər Moor kimi tanınır. Simon Binder tərəfindən 2019-cu ildə hazırlanmışdır və bir neçə böyük versiya keçmişdir. Drift Dart sorğularını drift_dev və build_runner köməyi ilə qurulma mərhələsində SQL-ə kompilyasiya edir, bu da tam tip təhlükəsizliyi və runtime-da SQL sintaksis səhvlərinin qarşısını alır.
Floor-dan fərqli olaraq, Drift sorğuları qurmaq üçün öz DSL-indən (Domain-Specific Language) istifadə edir — tərtibatçı Dart-da yazır, generator isə bunu SQL-ə çevirir. Bu, IDE-yə sintaksisi yoxlamağa, cədvəl sahələrini avtomatik tamamlamağa və sorğunu pozmaq qorxusu olmadan məlumat modelini refaktor etməyə imkan verir.
Drift (2024) məlumatlarına görə, kitabxana 8000-dən çox Flutter layihəsində istifadə olunur. Bütün populyar platformaları dəstəkləyir: Android sqflite vasitəsilə, iOS sqflite vasitəsilə, web sqlite3 WASM vasitəsilə, desktop yerli sqlite3 sürücüsü vasitəsilə.
Moor 2.0 versiyasında (2022) Drift olaraq dəyişdirildi. Səbəb — digər layihələrlə ad qarışıqlığı və köhnə koddan uzaqlaşmaq istəyi. API uyğun qaldı: miqrasiya üçün import-u moor-dan drift-ə dəyişmək və asılılıqları yeniləmək kifayətdir.
Drift təmin edir: məlumat dəyişikliyində avtomatik yenilənən daxili Stream sorğuları, geri qaytarma ilə əməliyyatlar dəstəyi, rawQuery vasitəsilə fərdi SQL sorğuları, məntiqi inkapsulyasiya üçün DAO nümunəsi, platformalararası miqrasiyalar və drift_riverpod və drift_bloc paketləri vasitəsilə Riverpod və BLoC ilə inteqrasiya.
Drift kompilyasiya mərhələsində kod generasiyasından istifadə edir. Tərtibatçı cədvəlləri @DataClass annotasiyaları və ya Table-i genişləndirən Dart sinifləri vasitəsilə təsvir edir. Generator köməkçi siniflər yaradır: Companion (əlavə/yeniləmə zamanı nullable sahələr üçün), DriftDatabase (giriş nöqtəsi) və DAO tətbiqləri.
SQLite sorğuları Drift birbaşa yerinə yetirmir. Bunun əvəzinə tərtibatçı Dart-da yazır: select(tasks).where(tasks.priority.greaterThan(3)).build(). Generator bunu SQL-ə çevirir və icra zamanı Drift sadəcə hazır SQL sorğusunu SQLite-ə göndərir. Bu, Dart sintaksisinin rahatlığını yerli SQL performansı ilə birləşdirir.
Drift iki sorğu rejimini dəstəkləyir: DSL (tövsiyə olunur) və raw SQL. DSL sorğuları daha təhlükəsizdir — kompilyator sahə adlarını, tipləri və uyğunluğu yoxlayır. Raw SQL DSL ilə əhatə olunmayan mürəkkəb sorğular üçün lazımdır: pəncərə funksiyaları, rekursiv CTE, spesifik SQLite əlavələri.
Drift sorğu yazmağın iki üsulunu təklif edir: Dart DSL (yerli) və raw SQL (mürəkkəb hallar üçün). DSL 90% ssenarilər üçün üstünlük təşkil edir: daha təhlükəsiz, daha oxunaqlı və refaktoringi dəstəkləyir. Raw SQL yalnız DSL tələb olunan konstruksiyanı əhatə etmədikdə istifadə olunur.
| Aspekt | Drift DSL | Drift-də Raw SQL |
|---|---|---|
| Tip təhlükəsizliyi | Tam (kompilyasiya) | Yox (runtime) |
| Avtomatik tamamlama | Bəli (IDE) | Yalnız sql fayllarında |
| Refaktoring | Avtomatik | Sətrlər üzrə əl axtarışı |
| Mürəkkəb JOIN | Dəstəklənir | Tam sərbəstlik |
| Pəncərə funksiyaları | Məhdud | Tam dəstək |
| Reaktivlik | Daxili (Stream) | .watch() vasitəsilə |
Drift DSL — əsas iş üsulu. SELECT, INSERT, UPDATE, DELETE, WHERE, ORDER BY, LIMIT, JOIN və qruplaşdırmanı əhatə edir. Bütün tipik CRUD sorğuları üçün DSL-dən istifadə edin: daha qısa, daha təhlükəsiz və dəyişikliklərdə Stream-i avtomatik yeniləyir.
Raw SQL Drift-də aşağıdakılar üçün lazımdır: fərdi SQLite funksiyaları (FTS5, JSON1), EXISTS ilə mürəkkəb alt sorğular, INSERT OR REPLACE, CASE ilə kütləvi UPDATE, həmçinin performansın kritik olduğu və DSL-in optimal icra planı yaratmadığı sorğular. Raw SQL tipizasiya dəstəyi ilə drift_dev vasitəsilə .sql fayllarında yazıla bilər.
Drift Table-i genişləndirən siniflər və ya @DataClass annotasiyasından istifadə edir. Aşağıda — DSL, raw SQL və reaktiv yeniləmə ilə Task modelinin tam nümunəsi. build_runner işə salındıqdan sonra bütün yaradılan siniflər hazırdır.
Tasks sinfi Table-i genişləndirir və sütunları müyyən edir. Hər bir sütun Column<T> tipli ifadədir. Parametrlər: withDefault() standart dəyər təyin edir, autoIncrement() avtomatik artımı təmin edir. Verilənlər bazası $DriftDatabase-i genişləndirən abstrakt sinifdir.
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 cədvəllər üçün into(tasks).insert(), select(tasks), update(tasks) və delete(tasks) metodlarını yaradır. Bütün əməliyyatlar Future qaytarır — SQLite ilə iş asinxrondur. Dəyişiklikləri izləmək üçün .get() əvəzinə .watch() istifadə edin.
// Yazı
await into(tasks).insert(TasksCompanion.insert(
title: Value('Məhsulları al'),
priority: Value(3),
));
// Filterlə oxu
final highPriority = await (select(tasks)
..where((t) => t.priority.greaterThan(2))
..orderBy([(t) => OrderingTerm(expression: t.priority, mode: OrderingMode.desc)]))
.get();
// Reaktiv müşahidə
select(tasks).watch().listen((tasksList) {
// tasksList — List, cədvəl hər dəyişdikdə yenilənir
updateUi(tasksList);
});
Mürəkkəb sorğular üçün Drift raw SQL yazmağa imkan verir, eyni zamanda tipizasiyanı qoruyur. customSelect metodu sorğu sətrini qəbul edir və kod generatoru vasitəsilə tipləşdirilmiş nəticə qaytarır. Bu yanaşma SQL elastikliyini Drift tip təhlükəsizliyi ilə birləşdirir.
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 həm avtomatik miqrasiyaları (sadə dəyişikliklər üçün), həm də əl miqrasiyaları (mürəkkəb transformasiyalar üçün) dəstəkləyir. Verilənlər bazasının versiyası AppDatabase konstruktorunda təyin edilir. Versiya uyğunsuzluğunda Drift bütün bağlanmamış miqrasiyaları ardıcıl olaraq tətbiq edir.
Standart dəyərə malik sütun əlavə etmək üçün Drift MigrationStrategy vasitəsilə avtomatik miqrasiya yarada bilər. Dəyişiklik mövcud məlumatları pozmursa (nullable sahə əlavə etmək), versiya yoxlaması və ALTER TABLE icrası ilə beforeOpen istifadə edilə bilər.
Mürəkkəb dəyişikliklər (cədvəlin adını dəyişmək, məlumatları birləşdirmək, sütun tipini dəyişmək) üçün Drift əl SQL miqrasiyası tələb edir. Miqrasiyalar verilənlər bazası sinfində migrations parametri ilə təyin edilir. Hər miqrasiya from/to nömrələri və SQL sorğuları olan obyektdir.
Drift NativeDatabase.memory() vasitəsilə test rejimində işə salınmasını dəstəkləyir. Yaddaşda verilənlər bazası hər testdən əvvəl sıfırdan yaradılır və testdən sonra məhv edilir. Mock etmək üçün mocklanmış QueryExecutor ilə mocktail paketindən istifadə edin. Drift həmçinin miqrasiyaları və sorğuları yoxlamaq üçün inteqrasiya testləri üçün DatabaseTestHelper təqdim edir.
Drift @DriftAccessor annotasiyası ilə abstrakt siniflər vasitəsilə DAO (Data Access Object) dəstəkləyir. DAO bir və ya bir neçə cədvələ sorğuları inkapsulyasiya edir və verilənlər bazasından ayrı test edilə bilər. Birbaşa Database sorğularından fərqli olaraq, DAO sorğu məntiqinin tətbiqin müxtəlf hissələri arasında təkrar istifadəsinə imkan verir və modul testlərini sadələşdirir.
@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);
}));
}
}
Tez-tez verilən suallar
Drift SQL sətrləri əvəzinə öz DSL-indən istifadə edir, bu da tam tip təhlükəsizliyi və IDE-də avtomatik tamamlama təmin edir. Floor @Query annotasiyasında SQL sətrlərindən istifadə edir. Drift həmçinin daha çox platformanı (web daxil olmaqla) dəstəkləyir və Stream vasitəsilə daxili reaktivliyə malikdir, Floor-da isə Stream əl ilə elan edilməlidir.
Bəli, Drift məlumatları qoruyaraq miqrasiyaları dəstəkləyir. Sütun əlavə etmək üçün Migration-da addColumn istifadə edin. Mürəkkəb transformasiyalar (ad dəyişikliyi, birləşmə) üçün miqrasiya daxilində raw SQL yazın. Miqrasiya göstərilməyibsə, sxem uyğunsuzluğunda Drift məlumat itkisi ilə bazanı yenidən yaradır.
Drift build_runner və drift_dev vasitəsilə kod generasiyası tələb edir. Generasiya olmadan tipləşdirilmiş sorğular yaratmaq mümkün deyil. Bununla belə, kiçik layihələr üçün Drift sqlparser-i dəstəkləyir — avtomatik tipizasiya ilə əl SQL fayl yazmaq, lakin bu hələ də generasiya mərhələsi tələb edir.
Riverpod ilə inteqrasiya üçün drift_riverpod paketindən istifadə edin. O, Database, DAO və Stream sorğuları üçün provider-lər təqdim edir. Nümunə: final tasksProvider = databaseProvider.select((db) => db.select(db.tasks).watch()) — UI məlumat dəyişikliyində avtomatik yenidən qurulur.
Drift daxili şifrələməyə malik deyil, lakin SEE (SQLite Encryption Extension) ilə fərdi sqlite3 kitabxanalarını qoşmağı dəstəkləyir. Mobil platformalar üçün QueryExecutor kimi sqflite_sqlcipher istifadə edin — Drift abstrakt QueryExecutor vasitəsilə istənilən SQLite tətbiqi ilə işləyir.
Yekun
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun