Queries
Ormed has a few ways to reach the database because a list screen, a model mutation, and a transaction have different responsibilities. Pick the smallest layer that matches the job, then move to a lower layer when you need more control.
Pick an API by the job
| If you need to... | Use | Why |
|---|---|---|
| Compose filters, joins, projections, or aggregates | Query Builder | Controls the shape of a typed read or write without hiding the SQL work |
| Insert, update, delete, or upsert a model | Repository | Keeps model-centric mutations and persistence rules together |
| Initialize connections, run transactions, or route databases | DataSource | Owns connection lifecycle and the boundary around multiple operations |
| Explore a table or run SQL before you have a model | Direct Database Access | Lets you start with the schema and add generated models when they become useful |
A common request flow
This example shows the usual split: the query builder reads a shaped result, while a repository handles a model write. The generated model and query definitions come from the model setup described in Defining Models.
Future<void> introQueryExample(DataSource dataSource) async {
// Query with fluent API
final users = await dataSource
.query<$User>()
.whereEquals('active', true)
.orderBy('createdAt', descending: true)
.limit(10)
.get();
// Repository operations
final repo = dataSource.repo<$User>();
final user = await repo.find(1);
if (user != null) {
user.setAttribute('name', 'John');
await repo.update(user);
}
}
For a multi-step change, put the read and write operations inside a transaction so they succeed or fail together. Keep connection setup in the DataSource; keep filtering and projections close to the query that needs them.
Choose a starting path
- Listing, searching, or reporting: start with the Query Builder. Add joins, predicates, ordering, pagination, or projections as the screen requires.
- CRUD around a model: start with the Repository. It is the clearest home for create, update, delete, and model-oriented workflows.
- Boot, transactions, or multiple databases: start with DataSource, then call the query or repository API inside that lifecycle boundary.
- No stable model yet: use Direct Database Access while you learn the schema. Introduce a generated model when repeated access benefits from types and shared behavior.
Learn in this order
- Query Builder: core read/write fluency.
- Repository: structured model mutations.
- Loading Relations: association-aware reads.
- DataSource: boot, connection control, transactions.
- JSON Queries + Caching: specialized tuning.
Keep the boundaries clear
The query builder controls SQL shape. The repository controls model workflow. The DataSource controls connection lifecycle and transaction scope. Keeping those responsibilities separate makes it easier to test a query, change persistence behavior, or add another database without rewriting every call site.