Drift (پہلے Moor) Flutter اور Dart کے لیے ایک ریاکٹو ORM ہے، جو SQLite پر اپنے DSL کے ساتھ بنایا گیا ہے۔ روایتی ORM کے برعکس، Drift بیلڈ ٹائم پر Dart کوئریوں کو SQL میں کمپائل کرتا ہے، رن ٹائم کی غلطیوں کو ختم کرتا ہے۔ Drift Docs, 2024 کے مطابق، Drift دستی SQL کوئریوں کے مقابلے میں 40% زیادہ کوڈ تیار کرتا ہے، لیکن دستی SQL نویسی کو مکمل طور پر ختم کرتا ہے، اسے ٹائپ محفوظ Dart سینٹیکس سے بدل دیتا ہے۔
اہم نکات
Drift Dart اور Flutter کے لیے ایک ORM ہے، جو پہلے Moor کے نام سے جانا جاتا تھا۔ اسے Simon Binder نے 2019 میں تیار کیا تھا اور تب سے یہ کئی بڑے ورشنز سے گزرا ہے۔ Drift drift_dev اور build_runner کا استعمال کرکے بیلڈ ٹائم پر Dart کوئریوں کو SQL میں کمپائل کرتا ہے، مکمل ٹائپ تحفظ فراہم کرتا ہے اور رن ٹائم پر SQL سینٹیکس کی غلطیوں کو ختم کرتا ہے۔
Floor کے برعکس، Drift کوئریز بنانے کے لیے اپنی DSL (ڈومین مخصوصی زبان) استعمال کرتا ہے — ڈیولپر Dart میں لکھتا ہے، اور جنریٹر اسے SQL میں ترجمہ کرتا ہے۔ یہ IDE کو سینٹیکس چیک کرنے، ٹیبل فیلڈز کو خودکار مکمل کرنے، اور کوئریز کو توڑنے کے خوف کے بغیر ڈیٹا ماڈل کو ری فیکٹر کرنے کی اجازت دیتا ہے۔
Drift (2024) کے مطابق، یہ لائبریری 8000 سے زائد Flutter پروجیکٹس میں استعمال ہوتی ہے۔ یہ تمام مقبول پلیٹ فارمز کو سپورٹ کرتی ہے: Android sqflite کے ذریعے، iOS sqflite کے ذریعے، web sqlite3 WASM کے ذریعے، ڈیسک ٹاپ sqlite3 نیٹو ڈرائیور کے ذریعے۔
Moor کا نام بدل کر ورشن 2.0 (2022) میں Drift رکھا گیا تھا۔ وجہ دیگر پروجیکٹس کے ساتھ نام کا ٹکراو اور پرانے کوڈ سے دوری اختیار کرنے کی خواہش تھی۔ API مطابق رہی: مائگریشن کے لیے، صرف import کو moor سے drift میں بدلیں اور انحصارات کو اپڈیٹ کریں۔
Drift فراہم کرتا ہے: ڈیٹا بدلنے پر خودکار اپڈیٹ کے ساتھ بیلٹ ان Stream کوئریز، رول بیک کے ساتھ ٹرانزیکشن کی سپورٹ، rawQuery کے ذریعے کسٹم SQL کوئریز، منطق کی ینکپسیولیشن کے لیے DAO پیٹرن، کروس پلیٹ فارم مائگریشنز، اور drift_riverpod اور drift_bloc پیکیجز کے ذریعے Riverpod اور BLoC کے ساتھ انضمام۔
Drift کمپائل ٹائم پر کوڈ جنریشن کا استعمال کرتا ہے۔ ڈیولپر @DataClass اینوٹیشنز یا Table کو بڑھانے والے Dart کلاسز کے ذریعے ٹیبلز کی وضاحت کرتا ہے۔ جنریٹر مددگار کلاسز بناتا ہے: Companion (درج/اپڈیٹ کے دوران null قابل فیلڈز کے لیے)، DriftDatabase (داخلے کا مقام)، اور DAO نفاذ۔
Drift سیدھا SQLite کوئریز پر عمل نہیں کرتا۔ اس کے بجای، ڈیولپر Dart میں لکھتا ہے: select(tasks).where(tasks.priority.greaterThan(3)).build()۔ جنریٹر اسے SQL میں ترجمہ کرتا ہے، اور رن ٹائم پر Drift تیار SQL کوئری کو SQLite کو بھیجتا ہے۔ یہ Dart سینٹیکس کی سهولت کو مقامی SQL کارکردگی کے ساتھ جوڑتا ہے۔
Drift دو کوئری موڈز کو سپورٹ کرتا ہے: DSL (تجویز شدہ) اور خام SQL۔ DSL کوئریز لکھنا محفوظ ہے — کمپائلر فیلڈ کے ناموں، اقسام اور مطابقت کو چیک کرتا ہے۔ خام SQL پیچیدہ کوئریز کے لیے ضروری ہے جو DSL سے کور نہیں ہوتیں: ونڈو فنکشنز، ریکرسو CTE، مخصوص SQLite اکسٹینشنز۔
Drift کوئریز لکھنے کے دو طریقے فراہم کرتا ہے: Dart DSL (مقامی) اور خام SQL (پیچیدہ معاملات کے لیے)۔ DSL 90% مناظروں کے لیے بہتر ہے: یہ محفوظ، زیادہ پڑھنے قابل، اور ری فیکٹرنگ کو سپورٹ کرتا ہے۔ خام SQL صرف اس وقت استعمال ہوتا ہے جب DSL مطلوبہ تعمیر کو کور نہیں کرتا۔
| پہلو | Drift DSL | Drift میں خام SQL |
|---|---|---|
| ٹائپ تحفظ | مکمل (کمپائل ٹائم) | نہیں (رن ٹائم) |
| خودکار مکملی | ہاں (IDE) | صرف sql فائلوں میں |
| ری فیکٹرنگ | خودکار | دستی سٹرنگ تلاش |
| پیچیدہ JOIN | سپورٹ شدہ | مکمل آزادی |
| ونڈو فنکشنز | محدود | مکمل سپورٹ |
| ریاکٹویٹی | بیلٹ ان (Stream) | .watch() کے ذریعے |
Drift DSL کام کا بنیادی طریقہ ہے۔ یہ SELECT، INSERT، UPDATE، DELETE، WHERE، ORDER BY، LIMIT، JOIN اور گروپنگ کو کور کرتا ہے۔ تمام معمولی CRUD کوئریز کے لیے، DSL استعمال کریں: یہ چہوٹا، محفوظ ہے اور تبدیلیوں پر Stream کو خودکار اپڈیٹ کرتا ہے۔
Drift میں خام SQL اس کے لیے ضروری ہے: کسٹم SQLite فنکشنز (FTS5، JSON1)، EXISTS کے ساتھ پیچیدہ ذیلی کوئریز، INSERT OR REPLACE، CASE کے ساتھ بلک UPDATE، اور وہ کوئریز جہاں کارکردگی اہم ہے اور DSL بہترین پیروگرام تیار نہیں کرتا۔ خام SQL drift_dev کے ذریعے ٹائپنگ کی سپورٹ کے ساتھ .sql فائلوں میں لکھا جا سکتا ہے۔
Drift Table کو بڑھانے والے کلاسز یا @DataClass اینوٹیشن کا استعمال کرتا ہے۔ ذیل DSL، خام SQL، اور ریاکٹو اپڈیٹ کے ذریعے کوئریز کے ساتھ Task ماڈل کی ایک مکمل مثال ہے۔ build_runner چلانے کے بعد، تمام جنریٹ کردہ کلاسز تیار ہیں۔
Tasks کلاس Table کو بڑھاتا ہے اور کالمز کی وضاحت کرتا ہے۔ ہر کالم Column<T> قسم کا ایک اظہار ہے۔ پیرامیٹرز: withDefault() ایک ڈفالٹ قیمت مقرر کرتا ہے، autoIncrement() خودکار اضافہ مقرر کرتا ہے۔ ڈیٹابیس ایک تجریدی کلاس ہے جو $DriftDatabase کو بڑھاتا ہے۔
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 ٹیبلز کے لیے طریقے into(tasks).insert()، select(tasks)، update(tasks) اور delete(tasks) تیار کرتا ہے۔ تمام کارروائیاں Future واپس کرتی ہیں — SQLite کے ساتھ کام غیر هم آہنگ ہے۔ تبدیلیوں کو ٹریک کرنے کے لیے، .get() کے بجائے .watch() استعمال کریں۔
// درج کریں
await into(tasks).insert(TasksCompanion.insert(
title: Value('گروسری خریدیں'),
priority: Value(3),
));
// فلٹر کے ساتھ پڑھیں
final highPriority = await (select(tasks)
..where((t) => t.priority.greaterThan(2))
..orderBy([(t) => OrderingTerm(expression: t.priority, mode: OrderingMode.desc)]))
.get();
// ریاکٹو مشاہدہ
select(tasks).watch().listen((tasksList) {
// tasksList — List, ٹیبل کی ہر تبدیلی پر اپڈیٹ ہوتا ہے
updateUi(tasksList);
});
پیچیدہ کوئریز کے لیے، Drift ٹائپنگ برقرار رکھتے ہوئے خام SQL لکھنے کی اجازت دیتا ہے۔ customSelect طریقہ ایک کوئری سٹرنگ لیتا ہے اور کوڈ جنریٹر کے ذریعے ایک ٹائپ شدہ نتیجہ واپس کرتا ہے۔ یہ طریقہ SQL کی لچیلی کو Drift کی ٹائپ تحفظ کے ساتھ جوڑتا ہے۔
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 خودکار مائگریشنز (سادہ تبدیلیوں کے لیے) اور دستی مائگریشنز (پیچیدہ تبدیلیوں کے لیے) دونوں کو سپورٹ کرتا ہے۔ ڈیٹابیس کا ورشن AppDatabase کنسٹرکٹر میں مقرر کیا جاتا ہے۔ جب ورشن مطابق نہیں ہوتا، Drift تمام زیری مائگریشنز کو بار ادار نفاذ کرتا ہے۔
ایک ڈفالٹ قیمت کے ساتھ کالم جوڑنے کے لیے، Drift MigrationStrategy کے ذریعے خودکار مائگریشن تیار کر سکتا ہے۔ اگر تبدیل موجودہ ڈیٹا کو خراب نہیں کرتی (null قابل فیلڈ کا اضافہ)، آپ ورشن چیک اور ALTER TABLE پر عمل کے ساتھ beforeOpen استعمال کر سکتے ہیں۔
پیچیدہ تبدیلیوں (ٹیبل کا نام بدلنا، ڈیٹا کو ضم کرنا، کالم کی قسم بدلنا) کے لیے، Drift کو دستی SQL مائگریشن کی ضرورت ہے۔ مائگریشنز ڈیٹابیس کلاس میں migrations پیرامیٹر کے ذریعے متعین کی جاتی ہیں۔ ہر مائگریشن from/to نمبر اور SQL کوئریز کا ایک آبیڠیکٹ ہے۔
Drift NativeDatabase.memory() کے ذریعے ٹیسٹ موڈ میں چلنے کی سپورٹ کرتا ہے۔ میمری میں ڈیٹابیس ہر ٹیسٹ سے پہلے شروع سے بنائی جاتی ہے اور بعد میں ختم کر دی جاتی ہے۔ ماکنگ کے لیے، ماک کیے گئے QueryExecutor کے ساتھ mocktail پیکیج استعمال کریں۔ Drift مائگریشن اور کوئری تصدیق کے ساتھ انٹیگریشن ٹیسٹس کے لیے DatabaseTestHelper بھی فراہم کرتا ہے۔
Drift @DriftAccessor اینوٹیشن کے ساتھ تجریدی کلاسز کے ذریعے DAO (ڈیٹا اکسس آبیڠیکٹ) کو سپورٹ کرتا ہے۔ DAO ایک یا زائد ٹیبلز کے لیے کوئریز کو ینکپسیوڳ کرتا ہے اور ڈیٹابیس سے علاوہ ٹیسٹ کیا جا سکتا ہے۔ Database کے ذریعے سیدھے کوئریز کے برعکس، DAO ایپلیکیشن کے مختلف حصوں کے درمیان کوئری لاجک کو دوبارہ استعمال کرنے کی اجازت دیتا ہے اور یونٹ ٹیسٹنگ کو آسان بناتا ہے۔
@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);
}));
}
}
اکثر پوچے جانے والے سوالات
Drift SQL سٹرنگز کے بجائے اپنا DSL استعمال کرتا ہے، جو مکمل ٹائپ تحفظ اور IDE میں خودکار مکملی فراہم کرتا ہے۔ Floor @Query اینوٹیشن میں SQL سٹرنگز استعمال کرتا ہے۔ Drift زیادہ پلیٹ فارمز (web سمیٹ) کو بھی سپورٹ کرتا ہے اور Stream کے ذریعے بیلٹ ان ریاکٹویٹی رکھتا ہے، جبکہ Floor میں Stream کو دستی طور پر مقرر کرنا پڑتا ہے۔
جی ہاں، Drift ڈیٹا تحفظ کے ساتھ مائگریشن کی حمایت کرتا ہے۔ کالم جوڑنے کے لیے، Migration میں addColumn استعمال کریں۔ پیچیدہ تبدیلیوں (نام بدلنا، ضم کرنا) کے لیے، مائگریشن کے اندر خام SQL لکھیں۔ اگر کئی مائگریشن متعین نہیں کی گئی، تو Drift اسکیما کے متابق نہ ہونے پر ڈیٹا کے نقصان کے ساتھ ڈیٹابیس کو دوبارہ بناتا ہے۔
Drift کو build_runner اور drift_dev کے ذریعے کوڈ جنریشن کی ضرورت ہے۔ جنریشن کے بغیر، ٹائپ شدہ کوئریز بنانا ناممکن ہے۔ تاہم، چہوٹے پروجیکٹس کے لیے، Drift sqlparser کو سپورٹ کرتا ہے — خودکار ٹائپنگ کے ساتھ دستی SQL فائل لکھنا، لیکن اس کے لیے اب بھی ایک جنریشن مرحلہ درکار ہے۔
Riverpod کے ساتھ انضمام کے لیے، drift_riverpod پیکیج استعمال کریں۔ یہ Database، DAO اور Stream کوئریز کے لیے پروائیڈرز فراہم کرتا ہے۔ مثال: final tasksProvider = databaseProvider.select((db) => db.select(db.tasks).watch()) — ڈیٹا بدلنے پر UI خودکار طور پر دوبارہ بنتا ہے۔
Drift میں بیلٹ ان خفنگی نہیں ہے، لیکن یہ SEE (SQLite Encryption Extension) کے ساتھ کسٹم sqlite3 لائبریریز کو منسلک کرنے کی حمایت کرتا ہے۔ موبائل پلیٹ فارمز کے لیے، QueryExecutor کے طور پر sqflite_sqlcipher استعمال کریں — Drift تجریدی QueryExecutor کے ذریعے کسی بھی SQLite نفاذ کے ساتھ کام کرتا ہے۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں