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 इष्टतम निष्पादन योजना नहीं बनाता है। रॉ 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 के माध्यम से स्वचालित रूप से माइग्रेशन जनरेट कर सकता है। यदि परिवर्तन मौजूदा डेटा को नहीं तोड़ता है (नल करने योग्य फ़ील्ड जोड़ना), तो आप संस्करण जाँच और 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 एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें