-
Notifications
You must be signed in to change notification settings - Fork 3
Database
Database is one of the (local) data sources of our application. It is responsible for persisting data on the device. This is important if you plan to support offline functionality in your application.
The project is using Isar as the database.
The database file is saved in the application's cache directory. IsarDatabaseFactory
is responsible for opening the database when we are going read or write data.
A DataObject
is a class that represents a table in the database.
See Data Objects for more details.
LocalDataSource
is an interface that defines the operations that can be done in the database. We use this interface to hide the implementation details of the database to the consumers of the data source.
abstract interface class LocalDataSource<T extends DataObject> {
Future<T?> get(int id);
Future<Iterable<T>> getAll({required int offset, required int limit});
Future<void> addOrUpdate(T object);
Future<void> addOrUpdateAll(Iterable<T> objects);
Future<void> delete(int id);
Future<void> deleteAll(Iterable<int> ids);
}
💡 IMPORTANT
- By default, we expose
getAll
anddeleteAll
database operations with filters. This is to avoid loading all the data in the database at once. This is important if you have a large amount of data in the database. Loading all the data without any filters may be applicable for tables that have a small or fixed amount of data. - Update the implementing interfaces of
LocalDataSource
if you wish to add additional filters. See the next sections below for more details.
Once you have created your data object, you can now create your local data source by extending IsarLocalDataSource
.
import 'package:injectable/injectable.dart';
import 'package:isar/isar.dart';
abstract interface class PostLocalDataSource implements LocalDataSource<PostDataObject> {}
@LazySingleton(as: PostLocalDataSource)
class PostLocalDataSourceImpl extends IsarLocalDataSource<PostDataObject> implements PostLocalDataSource {
const PostLocalDataSourceImpl(super._isarDatabaseFactory);
@protected
@override
@visibleForTesting
IsarGeneratedSchema get schema => PostDataObjectSchema;
}
-
@LazySingleton
is used to register the data source as a lazy singleton. We don't need to worry about sharing the same instance since all transactions will be using a different database instance fromIsarDatabaseFactory
. -
IsarLocalDataSource
is a base class that implementsLocalDataSource
. It is responsible for opening the database and executing transactions. -
PostDataObjectSchema
is generated after running thebuild_runner
. It is used to point the schema to use when opening the database. - It is important that we only implement
LocalDataSource<PostDataObject>
toPostLocalDataSource
. This will hide the unecessary implementation details ofIsarLocalDataSource
to the consumers ofPostLocalDataSource
.
💡 TIP
- Use the snippet shortcut
locd
to create a local data source.
If you need to support other queries to your data source, you can add update your own interface that implements LocalDataSource
.
import 'package:injectable/injectable.dart';
import 'package:isar/isar.dart';
abstract interface class PostLocalDataSource implements LocalDataSource<PostDataObject> {
Future<PostDataObject?> getPost(int postId);
}
@LazySingleton(as: PostLocalDataSource)
class PostLocalDataSourceImpl extends IsarLocalDataSource<PostDataObject> implements PostLocalDataSource {
PostLocalDataSourceImpl(super._isarDatabaseFactory);
@protected
@override
@visibleForTesting
IsarGeneratedSchema get schema => PostDataObjectSchema;
@override
Future<PostDataObject?> getPost(int postId) async {
final PostDataObject? object = await readWithIsar((Isar i) {
return i.posts.where().postIdEqualTo(postId).findFirst();
});
return object;
}
}s
- In the example above, we added
getPost
which usesIsar
's generated collection extension on an instance ofIsar
for ourPostDataObject
calledposts
. It provides additional filter options for each of the properties of the data object, for this example we usedpostIdEqualTo
to filter the posts bypostId
.
💡 TIP
- As stated in Isar's documentation about Indexes, using
@Index()
improves the performance of your queries if you are to use the annotated property for filtering.