Easily manipulate sqlite databases in Dart using this package. The designed objects structure is as follows:
- TableDb: Defines a table in a database. It consists of a collection of ColumnDb objects and a table name.
- ColumnDb: Defines a column of a database table. A TableDb object will be made up of a collection of ColumnDb objects.
- FieldTypeDb: Defines the type of the value of a column of a table in a database. SQLite does not have a separate Boolean storage class. Instead, Boolean values are stored as integers 0 (false) and 1 (true).
- ObjectStored: All objects that intend to be stored in SQLite databases should extend the ObjectStored class.
- PSQLite: Encapsulates a database that is made up of a TableDb and a database name.
- FilterDb: Defining a filter to make requests to PSQLite will allow us not to have to bring you all the SQLite fields and filter manually, optimizing SQLite queries through the use of filters.
- ConditionDb: Allows you to define the type of condition of a filter.
In the following example you will see how to create a user database.
Import psqlite.dart
import 'package:psqlite/psqlite.dart';
User class that represents the object that we are going to store. Any object that is going to be ported to SQLite requires extending the ObjectStored class. This will force us to override the toMap and getPrimaryKey methods.
import 'package:psqlite/psqlite.dart';
class User extends ObjectStored {
final String _id;
String _name;
String _lastName;
int _age;
User(this._id, this._name, this._lastName, this._age);
User.fromJson(this._id, this._name, this._lastName, this._age);
String getId() => _id;
String getName() => _name;
String getLastName() => _lastName;
int getAge() => _age;
void setName(String name) => _name = name;
void setLastName(String lastName) => _lastName = lastName;
void setAge(int age) => _age = age;
@override
String toString() =>
'User{_id: $_id, _name: $_name, _lastName: $_lastName, _age: $_age}';
// The keys must correspond to the names of the columns in the database.
@override
Map<String, dynamic> toMap() {
return {'id': _id, 'name': _name, 'lastName': _lastName, 'age': _age};
}
@override
String getPrimaryKey() => _id;
@override
bool operator ==(Object other) {
if (other is! User) return false;
if (_id != other._id) return false;
if (_name != other._name) return false;
if (_lastName != other._lastName) return false;
if (_age != other._age) return false;
return true;
}
@override
int get hashCode {
var result = 17;
result = 37 * result + _id.hashCode;
result = 37 * result + _name.hashCode;
result = 37 * result + _lastName.hashCode;
result = 37 * result + _age.hashCode;
return result;
}
}
The easiest way to encapsulate the data persistence of the User object that we have created is by creating a wrapper service. Inside we will create the columns of the table and the name of the database. The mockedDatabase parameter will allow us to perform unit tests on our service. For simplicity and in order to create FilterDb type objects, the parameterized use of the column names is recommended. In this case, an enumerator has been used for this example called UserColumnName.
import 'package:psqlite/psqlite.dart';
import 'user.dart';
enum UserColumnName { id, name, lastName, age }
class UserStorageService {
static final shared = UserStorageService.init();
late PSQLite _database;
final _tableName = 'users';
UserStorageService.init({bool mockedDatabase = false}) {
List<ColumnDb> columns = [
ColumnDb(
name: UserColumnName.id.name,
type: FieldTypeDb.text,
isPrimaryKey: true),
ColumnDb(name: UserColumnName.name.name, type: FieldTypeDb.text),
ColumnDb(name: UserColumnName.lastName.name, type: FieldTypeDb.text),
ColumnDb(name: UserColumnName.age.name, type: FieldTypeDb.integer)
];
final table = TableDb.create(name: _tableName, columns: columns);
_database = PSQLite(table: table, isMocked: mockedDatabase);
}
PSQLite getDatabase() => _database;
Future<void> addUser(User user) async {
await _database.insertElement(user);
}
Future<void> updateUser(User user) async {
await _database.updateElement(user);
}
Future<bool> removeUser(User user) async {
return await _database.deleteElement(user);
}
Future<User?> getUser(String id) async {
final response = await _database.getElementBy(id);
if (response != null) {
return User(
response[UserColumnName.id.name],
response[UserColumnName.name.name],
response[UserColumnName.lastName.name],
response[UserColumnName.age.name]);
}
return null;
}
Future<List<User>> getListOfUsers({List<FilterDb> where = const []}) async {
final maps = await _database.getElements(where: where);
return List.generate(maps.length, (i) {
return User(
maps[i][UserColumnName.id.name],
maps[i][UserColumnName.name.name],
maps[i][UserColumnName.lastName.name],
maps[i][UserColumnName.age.name]);
});
}
Future<void> removeUsers(List<FilterDb> filters) async {
await _database.deleteElements(where: filters);
}
Future<void> removeAll() async {
await _database.clearTable();
}
}
Now we can make requests to our User Storage Service from anywhere in the application.
You can create a single object:
final storageService = UserStorageService.init();
Or you can get the shared instance with singleton pattern:
final storageService = UserStorageService.shared;
You can add a new user using our user storage service:
final storageService = UserStorageService.init();
final user = User("1", "Liam", "Neeson", 18);
await storageService.addUser(user);
You can update a stored user, in this example first we add a new user and then we are going to update it:
final storageService = UserStorageService.init();
// User add part
User user = User("1", "Liam", "Neeson", 18);
await storageService.addUser(user);
// Update user part
user.setLastName(finalLastName);
await storageService.updateUser(user);
You can get the complete list of users stored:
final storageService = UserStorageService.init();
await storageService.getListOfUsers();
We can obtain a list of filtered elements. To do this we create a list of filters that we want to apply:
final storageService = UserStorageService.init();
List<FilterDb> filters = [
FilterDb(UserColumnName.lastName.name, "Neeson", ConditionDb.equal),
FilterDb(UserColumnName.age.name, 18, ConditionDb.greaterOrEqual)
];
final filteredUsers = await storageService.getListOfUsers(where: filters);
You can delete a user by passing an instance of it as a parameter:
final storageService = UserStorageService.init();
final user = User("1", "Liam", "Neeson", 18);
await storageService.removeUser(user);
You can delete ALL users in 2 different ways. Calling the removeAll method:
final storageService = UserStorageService.init();
await storageService.removeAll();
Or calling the removeUsers method without filters param:
final storageService = UserStorageService.init();
await storageService.removeUsers();