Skip to content

RoutedDart/ormed

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Ormed

Pub Version License: MIT Documentation Buy Me A Coffee GitHub Stars

A strongly typed ORM for Dart inspired by Laravel Eloquent, bringing familiar patterns from Eloquent, GORM, SQLAlchemy, and ActiveRecord to Dart developers.

Part of the Routed ecosystem.


✨ Features

  • Annotation-based models β€” Define tables, columns, and relationships with @OrmModel, @OrmField, @OrmRelation
  • Code generation β€” Auto-generate model definitions, codecs, DTOs, and factories via build_runner
  • Fluent query builder β€” Laravel-style API with where, orderBy, join, limit, and more
  • Eager & lazy loading β€” Load relations upfront or on-demand, with nested paths ('comments.author')
  • Lazy loading prevention β€” Catch N+1 queries in development with ModelRelations.preventsLazyLoading
  • Aggregate loaders β€” Load counts, sums, averages without fetching full collections (loadCount(), loadSum(), etc.)
  • Relation mutations β€” associate(), attach(), detach(), sync() for managing relationships
  • Schema migrations β€” CLI tooling for creating, applying, and rolling back migrations
  • Multi-database support β€” SQLite, PostgreSQL, MySQL/MariaDB
  • Driver capabilities β€” Runtime feature detection for cross-database compatibility
  • Multi-tenant connections β€” Manage multiple database connections with role-based routing
  • Observability β€” Structured logging, query instrumentation, and tracing hooks
  • Soft deletes β€” Built-in SoftDeletes mixin with scoped queries
  • Repository pattern β€” Bulk inserts, upserts, and JSON updates
  • Testing β€” Robust database isolation with ormedGroup and ormedTest. See the Testing Guide.

πŸ—„οΈ Supported Databases

Database Package Description
SQLite ormed_sqlite Via package:sqlite3
PostgreSQL ormed_postgres Via package:postgres (v3)
MySQL / MariaDB ormed_mysql Via package:mysql_client_plus

πŸš€ Quick Start

1. Install the CLI

dart pub global activate ormed_cli

2. Add dependencies

dependencies:
  ormed: any
  ormed_sqlite: any  # or your preferred driver

dev_dependencies:
  build_runner: ^2.4.0

3. Define a model

import 'package:ormed/ormed.dart';

part 'user.orm.dart';

@OrmModel(table: 'users')
class User {
  const User({required this.id, required this.email, this.name});

  @OrmField(isPrimaryKey: true, autoIncrement: true)
  final int id;

  @OrmField(isUnique: true)
  final String email;

  final String? name;
}

3. Generate code

dart run build_runner build --delete-conflicting-outputs

4. Query your data

import 'package:ormed/ormed.dart';
import 'lib/src/database/datasource.dart'; // Generated by 'ormed init'

void main() async {
  // Use the generated entrypoint
  final ds = createDataSource();
  await ds.init();

  // Insert
  await ds.repo<$User>().insert($UserInsertDto(
    email: 'john@example.com',
    name: 'John Doe',
  ));

  // Query with eager loading
  final users = await ds.query<$User>()
      .withRelation('posts')
      .withCount('posts', alias: 'post_count')
      .orderByDesc('created_at')
      .limit(10)
      .get();

  // Update
  await ds.query<$User>()
      .whereEquals('id', 1)
      .update({'name': 'Jane Doe'});

  // Eager load relations
  final posts = await ds.query<$Post>()
      .withRelation('author')
      .withRelation('tags')
      .withCount('comments')
      .get();

  // Lazy load relations
  final post = await ds.query<$Post>().firstOrFail();
  await post.load('author');
  await post.loadMissing(['tags', 'comments']);

  // Transaction
  await ds.transaction(() async {
    await ds.repo<$User>().insert(user1);
    await ds.repo<$User>().insert(user2);
  });

  // Cleanup
  await ds.dispose();
}
Alternative: Manual Setup (advanced)
import 'package:ormed_sqlite/ormed_sqlite.dart';

void main() async {
  final registry = ModelRegistry()..register(UserOrmDefinition.definition);
  final adapter = SqliteDriverAdapter.file('app.sqlite');
  final context = QueryContext(registry: registry, driver: adapter);

  final users = await context.query<$User>()
      .whereEquals('active', true)
      .get();
}

Test helper

