Quickeydb
Quickey is a Simple Flutter SQLite Wrapper
Install / Use
/learn @itskenzylimon/QuickeydbREADME
QuickeyDB is a simple ORM inspired from ActiveRecord, built on-top of Sqflite.
QuickeyDB Object-Relational Mapping (ORM) uses a coding technique with function descriptors connected to a relational database.
Apart from data access technique, QuickeyDB can benefit a developer in many ways including
- Requires Simplified development and Maintenance: this is because ORMs automate the object-to-table and table-to-object conversion
- QuickeyDB allow data caching /indexing improving database performance
- You get to write better queries in a Dart, Most developers are not the best at writing SQL statements.
- Lastly, QuickeyDB has incredibly lower code lines compared to embedded SQL Queries.
Platforms
| Platform | Supported? | |---------- |----------------------------| | Web | ❎ Coming Soon | | MacOS | ✅ Tried & Tested | | Windows | ✅ Tried & Tested | | Linux | ✅ Tried & Tested | | Android | ✅ Tried & Tested | | iOS | ✅ Tried & Tested |
- Introduction to QuickeyDB
- Getting Started with QuickeyDB
- Data Access Objects
- Data Tables Relations
- Database Migration
- Transaction
- Batch support
- Memory Cache
- Import Local Database
- Persist Data Storage
- Cool Color Logger
- Platform setup
- Taskan Crud Example
- Features Request & Bug Reports
- Contributing
- Articles and videos
Introduction to QuickeyDB:
QuickeyDB is an ORM inspired form ActiveRecord and depends on CREATE TABLE command which uses Regular Expression (RegExp) to analysis table defentions:
- Table name.
- Columns definition.
- Primary key.
- Foreign keys.
Note: QuickeyDB is a runtime library so it dosen't depend on heavily generate code.
Getting Started with QuickeyDB
1. Add QuickeyDB dependency
dependencies:
quickeydb: ^x.x.x
2. Create User Model and Task Model
// Database/Models/user.dart
import 'task.dart';
class User {
int? id;
String? name;
String? email;
String? phone;
int? age;
Task? task;
User({
this.id,
required this.name,
required this.email,
required this.age,
this.phone,
this.task
});
Map<String, dynamic> toMap() => {
'id': id,
'name': name,
'email': email,
'age': age,
'phone': phone,
'task': task != null ? task!.toMap() : null,
};
Map<String, dynamic> toTableMap() => {
'id': id,
'name': name,
'email': email,
'age': age,
'phone': phone,
};
User.fromMap(Map<String?, dynamic> map)
: id = map['id'],
name = map['name'],
email = map['email'],
age = map['age'],
phone = map['phone'],
task = map['task'] != null ? Task.fromMap(map['task']) : null;
}
// Database/Models/task.dart
import 'user.dart';
class Task {
int? id;
String name;
String body;
int? level;
User? user;
Task({
this.id,
required this.name,
required this.body,
required this.level,
this.user,
});
Task.fromMap(Map<String?, dynamic> map)
: id = map['id'],
name = map['name'],
body = map['body'],
level = map['level'],
user = map['user'] != null ? User.fromMap(map['user']) : null;
Map<String, dynamic> toMap() => {
'id': id,
'name': name,
'body': body,
'level': level,
'user': user != null ? user?.toMap() : null,
};
Map<String, dynamic> toTableMap() => {
'id': id,
'name': name,
'body': body,
'level': level,
};
}
3. Create a Schema Dart File
// Database/schema.dart
import 'package:quickeydb/quickeydb.dart';
import 'Models/user.dart';
import 'Models/task.dart';
class UserSchema extends DataAccessObject<User> {
UserSchema()
: super(
'''
CREATE TABLE user (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT NOT NULL,
phone TEXT,
age INTEGER
)
''',
relations: [
const HasOne<TaskSchema>(),
],
converter: Converter(
encode: (user) => User.fromMap(user),
decode: (user) => user!.toMap(),
decodeTable: (user) => user!.toTableMap(),
),
);
Future<List<User?>> getOldUsers() {
return where({'age >= ?': 18}).toList();
}
Future<List<User>> doRawQuery() async {
// Use your custom query
final results = await database!.rawQuery('SELECT * FROM user');
// when returning result use converter
return results.map((result) => converter.encode(result) as User).toList();
}
}
class TaskSchema extends DataAccessObject<Task> {
TaskSchema()
: super(
'''
CREATE TABLE tasks (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
name TEXT NOT NULL,
body TEXT,
status TEXT,
level INTEGER DEFAULT "1" NOT NULL,
FOREIGN KEY (user_id) REFERENCES user (id)
)
''',
relations: [
const BelongsTo<UserSchema>(),
],
converter: Converter(
encode: (task) => Task.fromMap(task),
decode: (task) => task!.toMap(),
decodeTable: (task) => task!.toTableMap(),
),
);
}
4. Initialize database
await QuickeyDB.initialize(
persist: false,
dbVersion: 1,
dataAccessObjects: [
UserSchema(),
TaskSchema(),
],
dbName: 'tascan_v1',
);
5. Simple Example
await QuickeyDB.getInstance!<UserTable>()?.create(
User(
name: 'Kenzy Limon',
email: 'itskenzylimon@gmail.com',
phone: '+254 712345678',
task: Task(name: 'Create Package', body: 'Create a Flutter DB Package')
),
);
Data Access Objects
Building Queries
/// SELECT * FROM user
QuickeyDB.getInstance!<UserSchema>()!.all; // | returns a list<T>
/// SELECT id FROM user
QuickeyDB.getInstance!<UserSchema>()!.select(['id']).toList(); // returns a list<T>
/// SELECT * FROM user WHERE name = 'Sam' OR name = 'Mike'
QuickeyDB.getInstance!<UserSchema>()!.where({'name': 'Kenzy Limon'}).or({'age': '21'}).toList();
/// To use any other operation just pass it after attribute
// SELECT * FROM user where age >= 18
QuickeyDB.getInstance!<UserSchema>()!.where({'age >= ?': 18}).toList();
// SELECT * FROM user ORDER BY name DESC
QuickeyDB.getInstance!<UserSchema>()!.order(['age']).toList();
// SELECT * FROM user GROUP BY name HAVING LENGTH(name) > 3
QuickeyDB.getInstance!<UserSchema>()!.group(['name']).having('LENGTH(name) > 5').toList();
// SELECT * FROM user LIMIT 50 OFFSET 100
QuickeyDB.getInstance!<UserSchema>()!.limit(1).offset(10).toList();
// SELECT DISTINCT * FROM user
QuickeyDB.getInstance!<UserSchema>()!.distinct().toList();
Include Queries
// SELECT * FROM user
// SELECT * FROM task WHERE id IN (1)
QuickeyDB.getInstance!<UserSchema>()?.includes([TaskSchema]).toList()
// [User(id: 1, name: 'Kenzy Limon',... task: [Task(id: 1, name: 'Complete ORM', body: 'Do nice Documentation')])]
Join Queries
// SELECT
// task.*,
// user.id AS user_id,
// user.name AS user_name,
// FROM task
// INNER JOIN user ON user.id = task.user_id
QuickeyDB.getInstance!<TaskSchema>()!.joins([UserSchema]).toList();
// [Task(id: 1, name: 'Complete ORM', body: 'Do nice Documentation',... user: User(id: 1, name: 'Kenzy Limon',...))]
Finder Queries
// SELECT * FROM user WHERE name = 'Kenzy Limon' LIMIT 1
QuickeyDB.getInstance!<UserSchema>()!.isExists({'name': 'John Doe'}); // true
// SELECT * FROM user WHERE id = 1 LIMIT 1
QuickeyDB.getInstance!<UserSchema>()!.find(1); // User
// SELECT * FROM user WHERE name = 'Mike' LIMIT 1
QuickeyDB.getInstance!<UserSchema>()!.findBy({'name': 'Jane Doe'}); // User
// SELECT * FROM user
QuickeyDB.getInstance!<UserSchema>()!.first; // first item
// SELECT * FROM user
QuickeyDB.getInstance!<UserSchema>()!.last; // last item
// SELECT * FROM user LIMIT 3
QuickeyDB.getInstance!<UserSchema>()!.take(10);
Data Persistence
final user = User(id: 1, name: 'Kenzy Limon', a
