Query Builder

The QueryBuilderInterface in Khadem offers a fluent, expressive, and type-safe interface for querying your database. It supports common operations like select, insert, update, delete, pagination, and aggregation, all while supporting model hydration and eager loading.

Selecting Records

Use select and where to fetch records.
dart

// Select specific columns
final users = await User().query
  .select(['id', 'name', 'email'])
  .where('status', '=', 'active')
  .orderBy('name')
  .get();

// Select all columns (default)
final users = await User().query
  .where('status', '=', 'active')
  .get();

// Get first record
final user = await User().query
  .where('email', '=', 'john@example.com')
  .first();

// Get single record or null
final user = await User().query
  .where('id', '=', 1)
  .first();

Filtering with WHERE and OR

Chain where, orWhere, and whereRaw conditions fluently.
dart

final results = await User().query
  .where('role', '=', 'admin')
  .orWhere('email', 'like', '%@example.com')
  .get();

Ordering and Limiting

Sort results with orderBy and limit the number of records.
dart

// Order by single column
final users = await User().query
  .orderBy('name')
  .get();

// Order by multiple columns
final users = await User().query
  .orderBy('created_at', direction: 'desc')
  .orderBy('name')
  .get();

// Limit and offset
final users = await User().query
  .orderBy('created_at', direction: 'desc')
  .limit(10)
  .get();

// Skip records with offset
final users = await User().query
  .orderBy('created_at', direction: 'desc')
  .limit(10)
  .offset(20) // Skip first 20 records
  .get();

Pagination

Paginate your results using paginate. Returns a PaginatedResult object.
dart

final paginated = await User().query
  .where('status', '=', 'active')
  .paginate(perPage: 10, page: 1);

print(paginated.data); // List<User>
print(paginated.total); // Total records

Inserting Records

Insert new records using insert. Returns the inserted ID.
dart

final id = await User().query.insert({
  'name': 'John Doe',
  'email': 'john@example.com'
});

Bulk Operations

Perform bulk insert, update, and delete operations efficiently.
dart

// Bulk insert multiple records
final userIds = [];
for (final userData in userDataList) {
  final id = await User().query.insert(userData);
  userIds.add(id);
}

// Bulk update multiple records
await User().query
  .where('status', '=', 'inactive')
  .update({'status': 'active'});

// Bulk delete with conditions
await User().query
  .where('last_login', '<', DateTime.now().subtract(Duration(days: 365)))
  .delete();

// Conditional bulk operations
await User().query
  .where('subscription_status', '=', 'expired')
  .where('created_at', '<', DateTime.now().subtract(Duration(days: 30)))
  .update({'status': 'suspended'});

Updating Records

Perform updates only when a where condition exists.
dart

await User().query
  .where('id', '=', 5)
  .update({
    'name': 'Updated Name'
  });

// Update multiple fields
await User().query
  .where('email', '=', 'old@example.com')
  .update({
    'email': 'new@example.com',
    'email_verified_at': DateTime.now(),
  });

// Update with complex conditions
await User().query
  .where('status', '=', 'pending')
  .where('created_at', '<', DateTime.now().subtract(Duration(days: 7)))
  .update({
    'status': 'expired',
    'updated_at': DateTime.now(),
  });

Deleting Records

Use delete carefully—it requires a where clause.
dart

await User().query
  .where('id', '=', 10)
  .delete();

// Delete with multiple conditions
await User().query
  .where('status', '=', 'inactive')
  .where('last_login', '<', DateTime.now().subtract(Duration(days: 365)))
  .delete();

// Soft delete (if implemented in your model)
await User().query
  .where('id', '=', 10)
  .update({
    'deleted_at': DateTime.now(),
  });

Eager Loading Relations

Use withRelations to load related data.
dart

// Basic eager loading
final user = await User().query
  .withRelations(['posts', 'profile'])
  .where('id', '=', 1)
  .first();

// Access loaded relations
final posts = user?.relation.get('posts'); // List<Post>
final profile = user?.relation.get('profile'); // Profile

// Multiple relations with conditions
final users = await User().query
  .withRelations(['posts', 'comments'])
  .where('status', '=', 'active')
  .get();

// Nested eager loading (if supported)
final users = await User().query
  .withRelations(['posts.comments'])
  .get();

// Eager loading with query constraints
final users = await User().query
  .withRelations(['posts' => (query) => query.where('published', '=', true).limit(5)])
  .get();

Aggregates (count, sum, avg, min, max)

Easily calculate aggregates like count, sum, avg, min, and max.
dart

final total = await User().query.count();
final avgAge = await User().query.avg('age');
final maxAge = await User().query.max('age');
final minAge = await User().query.min('age');

Exists and Pluck

Check if records exist or extract single column values.
dart

// Check if any records exist
final hasUsers = await User().query
  .where('status', '=', 'active')
  .exists();

// Extract single column values
final emails = await User().query
  .where('status', '=', 'active')
  .pluck('email');

final ids = await User().query.pluck('id');

Streaming Results

Use asStream() for memory-efficient processing of large datasets.
dart

// Process large datasets efficiently
final userStream = User().query
  .where('created_at', '>', DateTime.now().subtract(Duration(days: 30)))
  .asStream();

await for (final user in userStream) {
  // Process each user
  print('Processing user: ${user.name}');
  // Send email, export data, etc.
}

Advanced Query Features

Combine multiple conditions, use raw SQL, and chain complex queries.
dart

// Complex where conditions
final users = await User().query
  .where('age', '>', 18)
  .where((q) => q
    .where('role', '=', 'admin')
    .orWhere('role', '=', 'moderator')
  )
  .whereNotNull('email_verified_at')
  .get();

// Raw SQL where clause
final users = await User().query
  .whereRaw('DATE(created_at) = CURDATE()')
  .get();

// Group by and having
final stats = await User().query
  .select(['role', 'COUNT(*) as count'])
  .groupBy('role')
  .having('count', '>', 5)
  .get();

// Clone queries for reuse
final baseQuery = User().query.where('status', '=', 'active');
final admins = await baseQuery.clone().where('role', '=', 'admin').get();
final moderators = await baseQuery.clone().where('role', '=', 'moderator').get();

Conditional Queries

Use when to conditionally add clauses to your query.
dart

// Basic conditional query
final query = User().query.when(isAdmin, (q) => q.where('role', '=', 'admin'));
final users = await query.get();

// Multiple conditions
final users = await User().query
  .when(searchTerm != null, (q) => q.where('name', 'like', '%$searchTerm%'))
  .when(status != null, (q) => q.where('status', '=', status))
  .when(sortBy != null, (q) => q.orderBy(sortBy!))
  .get();

// Complex conditional logic
final users = await User().query
  .when(includeInactive, (q) => q.where('status', '=', 'active'))
  .when(!includeInactive, (q) => q.whereIn('status', ['active', 'pending']))
  .get();

// Conditional eager loading
final users = await User().query
  .when(loadPosts, (q) => q.withRelations(['posts']))
  .when(loadProfile, (q) => q.withRelations(['profile']))
  .get();

Raw SQL Output

Use toSql() to preview the raw SQL query string.
dart

final sql = User().query
  .where('id', '=', 1)
  .toSql();

print(sql); // Raw SQL query string

On this page