ormed init also writes lib/test/helpers/ormed_test_helper.dart. The helper wires up two SQLite DataSources via setUpOrmed (primary + analytics), runs the sample _CreateTestUsersTable migration, and exposes primaryTestConfig, analyticsTestConfig, and helpers such as primaryTestConnection(). Import it in your tests and pass the configs into ormedGroup or call primaryTestConnection() when you just need the default connection.


πŸ“¦ Packages

ORM Core & Drivers

Package Description
ormed Core ORM with annotations, query builder, migrations, codecs, and code generator
ormed_sqlite SQLite driver adapter with JSON1, FTS5, and R*Tree support
ormed_postgres PostgreSQL driver with full type support (UUID, JSONB, arrays, ranges, FTS)
ormed_mysql MySQL/MariaDB driver with JSON, spatial types, and SET support
ormed_cli CLI for migrations, seeding, schema operations, and project scaffolding

Development & Testing

Package Description
driver_tests Shared driver-agnostic integration test suites
orm_playground Demo application with end-to-end examples

πŸ› οΈ CLI Commands

Note: These examples assume you have globally activated the CLI via dart pub global activate ormed_cli. If not, use dart run ormed_cli:ormed instead of ormed.

# Initialize project structure
ormed init

# Create a new migration
ormed make --name create_users_table

# Run pending migrations
ormed migrate

# Preview migrations without executing
ormed migrate --pretend

# Rollback migrations
ormed migrate:rollback --steps 1

# Reset and re-run all migrations
ormed migrate:fresh

# Check migration status
ormed migrate:status

# Describe current schema
ormed schema:describe

# Run database seeders
dart run ormed_cli:ormed seed
dart run ormed_cli:ormed seed --class DemoContentSeeder

# Multi-tenant: apply to specific connection
dart run ormed_cli:ormed migrate --connection analytics

See ormed_cli for complete documentation of all commands and options.


πŸ”— Relations

Define relationships with @OrmRelation:

@OrmModel(table: 'posts')
class Post {
  final int id;
  final int authorId;
  final String title;

  // Belongs to
  @OrmRelation.belongsTo(related: User, foreignKey: 'author_id')
  final User? author;

  // Has many
  @OrmRelation.hasMany(related: Comment, foreignKey: 'post_id')
  final List<Comment> comments;

  // Many to many
  @OrmRelation.manyToMany(
    related: Tag,
    pivot: 'post_tags',
    foreignPivotKey: 'post_id',
    relatedPivotKey: 'tag_id',
  )
  final List<Tag> tags;
}

Query with relations:

// Eager loading
final posts = await ds.query<$Post>()
    .with_(['author', 'tags', 'comments.author'])
    .get();

// Relation aggregates
final posts = await ds.query<$Post>()
    .withCount('comments')
    .withExists('tags')
    .get();

// Filter by relation
final publishedWithComments = await ds.query<$Post>()
    .whereHas('comments', (q) => q.whereEquals('approved', true))
    .get();

πŸ“ Migrations

class CreatePostsTable extends Migration {
  @override
  void up(SchemaBuilder schema) {
    schema.create('posts', (table) {
      table.id();
      table.integer('author_id').references('users', 'id');
      table.string('title');
      table.text('body').nullable();
      table.boolean('published').defaultValue(false);
      table.timestamps();
      table.softDeletes();
      
      table.index(['author_id']);
    });
  }

  @override
  void down(SchemaBuilder schema) {
    schema.drop('posts');
  }
}

πŸ“š Documentation

Full documentation is available at ormed.vercel.app.

Topics Covered

  • CLI Reference β€” Complete CLI commands and options
  • Query Builder β€” Full query API reference
  • Relations & Lazy Loading β€” Eager/lazy loading and relation mutations
  • Migrations β€” Schema migrations and schema builder API
  • Data Source β€” Runtime database access patterns
  • Code Generation β€” Model annotations and generated code
  • Model Factories β€” Test data generation and seeding
  • Connectors β€” Connection management and multi-tenancy
  • Observability β€” Logging, instrumentation, and tracing
  • Driver Capabilities β€” Cross-database compatibility and feature detection
  • Best Practices β€” Optimization strategies, patterns, and anti-patterns

🀝 Contributing

Contributions are welcome! Please feel free to submit issues and pull requests.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

πŸ’– Support

If you find this project helpful, consider supporting its development:

Buy Me A Coffee


πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.