Code Generation
Ormed uses source generation to produce strongly-typed models and metadata. Start from plain Dart classes annotated with @OrmModel and let build_runner produce definitions consumed by the runtime.
Running the Generator
Add the builder and run:
dart run build_runner build --delete-conflicting-outputs
Or use watch mode for development:
dart run build_runner watch --delete-conflicting-outputs
Generated Files
The generator produces several files:
| File | Description |
|---|---|
<model>.ormed.dart | Model definition, codec, factory, and relation getters |
<model>.orm_model.json | Intermediate metadata for auto-registry (can be gitignored) |
lib/orm_registry.g.dart | Auto-generated registry of all ORM models |
Per-Model Generated Code
For each @OrmModel class, the generator creates:
$ModelName- Tracked model class with change trackingModelNameOrmDefinition- Model metadata and static helpers$ModelNamePartial- Partial entity for projectionsModelNameInsertDto/ModelNameUpdateDto- Data transfer objectsModelNameModelFactory- Factory helpers for test data (ifModelFactoryCapableis used)
Builder Configuration
Configure the builders via build.yaml:
Model Generator (ormed)
Generates .ormed.dart files for each annotated model:
targets:
$default:
builders:
ormed|ormed:
enabled: true
generate_for:
- lib/models/**
Auto-Registry Builder (orm_registry)
Aggregates all models into a single registry file:
targets:
$default:
builders:
ormed|orm_registry:
enabled: true
options:
output: lib/orm_registry.g.dart # default
Custom Output Location
targets:
$default:
builders:
ormed|orm_registry:
options:
output: lib/src/database/models.g.dart
Disabling Auto-Registry
If you prefer manual registration:
targets:
$default:
builders:
ormed|orm_registry:
enabled: false
Then register models manually:
void manualRegistration() {
final registry = ModelRegistry()
..register(UserOrmDefinition.definition)
..register(PostOrmDefinition.definition)
..registerTypeAlias<User>(UserOrmDefinition.definition);
}
Generated Registry Helpers
The orm_registry.g.dart file provides:
Future<void> registryUsage() async {
// Pre-populated registry
final registry = bootstrapOrm();
// Registry with factory support
final registryWithFactories = bootstrapOrm();
// Extension method
final customRegistry = ModelRegistry()..registerGeneratedModels();
// Direct access to definitions
final definitions = generatedOrmModelDefinitions;
}
Constructor Targeting
By default, the generator uses the first generative constructor. Override with the constructor parameter:
// Override with the `constructor` parameter:
// @OrmModel(
// table: 'users',
// constructor: 'fromDatabase',
// )
// class User extends Model<User> {
// // Default constructor - NOT used by generator
// const User({required this.id, required this.email});
//
// // Named constructor that the generator will use
// const User.fromDatabase({required this.id, required this.email});
//
// @OrmField(isPrimaryKey: true)
// final int id;
// final String email;
// }
Generated Relation Getters
For models with @OrmRelation annotations, the generator produces relation getters that integrate with lazy loading:
// Generated relation getters for lazy loading integration:
//
// **Single relations** (`belongsTo`, `hasOne`):
// @override
// Author? get author {
// if (relationLoaded('author')) {
// return getRelation<Author>('author');
// }
// return super.author;
// }
//
// **List relations** (`hasMany`, `manyToMany`):
// @override
// List<Tag> get tags {
// if (relationLoaded('tags')) {
// return getRelationList<Tag>('tags');
// }
// return super.tags;
// }
Recommended .gitignore
# ORM generated files (regenerated by build_runner)
*.orm_model.json
# Optionally ignore generated Dart files if you regenerate on CI
# *.ormed.dart
# lib/orm_registry.g.dart
Driver-Specific Field Overrides
Use driverOverrides for per-driver behavior:
// Use driverOverrides for per-driver behavior:
// @OrmField(
// columnType: 'TEXT',
// driverOverrides: {
// 'postgres': OrmDriverFieldOverride(
// columnType: 'jsonb',
// codec: PostgresPayloadCodec,
// ),
// 'sqlite': OrmDriverFieldOverride(
// columnType: 'TEXT',
// codec: SqlitePayloadCodec,
// ),
// },
// )
// final Map<String, Object?> payload;
Tips
- Keep model constructors
constwhen possible - Use
@OrmField(ignore: true)for computed properties - Re-run
build_runnerwhenever annotations change - Generated files are not meant to be edited manually