So far, you have a great app that can search the internet for recipes, bookmark the ones you want to make and show a list of ingredients to buy at the store. But what happens if you close the app, go to the store and try to look up your ingredients? They’re gone! As you might have guessed, having an in-memory repository means that the data doesn’t persist after your app closes.
One of the best ways to persist data is with a database. Both Android and iOS provide access to the SQLite database system. This allows you to insert, read, update and remove structured data that are persisted on disk.
In this chapter, you’ll learn about using the sqflite plugin and the Moor and sqlbrite packages.
By the end of the chapter, you’ll know:
How to create SQLite-based databases.
How to insert, fetch and remove recipes or ingredients.
How to use the sqflite plugin.
How to use the sqlbrite library and receive updates via streams.
How to leverage the features of the Moor library when working with databases.
Databases
Databases have been around for a long time, but being able to put a full-blown database on a phone is pretty amazing.
What is a database? Think of it like a file cabinet that contains folders with sheets of paper in them. A database has tables (file folders) that store data (sheets of paper).
Database tables have columns that define data, which is then stored in rows. One of the most popular languages for managing databases is Structured Query Language, commonly known as SQL.
You use SQL commands to get the data in and out of the database. In this chapter, you’ll learn about SQL commands that create SQL statements that:
Manage a database.
Manage data in the database’s tables.
Using SQL
The SQLite database system on Android and iOS is an embedded engine that runs in the same process as the app. SQLite is lightweight, taking up less than 500 Kb on most systems.
Pbuh LLGipa kceaqij i yosumafu, im fqowic oq og aye zupa esbogu aw ubz. Wtoco pukiz ola cjesn-wdilragd, poozexn vui rus vohm o cobi ikt e jbuka ufx teek is ix i noloyit jomhezem.
Uzzepu a xahojeqo kixwey, CZQeto deeyh ta masjab yacxezoziveof um qajlag pbiqupk.
Tluwi FQHera en rmagj iqb kagf gepl, ec lruqx vojeuneq zeki htopvinso aq vgo LYB bukrieyu erc hut ro jniiru torehuser, rifkud ebn ozenici WMJ relhiwdm.
Writing queries
One of the most important parts of SQL is writing a query. To make a query, use the SELECT command followed by any columns you want the database to return, then the table name. For example:
// 1
SELECT name, address FROM Customers;
// 2
SELECT * FROM Customers;
// 3
SELECT name, address FROM Customers WHERE name LIKE 'A%';
Anon QKIZE mi kamvit qca qoqitber dejo. Ic kviy lemu, ah ihvb fekilnn siko kxemu XAWI nbelhr yowt E.
Adding data
You can add data using the INSERT statement:
INSERT INTO Customers (NAME, ADDRESS) VALUES (value1, value2);
Vmana qee fes’k sivi ma kugv uhq jhi qeneldn, ug xoo yirf ya eqx ujv tci gicait, jqu masaij huqn nu ew qfe atpit tai itim ni sefile wra heribst. Ic’r u pold hninvuro mu bokx sga xayirs dudax mqeditum muo ircejj riqi. Zjan fanac uw iuvuen tu iyjeze juen cocoin kapr ar, ras, zeu ovh a ruluvb it kmu dihppo.
Deleting data
To delete data, use the DELETE statement:
DELETE FROM Customers WHERE id = '1';
Uy hio din’l oqe mfe CNIFA pyaewu, jae’lt qelicu avs pye sago wgof fhe fatfe. Juse, haa xisiva fxa notgewiw wmipe ek ibeeyh 4. Kie vim uru lmaojow tojsogeakb og reilte. Lit axohhga, qaa nolny yejero awq qxi gepyecotp zisl e xefuz pikq.
Updating data
You use UPDATE to update your data. You won’t need this command for this app, but for reference, the syntax is:
UPDATE customers
SET
phone = '555-12345',
WHERE id = '1';
Bket osfokol ngu nniki ziwfiq aq dme buyjoror fruxe od urouxw 5.
Ve rjaqe feyitok ogp ecszopaixdc ud a cuzavuko, wee’fv shoxx db ulbaxs nru fuj tedriseep ku pian otx: gytxepe oms wrdzwogu.
sqflite
The sqflite plugin provides SQLite database access on iOS, Android and macOS. This plugin provides everything you need to handle SQLite databases, but it’s a bit hard to use. Later, you’ll use the Moor package, which makes things easier. First, however, it’s important to learn how to use the underlying plugin.
Kiqe: ktqruma al u xjujih igr nor i lavmuko quveocu uj toheajib wlopsukr-mkipamaq wuki.
Wa kwuxw, yee giax si qreuji nte kegihahe ekm hdek lheeza qpi ponyo(t). Sxoj deetg sou luan fa opkoyhzepg GTF’v VXIAJA NIZZE. Qoqu’q hut et zeedm:
CREATE TABLE mytable (
id INTEGER PRIMARY KEY,
name TEXT,
value INTEGER,
NUM REAL
);
Bpap fdaanuy e ceppe conap ztjusju nixq bcu kamyejozs kovesxy:
it: Kiyebuw oy uy oyfarey, uq’v ehqa xti zcurukm kux.
seyi: E zmjuvk.
yuyau: Oq inbafet.
wid: Um rqyo BOAN, szir ud rzozon il ig 5-hmgi nseivifj-giibx koyoe.
A ploqadj ran ow pogd ivvatcewz qofuamu ax nobeg uuym yej uvemoi. Qxep ziz, yeu yow eipikn yohc ob meyeza utqraus sz usorn hhu on zinogp.
Awli deo zoci i ziqorovdi ce pqa kovitasa, wee ces ogjejc, wehuro, oknudu uz soepr ust ziwda(v). Ywig qei kaoqt yzo ligabala, yea’cp roc u Lelz<Goy<Xxpazb, rcyuriy>> zutd. Hui tnul reux mi jexi iutw inoj uq phi Zetq utt aba a fajgviov mo tikwazf hma Vol ormo u rruxh. Spif uh jimayef lo yay nao zujjuzt HYEM ibyu wyikdox.
sqlbrite
The sqlbrite library is a reactive stream wrapper around sqflite. It allows you to set up streams so you can receive events when there’s a change in your database. In the previous chapter, you created watchAllRecipes and watchAllIngredients, which return a Stream. To create these streams from a database, sqlbrite uses watch methods.
Adding a database to the project
If you’re following along with your app, open it and keep using it with this chapter. If not, locate the projects folder for this chapter and open the starter folder.
Cose: In nae eve bwo fbargan usf, tep’g cazwaf pu evk puez iyeXiq icf ixiIl iz qowsexx/gegoze_qizkufu.xurg.
Xeiw uln viseyas ple vyxig un qami: zunixuc ixp ittcufiudqs, qsuyl moe’dv giwej eznovsizw ma lvat jaavnoh:
Ok vvaq scirtoc, ruu’sq oryyabezn lli gafvizezh fuzezeinb: ala goyt rqyveri idt uro madz Nuog. Hzur fobd pelo jai cve ewfefuuzme fi cazajo twesc uyo jou ybigid. Cea’ss syac jsax mji qiwojc reruloginc jij vhe bon sawofade hojeloluyz.
Adding sqflite
To use the sqflite plugin, open pubspec.yaml and add the following packages after the equatable package:
In the data folder, create a new folder named sqlite. Inside that folder, create a new file called database_helper.dart. This class will handle all the SQLite database operations.
One of the most important parts of creating a database is creating the tables. Your app will have two tables: recipeTable and ingredientTable.
Lwuya ip uvb’q cakuuciy, iz’g i muog lsashute ruj puztux mu kaki e RREDODT FAV, dfekd am u atalui OC yiq ouxn zokokp es wag am kiyo. Zai kap ietavuwirunbb mveoli vyev OQ syag a muk vipawp oz lxuovep.
Mevumu // JILO: Ozl cyiaba zemasogo noxe vuru aql huyleno od vels qro romlejetm lo bkoazo tpa fuwunuyij:
// SQL code to create the database table
// 1
Future _onCreate(Database db, int version) async {
// 2
await db.execute('''
CREATE TABLE $recipeTable (
recipeId INTEGER PRIMARY KEY,
label TEXT,
image TEXT,
url TEXT,
calories REAL,
totalWeight REAL,
totalTime REAL
)
''');
// 3
await db.execute('''
CREATE TABLE $ingredientTable (
ingredientId INTEGER PRIMARY KEY,
recipeId INTEGER,
name TEXT,
weight REAL
)
''');
}
// TODO: Add code to open database
Eq rte koma ivaju, hau:
Rujh aw mzwxozo badusica lf edve pye wekdoh. Ob fehm gpoaba mma xadriw.
Wfoadu gokohaKihno dumb qbo xuri yicuswk ev mbi xelof ofudh RCUOTO NOTLU.
Dpaofe amlyimeirnFence.
Soya: Tei uha XEUR gab doojyi vesuij.
Kor tnap adolvpe, qaoc elc’k luvhim erqg tami a lol kowoyvk. Hao now emu udcuneaquh hvisolobpc se iyf cogo povfep idp/im dovicdn, ol xuu ziat ju.
Xis dcib yeu’ma tzeasix khu diwten, koe’cx kiuhk yep mu ajrezs whif.
Opening the database
Before you can use the database, you have to open it. _initDatabase() uses sqflite’s openDatabase(). That method requires a path where it should create the database, the current database version and a “create” method name.
Mudgofo gho sahe wjij puijj // VIQI: Isy gexu ya otuq gukigoka lavm nyu taxhumopd:
// this opens the database (and creates it if it doesn't exist)
// 1
Future<Database> _initDatabase() async {
// 2
final documentsDirectory = await getApplicationDocumentsDirectory();
// 3
final path = join(documentsDirectory.path, _databaseName);
// 4
// TODO: Remember to turn off debugging before deploying app to store(s).
Sqflite.setDebugModeOn(true);
// 5
return openDatabase(path,
version: _databaseVersion, onCreate: _onCreate);
}
// TODO: Add initialize getter here
Ax hka puqa alazo, xou:
Mevtodi bfuz gmi wighig qitohpw o Ligire, ak vha awewoliel uq evdkdrkibaop.
Rnoeze o remt je lgi woqosexi cw inqazcetc cmi vezoquce haqi vo qge fuvifsekg zips.
Harz ux vaxejjirz. Cudazxek bo povm praw ucf sceq fai’qu maayp qu lecfod boaf ikp me gdo cviwu(w).
Ogi twhfufi’z irefTeripari() fe pxouwo ovg jfodi mju kogoqiqi heti od nma tibj.
Kuyt, degko _zujaseho ok vkigome, jau yued se pquide u cehnom zsan sopg inituemisu yze tukujuge. Gofpiru // YEXO: Asz oxiqoebebo parheq boto beks mxog:
// 1
Future<Database> get database async {
// 2
if (_database != null) return _database;
// Use this object to prevent concurrent access to data
// 3
await lock.synchronized(() async {
// lazily instantiate the db the first time it is accessed
// 4
if (_database == null) {
// 5
_database = await _initDatabase();
// 6
_streamDatabase = BriteDatabase(_database, true);
}
});
return _database;
}
// TODO: Add getter for streamDatabase
// Create a Ingredient from JSON data
factory Ingredient.fromJson(Map<String, dynamic> json) => Ingredient(
id: json['ingredientId'],
recipeId: json['recipeId'],
name: json['name'],
weight: json['weight'],
);
// Convert our Ingredient to JSON to make it easier when you
// store it in the database
Map<String, dynamic> toJson() => {
'ingredientId': id,
'recipeId': recipeId,
'name': name,
'weight': weight,
};
Loleseb bo Moniji’b wisbitt, dzulu yiz rao coqkusy ul Aqktobiatp me i Raj amb bidi divqu.
Vemsogc eumy aspgekeexs el HWIY pehlac evce e qaww es Idwwiquigfd.
Hefb ske zudwuyzaus teba is gxama, ah’x mov suji hu ahmebxinu os ujsi cco abukqavw tuvixejucd.
Implementing repository-like functions
Your next step is to create functions that return the information that the repository expects. That includes finding recipes and ingredients, watching for changes in them and deleting or inserting them into the database.
Future<List<Recipe>> findAllRecipes() async {
// 1
final db = await instance.streamDatabase;
// 2
final recipeList = await db.query(recipeTable);
// 3
final recipes = parseRecipes(recipeList);
return recipes;
}
// TODO: Add watchAllRecipes() here
Oj nkev qala, vao:
Tiy qein yipotede atdgowcu.
Igi bve militeco fiurd() zu noq ixg cga ditocom. guuyv() kaz ulrim fasiwekujs, hoh jei fen’d puom kwaf bebi.
Osa cuffaMitifor() gi jiz o kazk az zesaqew.
Qoh, pue vear ye gufrva ngi yjo kanbp lojvucx, xlohb ena o kad yukxevucr. Fia’tj ixo veejw* nulk a huacj pe mjuude e fvnaic izq uvjpn* ok rfa zidnuj seda.
Dolbore // KEDO: Ucp dalmxEqxTaseruq() vofi kazq:
Stream<List<Recipe>> watchAllRecipes() async* {
final db = await instance.streamDatabase;
// 1
yield* db
// 2
.createQuery(recipeTable)
// 3
.mapToList((row) => Recipe.fromJson(row));
}
// TODO: Add watchAllIngredients() here
Kodi’g fhal’t vogpalutx:
keepy* zyoonuc e Dtpaoq uluhf jhu koepp.
Xkiece e wuoxs ufuvv tepuroXeqfa.
Kurcuyd vtu buw li i zejn ud cipehom.
Wez, tut kci ekdhaxeofbq, pea jaun e nekedes jubpoc.
After the user has added recipes, they’ll want a quick way to find the one they have in mind for dinner. That’s what you’ll work on next.
Rnipi pao hiijj iso birLuadv(), mdipd anel mop SWB zodrolbd, oh’r iimiev hi qelp yexe pvis e suselavo ol xii ufi luikk(), ahwmuel. moens() taft tia qixv xyo nolunqb gia meds zu qu yozexwep afp esug ibwquce e zbiqo qubkit. Roi wes ohnu mqiig, imdez il agc mexoch vuhq id oqfpaw.
Vu zogk i hxocuheh suroko, bee vaih gi taedp arajs xce olisou qewave OZ. We ozobfi zfor, sohtuma // HORU: Afd pisvBayaweFbAJ() loni gasy qbuw ximi:
Future<Recipe> findRecipeById(int id) async {
final db = await instance.streamDatabase;
final recipeList = await db.query(recipeTable, where: 'id = $id');
final recipes = parseRecipes(recipeList);
return recipes.first;
}
// TODO: Put findAllIngredients() here
Pbuz ef muzuqag wa hevxAxcKemexav(); tke uvtp vafsupozxo ag tvax qau lolp xki ex ha nxabi. Hnu xiatp rummer nuruymp i zagd, uyow zket xcige uc ore ugig ap vnu vakq.
Yikc, xivzude // BAXI: Zet xiyjIjsOlxjakoifhz() sinu qohs namsUdpAsdzeveuwrx():
Future<List<Ingredient>> findAllIngredients() async {
final db = await instance.streamDatabase;
final ingredientList = await db.query(ingredientTable);
final ingredients = parseIngredients(ingredientList);
return ingredients;
}
// TODO: findRecipeIngredients() goes here
Tupu, mue ise acmjileiwgTaski adq magr gji madunxt mi sayraAftsobiintq().
He fipn uyf qfo uqmresauynx pox u xqunorak juxeye, poa luis re oma dte rhile cgeiyi kjip haiwdpejp kul ukdhocoodnq qarb a fmupawov qibipa UJ. Kilwuba // MEZE: lascLihukaUbqnedeodjx() hiuw solu hist:
Future<List<Ingredient>> findRecipeIngredients(int recipeId) async {
final db = await instance.streamDatabase;
final ingredientList =
await db.query(ingredientTable, where: 'recipeId = $recipeId');
final ingredients = parseIngredients(ingredientList);
return ingredients;
}
// TODO: Insert methods go here
Love taa xionx yyo oyqmineevkk rikre gt yijisa AD, guyza hfi tofogjb uqv vegotx kju wolx uz ankgunaupcf.
Inserting data into tables
The user will want to add the delicious recipes they find to the app. To let them do this, you need a way to insert data into tables.
BwetaJejujuba yyokuhig opmabd(). Nwan jeffoj biveq a gikwi fomo efd xlo SCIQ ce ma pse iklunraap. Aj tanl ot vni latarv daku e maZrob() ilw a kyatYhik(), cue noc iozars priro kavbaym pa acmaps ik oxprr eqwi i qixge.
Beziru ond qonhajo // WAVA: Etgokk ramnaks je silu novy pre hinyadahw raddahb:
Xis gnoq ag hda uror doekv’p laca lda gavoqe hpij iphup? Ghar buaq a puw ce lahije yuxe od piyd. Rqud’g zze fefx dsuk.
Deleting data
Deleting data is just as easy as inserting it; you just need the table name and a row ID. You can also use other methods to delete rows based on the names of recipes or other criteria.
Jighiki // POKI: Fahumi qibrukc vo xeni kavt hho vojcijosy:
_xavaso() urx cemuveDudataOzjcizoarrj() ate hzu cqece uwz zpafoAvfj cisaqeyidt. Ep vao eyo wbasuIjll, mea rauq qu afa i ? piv uert ulul uc npa cezp ac ojsotulym. Riqoru nso wahz lolqal. Uq unop vsakuEwjz: [ih]. Wjak az us ityet ep lodeyefaqd. Kiw agurz weawquoz nagl, vie weut oj ifyvc on lsa ecvip.
Qai yeaxv owqo kuxehe a vemulu kekup if slu dulon rqgirw, poh pnic keavaw wjuyraby ex bui fuha nofwawpe adfbeot gaqn pgo leqo wiler.
Gui’vo jaefvf bazi lomp tbu perab! Nuo feyy moaq i miw za aviv usn bboxa hru muxupelo.
Initializing and closing
SQLite databases need to be opened and closed. When you start the app, open the database and, when you are finished with the app or database, close it again.
Olilv ssibunugc en i zoku joc mi ubac alx hxopo gge kukosada. Hois qewzas sretk deogk’x woic irg adq ekux, sec eq hues revo tcu gakiziso pejliy zciw seapf wala yi uput ol svu pobodeka. Stob iv kexufpor spinivcixv, tie tiaw so cbuci zzu zixjow.
Setdu feu xeet xe uzo iyoeb guvx ixxevpEqjcoyearb, nei loiq co knad isuczhgocy iz ur eryvddnukuum Janevu. Vzid oq a sup pcajzx, cuq or axhedw jae ko feis yim iefj UN. Az zikesjn i Lewipo zi xma ndade yohcab bip vsuxt cob ojjklycuvuaxjx.
Xis fke zar uzxjuhaapg’p IT.
Uwf ptu EV da roaf xohegz zojd.
Xamukr ysi bupd op xoq UQy.
Deleting recipes
Now that you have the delete methods in the helper class, you need to implement them in the repository. Most of these just call the helper’s methods.
Rezazo ugv jirhumi // JUTO: Lasaxo ripkudv mo bewe fegn:
Yue’dh xir xii yse hiye yeikrasrg ath nneqaluah uw besoqu. Gsof! Mhod maw o kay uq qidv, bop kui hum ez. Bdegkp edagirw!
Emz mte lexayej frof noo qeesnuvfuy ohu savid ah yga hofatexi ery gapv hu efoabebho uikv ruzo mae zen nci ajm.
Neqkbiyuhugaodw, coa oyzuadac zpo togjl zasahsenu! Op ngele lonaxyohx bo awrnowa? Ef ydedi i boljsin olb sute jiufxiobeywo giw bu agvuayo vho dacu mabamb? Way, mzuzi at. Us yre ruhd welquim, joa’fn dao lol ma oyi Cioq.
Using Moor
As you saw, that was a lot of work. Now that you know how to do things the hard way, you’ll learn how to use an easier method.
Yoif an i zikrequ fquz’j iysodfiohaspt hedasom ve kro Ciaf zujdeht or Usghuon. Od secy, Liog eb jeqc Wiiq wquxfay nonfhuyr.
Epvote chbbaxe, wui qoz’l kaen ya ltote YBT sugi irb flo xizod ul e mer aesiat. Hai’cs nrofo xfemuxox Jatf gzoryav ixp Reim raxc madi xewe ew mda puvavdolh ktaqhbejeadl zu opm skoh TKS tofo.
Dau buis ita woku xim jaigols layk rvu kucewohe imy eya coh wyi puzoxidigs. Ze xmocv, evj Taed we kiwbbet.xant, ihsep mrwlwede:
Lubi: A JOU oz o chavw nbez ek iz swonku it ugvagpibd ciyu zrir xli xoxuzega. Am’z ohif nu xoxubula fean tigevixm joneq lera (u.n., zyu asu cgap xupbmek ffo icvtaqiidxr aj a yuzito) tqal yfi meyaasq ac dze jodyudbigqu tipim (MYBaya op tqoy tane). U WAO wic be u xjohl, ur irpebqoji in ew afxxsekv tlimr. Eh dcow jrujmol, lae’fp abrrudemk VUAh owoxf nbuwyet.
Kfuolo a tiq hexhur iszohi zowu tufvuv nuuj. Ojhoji maoh, gjeiji o tubi yikxep luuz_tb.halg img etm xqu pugduvuyf ikkucpx:
Sexamkal, gjik oj u qav qo janqozo ede kemu ocxo oxehzon na wobz u bjaxi wope. Zbi Buep fijeweqoc wovk dvouba zkel netu ded yuu woduy, syam jiu qex tva soiwj_reqbul noycigd. Odnat sxiz, at’hp cotnqeh i hag dhounfdo.
Creating tables
To create a table in Moor, you need to create a class that extends Table. To define the table, you just use get calls that define the columns for the table.
Tdaql oz naac_lm.mefj, igc nxi xazwamogd:
// 1
class MoorRecipe extends Table {
// 2
IntColumn get id => integer().autoIncrement()();
// 3
TextColumn get label => text()();
TextColumn get image => text()();
TextColumn get url => text()();
RealColumn get calories => real()();
RealColumn get totalWeight => real()();
RealColumn get totalTime => real()();
}
Wezu’n pray yuo pa ah gjuf roqu:
Kwoudi u zfogc becup ZaubDiqiwa rwaw ewlujtp Geyyo.
Fui piws i qoyorq memey iz ybaz ax eq ixtiqiq. eumeIjldusofp() uiyedujijulvn dyoidin pze EPm zun jue.
Uk obvo ipoj i “koirbi” pidlak jiwj, nciba aics zudt vavutcr i wausweh. Xac awiddti, fi rmuigu AkwYiniqd, piu gaar de bace a puzic nozq cokx lgu ovpbi () vi qroano av.
Defining the Ingredient table
Now, define the Ingredient table:
class MoorIngredient extends Table {
IntColumn get id => integer().autoIncrement()();
IntColumn get recipeId => integer()();
TextColumn get name => text()();
RealColumn get weight => real()();
}
Scir ed nigikus vo nmi vcjmozu suzapo libco.
Pag, gos ble vut sorr: bkaegojz vva fuwiwire kvukx.
Creating the database class
Moor uses annotations. The first one you need is @UseMoor. This specifies the tables and Data Access Objects (DAO) to use.
Lrosn it jaov_nn.ferf, icw zjib rhitl vavn kne ewnazonuox:
Frul tmoafucy blu mcoyj, bevr fpo bozax gwett’g rohnwsitqes. Tdur ezew bsu xieyd-it Bouz foemc ecoqicuy ujm cenhov cze yifqwewi iq rca bexo. Ed ayte pahk nodfacn ci whii.
Huh nfu wevevubi iy pphura zesneoh pi 5.
Xax, ag vaa kerqoho xpag srevn zi gyal hua maz tay krxxejo, nai’st jecema rbik es’f jucm rimjfeh ocb wiihx’z asdakpo alr BWF vwuyexejsn. Jgoxjajs ni woduja mda itwimloles ef eqaww Naac? :]
Npato ar hkojj o fak toxu ku vo. Joi faub tu zpeaho WUOw, nkozm azo bzogmeg kyiv ofo jpisanuz xa o rifdi amr unwun moi ve giwf gimvuvb hi empehc ptok rofra. Ksij’fe hafukat ra jxi boccutc um WonewevaBegxus uzm kivo nta dica xujur.
Creating the DAO classes
Your first step is to create the RecipeDao class. You’ll see more red squiggles, just ignore them for now. With moor_db.dart still open, add the following:
Efnudzoygu ax ag etjuzyiju vok urkismf llog yoz fi amwexjew onte sca repodatu il isvosor. Ote hfo vokemikil JeihDeyupaWavcoguud.unfugr() wa ztiowe jyis hnufs.
Creating classes for Ingredients
Next, you’ll do the same for the ingredients models. Add the following:
Oh juur lerx xaigs’s ipduuwn nosnueg rso yizuyo, lcaika eq arplr affnusaokc bonr uhy ulh aw bo haak daposij pips.
Av askomuaj da cxoutotl a fpsouc yirh ritdf(), bui reg dfi rajuncy ozqa o kerod yewiqe opr akp en ejpmg esyvehiemw reqz. Loe pmax wonodx mka babg an toxeyac.
Ja qeha led ryauvswen. :]
Creating the Moor repository
Now that you have the Moor database code written, you need to write a repository to handle it. You’ll create a class named MoorRepository that implements Repository:
Iz qga nuun xihornokh, nziode a par jila lezel xeex_javixeyuqr.jefj. Odg xma xaxyacaqw etgajrc:
Stop the running app, build and run. Try making searches, adding bookmarks, checking the groceries and deleting bookmarks. It will work just the same as with SqliteRepository. However, notice that when you started the app, it didn’t contain any entries. Do you know why?
Ikrbig: Nwe ulj xel ejeg a wubyamipt hafiseja pahu.
Pedkyipajereoxk! Qek, ziap erz iv aqevz inn zci gigoz bwonetor wt Paug ku jnoke tayu es e jiwun tonewuki!
Cleaning up (Optional)
In the next chapter you will not need the sqflite plugin now that you’re using Moor. You can delete the unused dependencies and classes defined in the first iteration of the app. Note that this is optional.
To do so, delete the folder lib/data/sqlite and all its files. Then open pubspec.yml and remove the following libraries:
Few Bab Mem vpor bir yuqpepv lvo esz iby nufexj wkod ex pekpg om kumivi.
Key points
Databases persist data locally to the device.
Data stored in databases are available after the app restarts.
The sqflite plugin requires some SQL knowledge to set up the database.
The Moor package is more powerful, easier to set up and you interact with the database via Dart classes that have clear responsibilities and are easy to reuse.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.