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-এর নাম পরিবর্তন করে Drift করা হয়েছিল সংস্করণ 2.0 (2022)-এ। কারণ ছিল অন্যান্য প্রকল্পের সাথে নামের দ্বন্দ্ব এবং পুরানো কোড থেকে দূরত্ব তৈরি করার ইচ্ছা। API সামঞ্জস্যপূর্ণ ছিল: মাইগ্রেট করতে, শুধু import moor থেকে drift-এ পরিবর্তন করুন এবং নির্ভরতা আপডেট করুন।
Drift প্রদান করে: ডেটা পরিবর্তনের সময় স্বয়ংক্রিয় আপডেট সহ বিল্ট-ইন Stream কোয়েরি, রোলব্যাক সহ লেনদেন সমর্থন, rawQuery-এর মাধ্যমে কাস্টম SQL কোয়েরি, লজিক এনক্যাপসুলেশনের জন্য DAO প্যাটার্ন, ক্রস-প্ল্যাটফর্ম মাইগ্রেশন এবং drift_riverpod এবং drift_bloc প্যাকেজের মাধ্যমে Riverpod এবং BLoC-এর সাথে একীকরণ।
Drift কম্পাইল টাইমে কোড জেনারেশন ব্যবহার করে। ডেভেলপার @DataClass অ্যানোটেশন বা Table এক্সটেন্ড করে এমন Dart ক্লাসের মাধ্যমে টেবিল বর্ণনা করে। জেনারেটর হেল্পার ক্লাস তৈরি করে: Companion (ইনসার্ট/আপডেটের সময় নালযোগ্য ফিল্ডের জন্য), 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 স্বয়ংক্রিয়ভাবে আপডেট করে।
র SQL Drift-এ প্রয়োজন: কাস্টম SQLite ফাংশন (FTS5, JSON1), EXISTS-এর সাথে জটিল সাবকোয়েরি, INSERT OR REPLACE, CASE-এর সাথে মাস UPDATE, সেইসাথে কোয়েরি যেখানে কর্মক্ষমতা গুরুত্বপূর্ণ এবং DSL সর্বোত্তম নির্বাহ পরিকল্পনা তৈরি করে না। drift_dev-এর মাধ্যমে টাইপিং সমর্থন সহ .sql ফাইলে র 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-এর মাধ্যমে স্বয়ংক্রিয়ভাবে মাইগ্রেশন জেনারেট করতে পারে। যদি পরিবর্তন বিদ্যমান ডেটা ভাঙ্গে না (নালযোগ্য ফিল্ড যোগ করা), তাহলে আপনি ভার্সন চেক এবং 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 আরও প্ল্যাটফর্ম (ওয়েব সহ) সমর্থন করে এবং 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 অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন