Skip to main content

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).

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

Future<void> getRepositoryStaticHelpers() async {
// Assumes a default connection is configured (see DataSource docs).
final userRepo = Users.repo();
await userRepo.find(1);
}

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');
}
}