TikalORM
A lightweight, strongly-typed Object-Relational Mapper (ORM) for Dart supporting PostgreSQL, SQLite, and MySQL/MariaDB.
████████╗██╗██╗ ██╗ █████╗ ██╗ ██████╗ ██████╗ ███╗ ███╗
╚══██╔══╝██║██║ ██╔╝██╔══██╗██║ ██╔═══██╗██╔══██╗████╗ ████║
██║ ██║█████╔╝ ███████║██║ ██║ ██║██████╔╝██╔████╔██║
██║ ██║██╔═██╗ ██╔══██║██║ ██║ ██║██╔══██╗██║╚██╔╝██║
██║ ██║██║ ██╗██║ ██║███████╗╚██████╔╝██║ ██║██║ ╚═╝ ██║
╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝
📌 Requirements
- Dart SDK:
3.13.5or higher.
🚀 Installation
Add tikal_orm to your project dependencies:
dart pub add tikal_orm
🛠️ Getting Started
1. Define a Model
Create your model file in lib/models/user.dart:
import 'package:tikal_orm/tikal_orm.dart';
@TikalTable('users')
class User {
User({this.id, required this.name, required this.email});
@PrimaryKey(autoIncrement: true)
int? id;
String name;
@Unique()
String email;
}
2. Code Generation
Run the code generator to generate the static registry and query helpers:
dart run tikal_orm:tikal generate
Tip: Use the watch flag to automatically regenerate files when saving changes:
dart run tikal_orm:tikal generate --watchModels are registered automatically—no need to manually pass
models:.
3. Configure and Connect
import 'models/user.dart';
import 'generated/tikal.dart';
Future<void> main() async {
// Configure database connection
await Tikal.configure(
database: PostgresConfig(
host: 'localhost',
port: 5432,
database: 'my_database',
username: 'my_username',
password: 'my_password',
),
);
try {
// Insert a record
final user = await Tikal.save(
User(name: 'Ana', email: 'ana@example.com'),
);
// Fetch records
final found = await Tikal.find<User>(user.id!);
final users = await Tikal.all<User>();
// Update record
user.name = 'Ana María';
await Tikal.save(user);
// Delete record
await Tikal.delete(user);
} finally {
await Tikal.close();
}
}
⚠️ Note:
configure()does not automatically create database tables. Tables must exist before performing CRUD operations.
🗄️ Supported Drivers
SQLite
await Tikal.configure(
database: SqliteConfig(path: 'app.db'),
);
MySQL / MariaDB
await Tikal.configure(
database: MysqlConfig(
host: 'localhost',
port: 3306,
database: 'my_database',
username: 'my_username',
password: 'my_password',
),
);
PostgreSQL
await Tikal.configure(
database: PostgresConfig(
host: 'localhost',
port: 5432,
database: 'my_database',
username: 'my_username',
password: 'my_password',
),
);
Note: Schema inspection and migrations are currently available exclusively for PostgreSQL.
🔍 Query Builder
TikalORM provides type-safe query building out of the box:
final users = await Tikal.query<User>()
.where(User_.name.equals('Ana'))
.orderBy(User_.email)
.get();
🌱 Database Seeders
Create Seeders
Generate seeder classes using the CLI:
dart run tikal_orm:tikal make:seeder UserSeeder
dart run tikal_orm:tikal make:seeder DatabaseSeeder
Implement Logic
1. Individual Seeder (lib/seeders/user_seeder.dart):
import 'package:tikal_orm/tikal_orm.dart';
import '../models/user.dart';
@Seeder()
class UserSeeder {
Future<void> run() async {
await Tikal.save(User(name: 'Admin', email: 'admin@example.com'));
}
}
2. Main Seeder Runner (lib/seeders/database_seeder.dart):
import 'package:tikal_orm/tikal_orm.dart';
import 'user_seeder.dart';
@Seeder(calls: [UserSeeder])
class DatabaseSeeder {}
Configure your database connection directly inside
bin/tikal_seed.dart(or import your existing config). This file is created once and will not be overwritten.
Run Seeders
# 1. Regenerate code to register seeders
dart run tikal_orm:tikal generate
# 2. Run all seeders (defaults to DatabaseSeeder)
dart run tikal_orm:tikal db:seed
# Run a specific seeder class
dart run tikal_orm:tikal db:seed --class=UserSeeder
💡 Seeder Rules & Behavior
- Reflection-Free / AOT Compatible: The CLI executes
bin/tikal_seed.dartusing static imports without dynamic reflection. - Constructor: Every seeder class requires an unnamed public constructor with no mandatory parameters.
- Execution:
Future<void> run()is required unless the class delegates entirely viacalls. - Execution Order:
callsexecute sequentially before the localrun()method. - Error Handling: Errors stop execution immediately. Ensure your seeders manage duplicate prevention or transactions if needed.