Skip to main content

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:

FileDescription
<model>.ormed.dartModel definition, codec, factory, and relation getters
<model>.orm_model.jsonIntermediate metadata for auto-registry (can be gitignored)
lib/orm_registry.g.dartAuto-generated registry of all ORM models

Per-Model Generated Code

For each @OrmModel class, the generator creates:

  • $ModelName - Tracked model class with change tracking
  • ModelNameOrmDefinition - Model metadata and static helpers
  • $ModelNamePartial - Partial entity for projections
  • ModelNameInsertDto / ModelNameUpdateDto - Data transfer objects
  • ModelNameModelFactory - Factory helpers for test data (if ModelFactoryCapable is 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;
// }
# 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 const when possible
  • Use @OrmField(ignore: true) for computed properties
  • Re-run build_runner whenever annotations change
  • Generated files are not meant to be edited manually