bavard 0.0.26
bavard: ^0.0.26 copied to clipboard
An Eloquent-inspired ORM for Flutter. Supports SQLite, PostgreSQL and PowerSync with fluent queries, relationships, soft deletes, timestamps, casts and more.
Bavard ORM π£οΈ #
The Eloquent-style ORM for Dart.
Work in Progress: This project is currently under active development. APIs may change.
Bavard brings the elegance and simplicity of Eloquent to the Dart ecosystem. It is designed to provide a fluent, expressive interface for database interactions, prioritizing developer experience, runtime flexibility, and readability.
π Key Features #
- π Flutter ready: Seamlessly integrated with Flutter for mobile, desktop, and web applications.
- β‘οΈ Runtime-first architecture: Code generation is 100% optional. Bavard leverages Dart's runtime capabilities and mixins to work entirely without build processes.
- ποΈ Fluent Query Builder: Construct complex SQL queries using an expressive and type-safe interface.
- π Rich Relationship Mapping: Full support for One-to-One, One-to-Many, Many-to-Many, Polymorphic, and HasManyThrough relations.
- π§© Smart Data Casting: Automatic hydration and dehydration of complex types like JSON, DateTime, and Booleans between Dart and your database.
- π Production-ready features: Built-in support for Soft Deletes, Automatic Timestamps, and Global Scopes out of the box.
- π± Offline-first ready: Native support for client-side UUIDs and a driver-agnostic architecture, ideal for local-first applications.
- π΅οΈ Dirty Checking: Optimized database updates by tracking only the attributes that have actually changed.
- π Eager Loading: Powerful eager loading system to eliminate N+1 query problems.
- π Database Agnostic: Flexible adapter system with native support for SQLite and PostgreSQL.
π Documentation #
For detailed guides, API references, and usage examples, please visit our documentation:
π Quick Start #
0. Initialize Database #
Bavard is driver-agnostic. You just need to provide an implementation of DatabaseAdapter (see Adapters documentation for reference implementations).
import 'package:bavard/bavard.dart';
import 'your_project/my_database_adapter.dart'; // Your custom implementation
void main() async {
// Initialize your custom adapter (SQLite, Postgres, PowerSync, etc.)
final adapter = MyDatabaseAdapter();
await adapter.connect();
// Register it as the default connection
DatabaseManager().setDatabase(adapter);
}
1. Define a Model #
Bavard models use a schema-first approach. For the best experience, use code generation to get full type safety.
import 'package:bavard/bavard.dart';
part 'user.fillable.g.dart';
@fillable
class User extends Model with $UserFillable {
@override
String get table => 'users';
// Define schema for query safety and automatic casting
static const schema = (
id: IdColumn(),
name: TextColumn('name'),
email: TextColumn('email'),
isActive: BoolColumn('is_active'),
);
User([super.attributes]);
@override
User fromMap(Map<String, dynamic> map) => User(map);
}
2. Use it! #
Enjoy a fluent, expressive, and type-safe API.
// Create
final user = User();
user.name = 'Mario'; // Typed setter
user.isActive = true;
await user.save();
// Read (Type-Safe)
final users = await User().query()
.where(User.schema.isActive, true) // Uses generated schema
.orderBy(User.schema.name)
.get();
// Update (with Dirty Checking)
final mario = await User().query().find(1);
mario.name = 'Super Mario';
await mario.save(); // Only updates the 'name' column
// Reactive Streams (Flutter friendly)
StreamBuilder<List<User>>(
stream: User().query().watch(), // Auto-updates on DB changes
builder: (context, snapshot) {
// ...
},
);
π Relationships #
Defining relationships is easy, but requires overriding getRelation for proper dispatching.
class User extends Model {
// ... (table, columns, etc.)
// Define the relationship
HasMany<Post> posts() => hasMany(Post.new);
// REGISTER the relationship (Mandatory!)
@override
Relation? getRelation(String name) {
if (name == 'posts') return posts();
return super.getRelation(name);
}
}
// Usage
final user = await User().query().find(1);
// Lazy Load
final posts = await user.posts().get();
// Eager Load (Avoid N+1)
final usersWithPosts = await User().query().withRelations(['posts']).get();
π§ͺ Examples & Integration #
To see Bavard in action with a real database environment, check the integration suite:
π€ Contributing #
Bavard is open-source. Feel free to explore the code, report issues, or submit pull requests.