Skip to content

physgun-com/Ferroquent

Repository files navigation

Ferroquent

A faithful port of Laravel's Eloquent ORM to Rust.

Rust has excellent query builders and entity-first ORMs, but nothing with Eloquent's ActiveRecord ergonomics. Ferroquent brings that feel - User::query().where_("votes", ">", 100).get(db).await - with models, relations, eager loading, existence queries, scopes, soft deletes, casts, observers, factories, a schema builder, and migrations. It runs on MySQL, MariaDB, and PostgreSQL through sqlx, behind a driver seam (copied from Laravel) so other backends can be added without touching the core.

use ferroquent::prelude::*;

#[derive(Model, Clone, Debug, Default)]
#[ferroquent(soft_deletes)]
struct User {
    id: u64,
    #[ferroquent(fillable)] name: String,
    #[ferroquent(fillable)] email: String,
    #[ferroquent(fillable)] votes: i32,
    created_at: Option<chrono::NaiveDateTime>,
    updated_at: Option<chrono::NaiveDateTime>,
    deleted_at: Option<chrono::NaiveDateTime>,
    posts: HasMany<Post>,
    state: ModelState<User>,
}

# async fn demo() -> ferroquent::core::error::Result<()> {
Ferroquent::boot(ConnectionConfig::from_url("mysql://root:secret@127.0.0.1/app")?)?;
let conn = Ferroquent::connection(None).await?;
let db = conn.as_ref();

// Create (mass-assigned), then a dirty-only UPDATE.
let mut user = User::create(db, record([
    ("name", Value::Str("Taylor".into())),
    ("email", Value::Str("taylor@example.com".into())),
    ("votes", Value::Int(10)),
])).await?;
user.votes = 11;
user.save(db).await?;

// Eloquent-style querying with eager loading (no N+1).
let mut q = User::query();
q.where_("votes", ">", 8).with(["posts"]).order_by_desc("votes");
let active = q.get(db).await?;
# Ok(()) }

Highlights

  • Models - #[derive(Model)] with casts, dirty tracking, the full save/create/update/ delete lifecycle, timestamps, and mass assignment (fillable/guarded).
  • Every relation type - HasOne, HasMany, BelongsTo, BelongsToMany (with attach/detach/sync), HasManyThrough, and polymorphic MorphOne/MorphMany/MorphTo. Lazy accessors, eager loading, and dot-nested eager loading (with("posts.comments")).
  • Existence & aggregates - has, doesnt_have, where_has, with_count.
  • Soft deletes - the full lifecycle: scoped queries, with_trashed/only_trashed, restore, force_delete.
  • Scopes & events - local scopes (extension traits + .scoped()), global scopes, and typed observers with halting before-hooks.
  • Query builder - the where family, joins, group/having, unions, aggregates, upsert, JSON path selectors, and full-text search, compiled by per-dialect grammars.
  • Schema & migrations - a fluent Blueprint, a Migrator, and an embedded CLI (migrate, migrate:rollback, migrate:status, make:model, make:migration).
  • Factories & seeders, plus a synchronous [blocking] facade for scripts.

Installation

[dependencies]
ferroquent = "0.0.1"
tokio = { version = "1", features = ["full"] }

Default features include the mysql driver (which also serves MariaDB), chrono, schema, migrations, and cli. PostgreSQL is provided by ferroquent-postgres with its driver feature.

Workspace

Crate Role
ferroquent Facade: prelude, re-exports, Ferroquent::boot, derive macros, blocking facade
ferroquent-core Value, bindings, query AST, Grammar/Connection traits, driver registry
ferroquent-model Model layer: Model, Builder<M>, relations, casts, scopes, observers
ferroquent-macros #[derive(Model)] and #[derive(MorphTarget)]
ferroquent-inflect English inflection, used at macro-expansion time
ferroquent-mysql The sqlx-backed MySQL/MariaDB driver (grammar + connection)
ferroquent-postgres PostgreSQL: a core-only grammar, plus a live driver behind --features driver
ferroquent-schema Fluent schema builder and DDL grammar
ferroquent-migrations Migration trait, Migrator, the migrations table
ferroquent-cli Embedded CLI runtime (migrate + scaffolding)

The driver seam is real: ferroquent-postgres depends on ferroquent-core alone by default - a new backend is a self-contained crate, exactly like Laravel's driver packages.

Testing

Unit and grammar golden tests need no database:

cargo test --workspace

Integration tests run against live servers (see docker-compose.yml):

docker compose up -d
export FERROQUENT_TEST_MYSQL_DSN=mysql://root:secret@127.0.0.1:33061/ferroquent_test
export FERROQUENT_TEST_MARIADB_DSN=mysql://root:secret@127.0.0.1:33062/ferroquent_test
export FERROQUENT_TEST_PG_DSN=postgres://postgres:secret@127.0.0.1:33063/ferroquent_test
cargo test --workspace --all-features
cargo test -p ferroquent-postgres --features driver

Fidelity

Ferroquent mirrors Eloquent's behavior closely; where Rust's type system forces a different shape (no property interception, no runtime reflection), the divergence is intentional and documented in docs/DEVIATIONS.md.

License

MIT - see LICENSE.

About

Eloquent ORM, but for Rust

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages