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 CakeTablelike this:
database.managers.cakeTable
| |
Lines 11–13: To delete a single instance, we need to first create a filter on a
Cakewith the given id, and can then call thedeletefunction.Lines 15–16: The
watchfunction allows us to listen to changes to the table’s content. Since we specifiedCakeas the “row class” deserialization happens automatically.Lines 19–26: Inserting takes a few more lines of code. Here we have to use the
createfunction and manually map theCakeattributes.Lines 29–37: Updating works similarly to inserting data. The only difference is that we first need to
filterwhich rows should be affected, and then use theupdatefunction.
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.