This article is part of the Data Storage in Flutter series.
In some previous tutorials, I showed you how to use sembast and isar as a local data storage for your Flutter apps. This time, we are going to use the drift package to store our data in an SQLite database.
I will use the same app structure as in the other two tutorials to keep them comparable and only talk about the differences here.
SQLite is a very commonly used database for mobile apps, this makes it a very safe choice.
Since it’s a relational SQL database this means that it requires the user to specify the data structure in the form
of database tables.
That is a different approach to databases like sembast
which stores any type of JSON data.
The drift
package helps us to take away some of the heavy lifting.
That way, we don’t need to write any SQL statements – but we can if we wish.
You can find the source code for this tutorial on GitHub: https://github.com/bettercoding-dev/drift-sqlite
Prerequisites
There four packages are needed for adding drift to your project: drift
, drift_flutter
, drift_dev
and
build_runner
.
Together with the packages for riverpod
and freezed
this is what our dependencies should look like:
|
|
To add them all at once, you can use this command:
flutter pub add drift drift_flutter flutter_riverpod freezed_annotation json_annotation riverpod_annotation dev:build_runner dev:riverpod_generator dev:freezed dev:json_serializable dev:drift_dev
The drift
package also relies on code generation. To watch for changes and rebuild the generated classes, use:
dart run build_runner watch --delete-conflicting-outputs
The CakeTable
In contrast to sembast
, where we had no schema definition at all, and isar
where the schema could be derived from a
data class, when using drift
we need to manually specify our database table.
|
|
This is relatively simple, but we need to be careful to have our CakeModel
and the CakeTable
in sync.
Notice the @UseRowClass
annotation. This binds the Cake
class to this table and helps deserialize the data when
reading the database.
Creating a Database
With drift
we need to create a class to specify our database.
|
|
Using the @DriftDatabase
(line 7) annotation we mark our database class and specify the tables that should exist
in the database.
The super
constructor (line 9) requires us to pass in a QueryExecutor
object that opens the database.
We can use the driftDatabase
function for this case.
In line 12 we need to specify a schema version. This becomes relevant when migrating between different versions of the database.
As with the other tutorials, we create a provider for the database. With drift
this can be done synchronously.
|
|
Implementing CakeRepsoitory
with drift
Finally, let’s implement the CakeRepository
.
For simple database operations as we use in this case, drift
offers us so-called managers
.
We can access the functions for the CakeTable
like this:
database.managers.cakeTable
|
|
Lines 11–13: To delete a single instance, we need to first create a filter on a
Cake
with the given id, and can then call thedelete
function.Lines 15–16: The
watch
function allows us to listen to changes to the table’s content. Since we specifiedCake
as the “row class” deserialization happens automatically.Lines 19–26: Inserting takes a few more lines of code. Here we have to use the
create
function and manually map theCake
attributes.Lines 29–37: Updating works similarly to inserting data. The only difference is that we first need to
filter
which rows should be affected, and then use theupdate
function.
Summary
In this tutorial you learned how to use drift
to use SQLite as your app’s data storage.
We specified a table that matches our data model, initialized a database and implemented the CakeRepository
to create,
update, delete and read data from the database.
Of course, drift
comes with a ton more of features. If you plan to use this package for your next app, I’d recommend
you checking out the documentation: https://drift.simonbinder.eu.