Repository
Repositories provide CRUD operations with flexible input handling, accepting tracked models, DTOs, or raw maps.
Snippet context
- Snippets focus on repository calls and omit full setup.
- You can obtain a repository from either:
- a
DataSource/QueryContext(explicit, recommended for multi-database flows), or - the generated model helper class (uses the default connection).
- a
The default connection is tracked by ConnectionManager and is typically set when you call await dataSource.init() (first one auto-defaults) or dataSource.setAsDefault().
Getting a Repository
- Default connection
- From DataSource
Future<void> getRepositoryStaticHelpers() async {
// Assumes a default connection is configured (see DataSource docs).
final userRepo = Users.repo();
await userRepo.find(1);
}
Future<void> getRepositoryExample(DataSource dataSource) async {
final userRepo = dataSource.repo<$User>();
}
Insert Operations
Insert Single
Future<void> insertExamples(DataSource dataSource) async {
final userRepo = dataSource.repo<$User>();
// With tracked model
final user = await userRepo.insert(
$User(id: 0, email: 'john@example.com', name: 'John'),
);
// With insert DTO
final user2 = await userRepo.insert(
UserInsertDto(email: 'john@example.com', name: 'John'),
);
// With raw map
final user3 = await userRepo.insert({
'email': 'john@example.com',
'name': 'John',
});
}
Insert Many
Future<void> insertManyExample(DataSource dataSource) async {
final userRepo = dataSource.repo<$User>();
final users = await userRepo.insertMany([
$User(id: 0, email: 'user1@example.com'),
$User(id: 0, email: 'user2@example.com'),
]);
}
Upsert (Insert or Update)
Future<void> upsertExample(DataSource dataSource) async {
final userRepo = dataSource.repo<$User>();
// Insert if not exists, update if exists
final user = await userRepo.upsert(
$User(id: 1, email: 'john@example.com', name: 'Updated Name'),
);
}
Find Operations
Find by Primary Key
Future<void> findExamples(DataSource dataSource) async {
final userRepo = dataSource.repo<$User>();
final user = await userRepo.find(1); // Returns null if not found
final user2 = await userRepo.findOrFail(1); // Throws if not found
final users = await userRepo.findMany([1, 2, 3]);
}
Get All
Future<void> firstCountExamples(DataSource dataSource) async {
final userRepo = dataSource.repo<$User>();
final user = await userRepo.first();
final user2 = await userRepo.first(where: {'active': true});
final count = await userRepo.count();
final activeCount = await userRepo.count(where: {'active': true});
final hasActive = await userRepo.exists({'active': true});
}
Count & Exists
Future<void> firstCountExamples(DataSource dataSource) async {
final userRepo = dataSource.repo<$User>();
final user = await userRepo.first();
final user2 = await userRepo.first(where: {'active': true});
final count = await userRepo.count();
final activeCount = await userRepo.count(where: {'active': true});
final hasActive = await userRepo.exists({'active': true});
}
Update Operations
Update Single
Future<void> updateExamples(DataSource dataSource) async {
final userRepo = dataSource.repo<$User>();
final user = await userRepo.find(1);
// With tracked model (uses primary key)
if (user != null) {
user.setAttribute('name', 'Updated Name');
final updated = await userRepo.update(user);
}
// With DTO and where clause
final updated2 = await userRepo.update(
UserUpdateDto(name: 'Updated Name'),
where: {'id': 1},
);
// With Query callback
final updated3 = await userRepo.update(
UserUpdateDto(name: 'Updated Name'),
where: (Query<$User> q) => q.whereEquals('email', 'john@example.com'),
);
}
Update Many
Future<void> updateManyExample(DataSource dataSource) async {
final userRepo = dataSource.repo<$User>();
final updated = await userRepo.updateMany([
$User(id: 1, email: 'user1@example.com', name: 'Name 1'),
$User(id: 2, email: 'user2@example.com', name: 'Name 2'),
]);
}
Where Parameter Types
The where parameter accepts various input types:
Future<void> whereTypesExamples(DataSource dataSource) async {
final userRepo = dataSource.repo<$User>();
// Map
await userRepo.update(UserUpdateDto(name: 'Test'), where: {'id': 1});
// Partial entity
await userRepo.update(
UserUpdateDto(name: 'Test'),
where: $UserPartial(id: 1),
);
// DTO
await userRepo.update(
UserUpdateDto(name: 'Test'),
where: UserUpdateDto(email: 'john@example.com'),
);
// Query callback (must type the parameter!)
await userRepo.update(
UserUpdateDto(name: 'Test'),
where: (Query<$User> q) => q.whereEquals('email', 'test@example.com'),
);
}
Typed Where Callbacks
Future<void> whereTypedCallbackExample(DataSource dataSource) async {
final userRepo = dataSource.repo<$User>();
await userRepo.update(
UserUpdateDto(name: 'Test'),
where: (Query<$User> q) =>
q.whereTyped((p) => p.email.eq('test@example.com')),
);
}
Important
When using a callback function for where, the parameter is dynamic unless you
explicitly type it. Untyped callbacks still work, but you lose static checking.
If you want typed predicate field accessors, type the parameter.
// ✅ Preferred - typed parameter enables typed predicate fields
// where: (Query<$User> q) => q.whereTyped((p) => p.email.eq('test@example.com'))
//
// ✅ Works, but `q` is dynamic (less static checking)
// where: (q) => q.whereTyped((p) => p.email.eq('test@example.com'))
Delete Operations
Delete Single
Future<void> deleteExamples(DataSource dataSource) async {
final userRepo = dataSource.repo<$User>();
final user = await userRepo.find(1);
// By primary key
await userRepo.delete(1);
// By tracked model
if (user != null) {
await userRepo.delete(user);
}
// By where clause
await userRepo.delete({'email': 'john@example.com'});
// By Query callback
await userRepo.delete((Query<$User> q) => q.whereEquals('role', 'guest'));
}
Delete Many
Future<void> deleteManyExamples(DataSource dataSource) async {
final userRepo = dataSource.repo<$User>();
await userRepo.deleteByIds([1, 2, 3]);
await userRepo.deleteMany([
{'id': 1},
(Query<$User> q) => q.whereEquals('role', 'guest'),
]);
}
Soft Delete Operations
For models with SoftDeletes:
Future<void> softDeleteExamples(DataSource dataSource) async {
final userRepo = dataSource.repo<$User>();
final user = await userRepo.find(1);
if (user != null) {
// Soft delete (sets deleted_at)
await userRepo.delete(user);
// Restore
await userRepo.restore(user);
await userRepo.restore({'id': 1});
// Force delete (permanently removes)
await userRepo.forceDelete(user);
}
}
Working with Relations
Future<void> relationExamples(DataSource dataSource) async {
final userRepo = dataSource.repo<$User>();
final user = await userRepo.find(1);
if (user != null) {
// Load relations
await user.load(['posts', 'profile']);
}
}
Error Handling
Future<void> errorHandlingExample(DataSource dataSource) async {
final userRepo = dataSource.repo<$User>();
try {
final user = await userRepo.findOrFail(999);
} on ModelNotFoundException catch (e) {
print('User not found: ${e.key}');
}
try {
await userRepo.update(UserUpdateDto(name: 'Test'), where: {'id': 999});
} on NoRowsAffectedException {
print('No rows were updated');
}
}