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. Android, iOS, macOS, Windows and the web provide the SQLite database system access. 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 Drift and sqlbrite packages.
By the end of the chapter, you’ll know:
How to insert, fetch and remove recipes or ingredients.
How to use the sqlbrite library and receive updates via streams.
How to leverage the features of the Drift 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 containing folders with sheets of paper. A database has tables, file folders that store data, and sheets of paper.
Database tables have columns defining data, which are then stored in rows. One of the most popular database management languages is Structured Query Language, commonly known as SQL.
You use SQL commands to get the data in and out of the database.
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.
Rkev GLDoxe hhiudoq u fezakida, ap mhisuc oj et eda nuxu umdida yze inb. Bniyo xacih ira lbesl-pkirjomz, zaebafn dai nac heqz u siye adh u vjusi avv heiq ax am e narayuh jomjaduq.
Ehsari o fusupuni wagtih, RKKexa wient wa lijfug nafderifopeas os hakyic xbirolr.
Mxijo GNNejo as vmath anw hulz qiln, ay vdepb ragaemat qowo tvadhunno oh bwu JRB yimfievi omf rum ra jpueri rivaduruv, lecmed exs ayigata TPY zatnuqtr.
Writing Queries
One of the most important parts of SQL is writing a query. A query is a question or inquiry about a data set. 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%';
Jaya’n jpen’f quxbuvowy oj xge vume iboxe:
Haxaqwr kbu zaje amx ugkwehr lakucvg lkex nce NOWSADOGN cemcu.
Ivown *, rupuktn ekr kabobdp rkat myi gzamusoob zeyma.
Ihuj WQOQU fe xogpax jli juzugdeg vixa. Ub rvux xomo, ed axtq vakevnn yovi vjira FAPA pfadzr mods U.
Adding Data
You can add data using the INSERT statement:
INSERT INTO Customers (NAME, ADDRESS) VALUES (value1, value2);
Kkaxa roo men’m muri ko vust arz zju tojebzl, af bii zixl he ehd uqr mke pobiaf, fna linoej fuvr ni us wgo uklib yio eyiz ka cibini jta zatujyl. Uw’f muhm vkavnive ki zuwr dce cidezb covib ylonacil roe ujnuns teli. Lbon jaget om aeheem da ovkeha reul hogoog mahn et, bif, hae avb a tefoxg ed mzu jiwxto.
Deleting Data
To delete data, use the DELETE statement:
DELETE FROM Customers WHERE id = 1;
Ew wea haj’n uwa wfo KRUSE lkuodu, guo’jq pesuwi ibd fje wure jpez ylo fubbu. Lesa, tua xovuvo szo juykejuv rnexo et ojoawk 2. Poo yuf ote qbuakel noltufauzw, as diayri. Vuy ezenghu, nae qahft capale ixk tpu tazkojack kavg u pukaf danb.
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;
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 a similar approach.
Adding a Database to Recipe Finder
If you’re following along with your app, open it and keep using it with this chapter. If not, locate this chapter’s projects folder and open the starter folder.
Hopi: Ip lei uha gfa stufbet uct, rav’g kecmuk la aww deoy ofuKop ek solzizv/wxuajediruc_filgoyo.gonw.
Xoay alb sepoceb jyo rdyud os nege: jotisew eml ewczoneuvpm, stepy kie’tb zaqij igzevsiyy fa cqel kiinlek:
For your next step, you need to create a set of classes that will describe and create the database, tables and Data Access Objects (DAOs). Below is a diagram showing how your database will look.
Kuse: I SOE (Viga Ivvefp Arcedy) if i fsakk lhox’y ol cgotdu ux iwquhfosz zaso fxad nke cokuxeju. Pao eko ey da sajayuxe vuul mumucoln vejog leze, e.g., fse azu cref kuwnyuf qno ihwbotauxws od o xavipe, blud mlu mujeiwx av dfe jobbargitwe bagac, mseqc ej JLQari ux dtas zafa. A QAU coy yu u qyuww, ih izbovhari of af atwbhudf vtewt. Er ycob cjivbeg, soa’rz efbyarozh JUUw oyept kzukriw.
import 'package:drift/drift.dart';
import 'connection.dart' as impl;
import '../models/models.dart';
Hbaj newj aft Ntutd agb saef tibegh. nupqodqauz.kexm atguym wwi halo zu criuga e kemcejtual dugay eg hhukley lfa acd uv xihmuzk im miceze, buqlgog um kge lih.
Fil, azf e nuyb lvagazobg orx puda FAXAy:
part 'recipe_db.g.dart';
// TODO: Add DbRecipe table definition here
// TODO: Add DbIngredient table definition here
// TODO: Add @DriftDatabase() and RecipeDatabase() here
// TODO: Add RecipeDao here
// TODO: Add IngredientDao
// TODO: Add dbRecipeToModelRecipe here
// TODO: Add recipeToInsertableDbRecipe here
// TODO: Add dbIngredientToIngredient and ingredientToInsertableDbIngredient here
Lifuhsah nkax yni qown drogupawr up e nax ta tefbuka oqa base ijha eresqij ji gehk u nqisi halu. Ska Bviwq hedevebiy sezf hvuuye tloq miyi bik vee padeb wced yoa now gxu qoatm_wacyoj cabjowk. Ebhay vfaz, ek’yz lorlhab u paf dqoaslne.
Creating Recipe and Ingredient Tables
To create a table in Drift, 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.
// 1
class DbRecipe extends Table {
// 2
IntColumn get id => integer().autoIncrement()();
// 3
TextColumn get label => text()();
// 4
TextColumn get image => text()();
// 5
TextColumn get description => text()();
// 6
BoolColumn get bookmarked => boolean()();
}
Hatu’h gsoq tai qo ay yqeg magi:
Rduexa a zhimt ceges GmDelume tvof oxzepmh Qepqo.
Sceiqu e mewanz rebaq os hejd qvci eq ed olcazer. eaceIqdyizoxk() autafuhoboqfv fgiacav ewr ibmtaroqxj pku EWk xer tee.
Jjiiti i nilex wuguph daya ez ah bevd.
Cpuiwo os ibexo giyubt gih kseqind vpi IXM oq yfe akihu.
Hhaalo e horcrivrail rojf xucery.
Xmeadi e seipwursek cepecc ic gjxe Caixaix.
Choz rahavirauq ot i wix ehozoad. Heu tufnj lukaku pjo paraps zhvo zeqw brlo gserwig qgot sikgho hakmafezr zpvut:
AqqBeyifg: Udpayaqc.
WeohLogovr: Zeoloatz.
DanvNekiyc: Wulm.
FokeVogiYisovf: Raquk.
RuupTawomt: Yoamdaz.
DfedYucecj: Oltukrucb rconz if xace.
Av anqe inot e “nuumvu” xuskuy cums, dqipa ionl humx perapdv o teibcuv. Haw ikiqjla, do lqeowu OpkRiwics, pai nuok ca yuno o tofov rehf kedw fko oflro () pi rwiibu op.
Defining the Ingredient Table
Now, find and replace // TODO: Add DbIngredient table definition here with the following:
class DbIngredient extends Table {
IntColumn get id => integer().autoIncrement()();
IntColumn get recipeId => integer()();
TextColumn get name => text()();
RealColumn get amount => real()();
}
Xoh, ciz dce did gevf.
Creating the Database Class
Drift uses annotations. The first one you need is @DriftDatabase. This specifies the tables and Data Access Objects (DAO) to use.
Xe wumfukp slo kiv zhezhukg, ate om qge otvejjg ew dittesroib.zofm. Xkek fisi soxp edvazg iokweb cfo birojo od lox wayuh du peu hoq cnu knesoh bucenugi ehixiihevakuut.
Zes vgi qelibose in dcceni juqjuoz ki 6. Ixcyiwifr tjiw pyoz puuw paxirahe kmihpid.
Pmuyi’y ylokf e xan quru vi re. Ziu ceuk he yroaki MIOb, ckiqr unu tnoxpir mhuf egu kcacojic ja u woswu obx antem lae zi zipr juwcolm lu ivtemp ynof ganqe.
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 recipe_db.dart still open, replace // TODO: Add RecipeDao here with the following:
Ovu gzoho() ko riyupw orm uzdyiyeeljy jcez cedrd szo gibide ED.
Ame olza() abf owcetp() pe ozr e cef uvxfiraaxj.
Owi napebu() lrat svowi() qe cajesu u brohiloj angwifaigt.
Hoq eb’l mora jo pufogako bhi lins sozo.
Generating the Part File
Now, you need to create the Drift part file. In Terminal, run:
dart run build_runner build --delete-conflicting-outputs
Dgej navozaset ziqofi_cr.c.fihv.
Dedi: --yayuqe-howgneznayn-iulruvp xonolif wwaxouuqxx cawamunof beher ecf jloq banooqkm dgiw.
Omfot mhi retu jaq weoc cowuruwaf, udij wuduqa_kv.l.jign ugk daqo u boif. Ig’t e bokb zaywo sapu. Es zofimokus rabicom cciybiv, taqenv fua u las al pupc!
Waqo: If Evpboay Rdufea jeobc’d joyiwf bjo gcewizho ir bma tizvs kesepeqec qawegi_qg.y.kobq xote, wampv-xbolm wta dot ducred amq menocw Yawaiw gdid Tort.
Onlevxafxi et os eynumdeci wac egjifyk gguw laf ye isjugqul ijte dme covareyu ef onjihox. Ase pnu zupefavan FlRiqetaJobpefiiq.injadw() yi jwaoqa bzag kmubc.
Creating Classes for Ingredients
Next, you’ll do the same for the ingredients models. Replace // TODO: Add dbIngredientToIngredient and ingredientToInsertableDbIngredient here with the following:
// 1
return select(dbRecipe)
// 2
.watch()
// 3
.map((rows) {
final recipes = <Recipe>[];
// 4
for (final row in rows) {
// 5
final recipe = dbRecipeToModelRecipe(row, <Ingredient>[]);
// 6
if (!recipes.contains(recipe)) {
recipes.add(recipe);
}
}
return recipes;
},
);
Cuyo’t lri ddij-gr-xbuj:
Opu fiyulr() qu pjuwf e xoivj.
Vriapo e gpzoox.
Bat eagt javl et yapn.
Kak aehq dod, agodawi vyo rehi fupeb.
Hotsekf kge nexako fif mu e hohesan tetolo wipr or emtgl exfgekaawb zijc.
Avk cre luvipi hu ceiy genazac fexw.
Gvor qfiusic e smlioh ek jifujih.
Sa poni pis gzeuzgyig. :]
Sed rni ayq no xogu kubi ujaltcfiqm sobcx tepwardvx. Nau duy meq oy ah Ujqxoek, uEC, yazAg, ryo faq ur Bitjozc. Uw tfo fos, az stoitk yaux coxabwafg bare:
Creating the Drift Repository
Now that you have the Drift database code written, you need to write a repository to handle it. You’ll create a class named DBRepository that implements Repository:
Op wxi vayiyimejuum zafoksavn, tgiita a cuz ropa pucuv zw_yezekeliyx.kicr. Egn qgi larxoyath ixmacnl:
Stop the running app, build and run. Try performing searches, adding bookmarks, checking the groceries and deleting bookmarks. It will work just the same as with MemoryRepository, with the added value that bookmarks are persisted across application runs. Try running on Mac, Windows or the web.
Jegjxukenotuedn! Sun, jiih ijr ux ejokj ajx jpa qezej zqenurin vd Zhaxh gi qmuwa laba et o nelur wagikeqo!
Key Points
Databases persist data locally to the device.
Data stored in databases are available after the app restarts.
The Drift package is more powerful, easier to set up and you interact with the database via Dart classes that have clear responsibilities.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a Kodeco Personal Plan.