Database & ORM
Powerful database abstraction with migrations, query builder, and ORM capabilities for Khadem Dart.
DatabaseManagerKhademModelQueryBuilderMigrationsSeeders
Database Configuration
Database Manager Setup
dart
// config/database.dart
import 'package:khadem/khadem.dart';
class DatabaseConfig {
static Map<String, dynamic> get config => {
'driver': 'mysql', // Currently only MySQL is supported
'host': Khadem.env.getOrDefault('DB_HOST', 'localhost'),
'port': Khadem.env.getInt('DB_PORT', 3306),
'database': Khadem.env.get('DB_DATABASE'),
'username': Khadem.env.get('DB_USERNAME'),
'password': Khadem.env.get('DB_PASSWORD'),
'charset': 'utf8mb4',
'collation': 'utf8mb4_unicode_ci',
'run_migrations': true,
'run_seeders': false,
};
}
// In your .env file:
// DB_HOST=localhost
// DB_PORT=3306
// DB_DATABASE=khadem_app
// DB_USERNAME=root
// DB_PASSWORD=secret💡 Note: Configuration is loaded from config/database.dart
⚡ Tip: Use environment variables for sensitive connection details
MySQL
Fully SupportedProduction-ready relational database with full ORM support, migrations, and query builder.
mysql✨ RecommendedSQLite & PostgreSQL
Coming SoonSQLite and PostgreSQL drivers are planned for future releases.
sqlitepgsqlMigrations
Creating Migrations
dart
// database/migrations/0_create_users_table.dart
import 'package:khadem/khadem.dart';
class CreateUsersTable implements MigrationFile {
@override
String get name => 'create_users_table';
@override
Future<void> up(SchemaBuilder schema) async {
schema.create('users', (Blueprint table) {
table.id();
table.string('name');
table.string('email').unique();
table.timestamp('email_verified_at').nullable();
table.string('password');
table.timestamps();
});
}
@override
Future<void> down(SchemaBuilder schema) async {
schema.dropIfExists('users');
}
}📁 Location: database/migrations/
🔄 Naming: timestamp_description.dart
dart
// Available column types in Blueprint
schema.create('products', (Blueprint table) {
// Primary Keys
table.id(); // Auto-incrementing BIGINT primary key
table.id('custom_id'); // Custom primary key name
// Strings
table.string('name', length: 100); // VARCHAR(100)
table.text('description'); // TEXT
// Numbers
table.integer('quantity'); // INT
table.bigInteger('views'); // BIGINT
table.float('price'); // FLOAT
// Dates & Times
table.date('birth_date'); // DATE
table.timestamp('created_at'); // TIMESTAMP
// Boolean & Enum
table.boolean('is_active'); // BOOLEAN/TINYINT
table.enumColumn('status', ['pending', 'approved', 'rejected']);
// JSON
table.json('metadata'); // JSON column
// Special helper methods
table.timestamps(); // Adds created_at and updated_at
table.softDeletes(); // Adds deleted_at for soft deletes
// Foreign Keys & Relations
table.foreignId('user_id'); // BIGINT UNSIGNED for foreign keys
table.morphs('commentable'); // Polymorphic relation columns
// Creates: commentable_type (VARCHAR) and commentable_id (BIGINT)
});dart
// Using the Migrator class
import 'package:khadem/khadem.dart';
final migrator = Migrator(Khadem.db);
// Run all pending migrations
await migrator.upAll();
// Rollback all migrations
await migrator.downAll();
// Reset and re-run all migrations
await migrator.reset();
// Refresh database (downAll + upAll)
await migrator.refresh();
// Show migration status
await migrator.status();
// Run specific migration
await migrator.up('create_users_table');
// Rollback specific migration
await migrator.down('create_users_table');Khadem Model (ORM)
Model Definition
dart
// app/models/user.dart
import 'package:khadem/khadem.dart';
class User extends KhademModel<User> with Timestamps, HasRelationships {
User({
this.name,
this.email,
this.password,
int? id,
}) {
this.id = id;
}
String? name;
String? email;
String? password;
@override
String get tableName => 'users';
@override
List<String> get fillable => ['name', 'email', 'password'];
@override
List<String> get hidden => ['password'];
@override
List<String> get protected => ['password']; // Never in JSON
@override
Map<String, dynamic> get casts => {
'created_at': DateTime,
'updated_at': DateTime,
};
@override
Map<String, RelationDefinition> get relations => {
'posts': hasMany<Post>(
foreignKey: 'user_id',
relatedTable: 'posts',
factory: () => Post(),
),
};
@override
dynamic getField(String key) {
return switch (key) {
'id' => id,
'name' => name,
'email' => email,
'password' => password,
'created_at' => createdAt,
'updated_at' => updatedAt,
_ => null
};
}
@override
void setField(String key, dynamic value) {
switch (key) {
case 'id': id = value; break;
case 'name': name = value; break;
case 'email': email = value; break;
case 'password': password = value; break;
case 'created_at': createdAt = value; break;
case 'updated_at': updatedAt = value; break;
}
}
@override
User newFactory(Map<String, dynamic> data) {
return User()..fromJson(data);
}
}📁 Location: app/models/
🔗 Extends: KhademModel
dart
// Create a new user
final user = User(name: 'John Doe', email: 'john@example.com', password: 'secret');
await user.save();
print('User created with ID: ${user.id}');
// Find user by ID using query builder
final foundUser = await User().query.where('id', '=', 1).first();
if (foundUser != null) {
print('Found: ${foundUser.name}');
}
// Find users by condition
final users = await User().query.where('email', '=', 'john@example.com').get();
print('Found ${users.length} users');
// Update user
user.name = 'John Smith';
await user.save();
// Delete user
await user.delete();
// Mass assignment with fillable protection
final newUser = User()..fromJson({
'name': 'Jane Doe',
'email': 'jane@example.com',
'password': 'secret',
'role': 'admin', // Ignored if not in fillable
});
await newUser.save();dart
// Load relationships
final user = await User().query.where('id', '=', 1).first();
await user?.load('posts');
// Eager load with query
final users = await User().query.withRelations(['posts']).get();
// Check if relation is loaded
if (user?.isRelationLoaded('posts') ?? false) {
final posts = user!.getRelation('posts');
}
// Load missing relations only
await user?.loadMissing(['posts', 'profile']);
// Get only specific attributes
final userData = user?.only(['name', 'email']);
// Get all except specific attributes
final userData = user?.except(['password']);Query Builder
Fluent Query Interface
dart
// Using query builder through models
import 'package:khadem/khadem.dart';
// Get all records
final users = await User().query.get();
// Get first record
final user = await User().query.first();
// Get specific columns
final users = await User().query.select(['name', 'email']).get();
// Where clauses
final activeUsers = await User().query
.where('is_active', '=', true)
.get();
// Multiple where conditions
final filteredUsers = await User().query
.where('is_active', '=', true)
.where('role', '=', 'admin')
.get();
// Ordering
final latestUsers = await User().query
.orderBy('created_at', direction: 'DESC')
.limit(10)
.get();
// Pagination
final result = await User().query.paginate(perPage: 15, page: 1);
print('Total: ${result.total}');
print('Current page: ${result.currentPage}');
print('Data: ${result.data.length} items');
// Count records
final count = await User().query.count();
// Check existence
final exists = await User().query
.where('email', '=', 'john@example.com')
.exists();
// Insert record using model
final user = User(
name: 'John Doe',
email: 'john@example.com',
);
await user.save();
// Update records using model
final user = await User().query.where('id', '=', 1).first();
if (user != null) {
user.name = 'John Smith';
await user.save();
}
// Delete records using model
final user = await User().query.where('id', '=', 1).first();
await user?.delete();🔧 Interface: QueryBuilderInterface
📊 Supports: Complex queries, joins, aggregations
dart
// Complex where conditions
final users = await User().query
.where('age', '>', 18)
.where('city', '=', 'New York')
.orWhere('city', '=', 'Los Angeles')
.get();
// Ordering and pagination
final users = await User().query
.orderBy('created_at', direction: 'DESC')
.limit(10)
.offset(20)
.get();
// whereHas - Query based on relationships
final usersWithPosts = await User().query
.whereHas('posts', (query) {
query.where('status', '=', 'published');
})
.get();
// Grouping with having
final query = User().query
.select(['role', 'COUNT(*) as count'])
.groupBy('role')
.having('count', '>', 5);
// Raw queries
final users = await User().query
.whereRaw('created_at > ?', [DateTime.now().subtract(Duration(days: 30))])
.get();
// JSON queries
final users = await User().query
.whereJsonContains('settings->notifications', 'email')
.get();dart
// Raw SQL queries using DatabaseManager
import 'package:khadem/khadem.dart';
final db = Khadem.db;
final connection = db.connection;
// Raw select
final results = await connection.query(
'SELECT * FROM users WHERE id = ?',
[1]
);
// Raw insert
await connection.execute(
'INSERT INTO users (name, email, created_at, updated_at) VALUES (?, ?, ?, ?)',
['John Doe', 'john@example.com', DateTime.now(), DateTime.now()]
);
// Raw update
await connection.execute(
'UPDATE users SET name = ?, updated_at = ? WHERE id = ?',
['John Smith', DateTime.now(), 1]
);
// Raw delete
await connection.execute('DELETE FROM users WHERE id = ?', [1]);
// Use whereRaw in query builder for safer raw queries
final users = await User().query
.whereRaw('YEAR(created_at) = ?', [2024])
.get();Seeders
Database Seeding
dart
// database/seeders/database_seeder.dart
import 'package:khadem/khadem.dart';
class DatabaseSeeder implements Seeder {
@override
String get name => 'database_seeder';
@override
Future<void> run() async {
// Call other seeders
await UserSeeder().run();
await PostSeeder().run();
await CategorySeeder().run();
}
}
// database/seeders/user_seeder.dart
class UserSeeder implements Seeder {
@override
String get name => 'user_seeder';
@override
Future<void> run() async {
// Create test users using models
final users = [
User(name: 'John Doe', email: 'john@example.com', password: 'hashed_password'),
User(name: 'Jane Smith', email: 'jane@example.com', password: 'hashed_password'),
];
for (final user in users) {
await user.save();
}
}
}📁 Location: database/seeders/
🎯 Purpose: Populate database with test data
dart
// Using factories for seeding
class UserFactory {
static Map<String, dynamic> make() {
return {
'name': 'Test User',
'email': 'test@example.com',
'password': 'hashed_password',
'created_at': DateTime.now(),
'updated_at': DateTime.now(),
};
}
static Map<String, dynamic> makeWithOverrides(Map<String, dynamic> overrides) {
return {...make(), ...overrides};
}
}
// In seeder
class UserSeeder implements Seeder {
@override
String get name => 'user_seeder';
@override
Future<void> run() async {
// Create 10 users using factory
for (var i = 0; i < 10; i++) {
final userData = UserFactory.makeWithOverrides({
'name': 'User $i',
'email': 'user$i@example.com',
});
final user = User()..fromJson(userData);
await user.save();
}
}
}dart
// Using Seeder class
import 'package:khadem/khadem.dart';
// Create and run database seeder
final databaseSeeder = DatabaseSeeder();
await databaseSeeder.run();
// Run specific seeder
final userSeeder = UserSeeder();
await userSeeder.run();
// Or manually seed data
await User(name: 'Admin', email: 'admin@example.com', password: 'hashed').save();
await User(name: 'User', email: 'user@example.com', password: 'hashed').save();Database Transactions
Transaction Management
dart
// Using DatabaseManager transactions
import 'package:khadem/khadem.dart';
final connection = Khadem.db.connection;
await connection.transaction((trx) async {
// Create user
final user = User(name: 'John Doe', email: 'john@example.com');
await user.save();
// Create profile for the user
final profile = Profile(userId: user.id, bio: 'Software developer');
await profile.save();
// If any operation fails, the entire transaction is rolled back
});
// Transaction with error handling
try {
await connection.transaction((trx) async {
final user = User(name: 'Jane Doe', email: 'jane@example.com');
await user.save();
// This might fail
final order = Order(userId: user.id, total: 100.0);
await order.save();
});
print('Transaction completed successfully');
} catch (e) {
print('Transaction failed: $e');
// All changes are automatically rolled back
}🔒 Ensures: Data consistency and integrity
⚡ Performance: Batch operations efficiently
