| Crates.io | tideorm |
| lib.rs | tideorm |
| version | 0.4.5 |
| created_at | 2026-01-08 14:33:08.089867+00 |
| updated_at | 2026-01-17 22:44:43.698799+00 |
| description | A developer-friendly ORM for Rust with clean, expressive syntax |
| homepage | https://tideorm.com |
| repository | https://github.com/mohamadzoh/tideorm |
| max_upload_size | |
| id | 2030318 |
| size | 1,813,081 |
A developer-friendly ORM for Rust with clean, expressive syntax.
#[tideorm::model] attribute macrouse tideorm::prelude::*;
#[tideorm::model]
#[tide(table = "users")]
pub struct User {
#[tide(primary_key, auto_increment)]
pub id: i64,
pub email: String,
pub name: String,
pub active: bool,
// Relations defined as struct fields
#[tide(has_one = "Profile", foreign_key = "user_id")]
pub profile: HasOne<Profile>,
#[tide(has_many = "Post", foreign_key = "user_id")]
pub posts: HasMany<Post>,
}
#[tideorm::model]
#[tide(table = "posts")]
pub struct Post {
#[tide(primary_key, auto_increment)]
pub id: i64,
pub user_id: i64,
pub title: String,
#[tide(belongs_to = "User", foreign_key = "user_id")]
pub author: BelongsTo<User>,
}
#[tokio::main]
async fn main() -> tideorm::Result<()> {
// Connect with auto schema sync (development only!)
TideConfig::init()
.database("postgres://localhost/mydb")
.sync(true)
.connect()
.await?;
// Create
let user = User {
id: 0,
email: "john@example.com".into(),
name: "John Doe".into(),
active: true,
..Default::default()
};
let user = user.save().await?;
// Query
let users = User::query()
.where_eq("active", true)
.order_desc("created_at")
.limit(10)
.get()
.await?;
// Complex queries with OR conditions
let premium_or_featured = Product::query()
.where_eq("active", true)
.begin_or()
.or_where_gt("price", 500.0).and_where_gte("rating", 4.5)
.or_where_eq("featured", true)
.end_or()
.get()
.await?;
// Load relations
let posts = user.posts.load().await?;
let profile = user.profile.load().await?;
// Update
let mut user = User::find(1).await?.unwrap();
user.name = "Jane Doe".into();
user.update().await?;
// Delete
User::destroy(1).await?;
Ok(())
}
TideORM supports SeaORM-style relations defined as struct fields:
#[tideorm::model]
#[tide(table = "users")]
pub struct User {
#[tide(primary_key, auto_increment)]
pub id: i64,
pub name: String,
// One-to-one: User has one Profile
#[tide(has_one = "Profile", foreign_key = "user_id")]
pub profile: HasOne<Profile>,
// One-to-many: User has many Posts
#[tide(has_many = "Post", foreign_key = "user_id")]
pub posts: HasMany<Post>,
// Many-to-many through pivot table
#[tide(has_many_through = "Role", pivot = "user_roles", foreign_key = "user_id", related_key = "role_id")]
pub roles: HasManyThrough<Role, UserRole>,
}
#[tideorm::model]
#[tide(table = "posts")]
pub struct Post {
#[tide(primary_key, auto_increment)]
pub id: i64,
pub user_id: i64,
pub title: String,
// Inverse relation: Post belongs to User
#[tide(belongs_to = "User", foreign_key = "user_id")]
pub author: BelongsTo<User>,
}
// Loading relations
let user = User::find(1).await?.unwrap();
let posts = user.posts.load().await?; // Vec<Post>
let profile = user.profile.load().await?; // Option<Profile>
let post = Post::find(1).await?.unwrap();
let author = post.author.load().await?; // Option<User>
// Check if relation exists
let has_posts = user.posts.exists().await?; // bool
let post_count = user.posts.count().await?; // u64
// Load with constraints
let recent_posts = user.posts.load_with(|q| {
q.where_eq("published", true)
.order_desc("created_at")
.limit(5)
}).await?;
[dependencies]
# PostgreSQL (default)
tideorm = { version = "*", features = ["postgres"] }
# MySQL
tideorm = { version = "*", features = ["mysql"] }
# SQLite
tideorm = { version = "*", features = ["sqlite"] }
| Feature | Description |
|---|---|
postgres |
PostgreSQL support (default) |
mysql |
MySQL/MariaDB support |
sqlite |
SQLite support |
runtime-tokio |
Tokio runtime (default) |
runtime-async-std |
async-std runtime |
| Type | Description | Example |
|---|---|---|
HasOne<T> |
One-to-one relationship | User has one Profile |
HasMany<T> |
One-to-many relationship | User has many Posts |
BelongsTo<T> |
Inverse of HasOne/HasMany | Post belongs to User |
HasManyThrough<T, P> |
Many-to-many via pivot | User has many Roles through UserRoles |
MorphOne<T> |
Polymorphic one-to-one | Post/Video has one Image |
MorphMany<T> |
Polymorphic one-to-many | Post/Video has many Comments |
For detailed documentation on all features, see DOCUMENTATION.md.
Key sections:
For comprehensive examples demonstrating TideORM features, see the tideorm-examples repository.
# Clone the examples repository
git clone https://github.com/mohamadzoh/tideorm-examples.git
cd tideorm-examples
# Run a basic example
cargo run --bin basic
# Run with different databases
cargo run --bin postgres_demo
cargo run --bin mysql_demo --features "mysql runtime-tokio" --no-default-features
cargo run --bin sqlite_demo --features "sqlite runtime-tokio" --no-default-features
| Example | Description |
|---|---|
basic |
Core CRUD operations |
query_builder |
Advanced querying (WHERE, ORDER BY, LIMIT) |
where_and_or_demo |
Comprehensive WHERE & OR conditions |
upsert_demo |
Insert-or-update with conflict handling |
postgres_complete |
Complete PostgreSQL feature showcase |
migrations |
Database schema migrations |
validation_demo |
Model validation system |
fulltext_demo |
Full-text search with highlighting |
tokenization_demo |
Secure record ID tokenization |
See the tideorm-examples README for the complete list.
Run tests:
cargo test --features postgres
See DOCUMENTATION.md for more.
TideORM is part of the larger Rusty Rails project, which aims to bridge the gap between Rust and Ruby/Ruby on Rails ecosystems. We're actively working on recreating Ruby libraries in Rust to make working with Rust more easy and fun for new developers.
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.
Made with love by the Rusty Rails team