🐘 Relational Databases (SeaORM)
For relational databases (PostgreSQL, MySQL, SQLite), Ferrox integrates with SeaORM via ferrox-database-seaorm.
SeaORM provides an async ORM built on top of sqlx, offering compile-time safety, dynamic query building, and seamless integration with Tokio.
1. Connecting to PostgreSQL / MySQL
Initialize the SeaORM database connection pool during application bootstrap:
use sea_orm::{Database, DatabaseConnection};
use ferrox_errors::AppError;
pub async fn init_db(database_url: &str) -> Result<DatabaseConnection, AppError> {
let db = Database::connect(database_url)
.await
.map_err(|e| AppError::DatabaseError(e.to_string()))?;
println!("✅ Connected to Relational Database via SeaORM");
Ok(db)
}
2. Implementing a SeaORM Repository
Implement the Repository trait for your entity:
use async_trait::async_trait;
use sea_orm::{DatabaseConnection, EntityTrait, Set, ActiveModelTrait};
use ferrox_database_core::Repository;
use ferrox_errors::AppError;
use crate::entities::user::{Entity as UserEntity, ActiveModel as UserActiveModel, Model as UserModel};
pub struct SeaOrmUserRepository {
db: DatabaseConnection,
}
impl SeaOrmUserRepository {
pub fn new(db: DatabaseConnection) -> Self {
Self { db }
}
}
#[async_trait]
impl Repository<UserModel, i32> for SeaOrmUserRepository {
async fn find_by_id(&self, id: i32) -> Result<Option<UserModel>, AppError> {
UserEntity::find_by_id(id)
.one(&self.db)
.await
.map_err(|e| AppError::DatabaseError(e.to_string()))
}
async fn find_all(&self) -> Result<Vec<UserModel>, AppError> {
UserEntity::find()
.all(&self.db)
.await
.map_err(|e| AppError::DatabaseError(e.to_string()))
}
async fn insert(&self, user: UserModel) -> Result<UserModel, AppError> {
let active_model = UserActiveModel {
name: Set(user.name),
email: Set(user.email),
..Default::default()
};
active_model
.insert(&self.db)
.await
.map_err(|e| AppError::DatabaseError(e.to_string()))
}
async fn update(&self, _id: i32, _user: UserModel) -> Result<UserModel, AppError> {
// Implement update logic
todo!()
}
async fn delete(&self, id: i32) -> Result<(), AppError> {
UserEntity::delete_by_id(id)
.exec(&self.db)
.await
.map_err(|e| AppError::DatabaseError(e.to_string()))?;
Ok(())
}
}
3. Database Transactions
SeaORM supports async transactions for multi-step atomic operations:
use sea_orm::TransactionTrait;
let txn = db.begin().await?;
// Perform multiple queries inside txn...
txn.commit().await?;
4. ✅ Best Practices
- Configure connection pool bounds: Always set max pool size (
max_connections) based on database CPU core count to avoid exhaustion under high concurrency.