use chrono::Utc;
use sea_orm::{
ColumnTrait, Database, DatabaseConnection, DbErr, EntityTrait, QueryFilter, Select,
entity::prelude::*,
};
use searepo::{DeleteFilter, FindFilter, Pagination, Repository, SearchFilter, SearchResult};
use std::sync::Arc;
use sea_orm::prelude::DateTimeWithTimeZone;
pub mod entities {
pub mod user {
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
#[sea_orm(table_name = "users")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i64,
pub username: String,
pub email: String,
pub active: bool,
pub created_at: DateTimeWithTimeZone,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}
impl ActiveModelBehavior for ActiveModel {}
}
}
#[derive(Debug, Clone)]
pub struct User {
pub id: i64,
pub username: String,
pub email: String,
pub active: bool,
pub created_at: DateTimeWithTimeZone,
}
impl From<entities::user::Model> for User {
fn from(model: entities::user::Model) -> Self {
Self {
id: model.id,
username: model.username,
email: model.email,
active: model.active,
created_at: model.created_at,
}
}
}
impl From<User> for entities::user::ActiveModel {
fn from(user: User) -> Self {
use sea_orm::ActiveValue::*;
Self {
id: Set(user.id),
username: Set(user.username),
email: Set(user.email),
active: Set(user.active),
created_at: Set(user.created_at),
}
}
}
#[derive(Repository)]
#[repository(entity = "entities::user", domain = "User")]
pub struct UserRepository {
db: Arc<DatabaseConnection>,
}
pub mod filter {
use super::*;
use entities::user::{Column, Entity};
pub enum Find {
ById(i64),
ByEmail(String),
ByUsername(String),
}
impl FindFilter<Entity> for Find {
fn to_select(self) -> Select<Entity> {
match self {
Find::ById(id) => Entity::find_by_id(id),
Find::ByEmail(email) => Entity::find().filter(Column::Email.eq(email)),
Find::ByUsername(username) => Entity::find().filter(Column::Username.eq(username)),
}
}
}
#[derive(Default)]
pub struct Search {
pub username: Option<String>,
pub email: Option<String>,
pub active: Option<bool>,
pub pagination: Option<Pagination>,
}
impl SearchFilter<Entity> for Search {
fn to_select(self) -> Select<Entity> {
let mut select = Entity::find();
if let Some(username) = self.username {
select = select.filter(Column::Username.contains(&username));
}
if let Some(email) = self.email {
select = select.filter(Column::Email.contains(&email));
}
if let Some(active) = self.active {
select = select.filter(Column::Active.eq(active));
}
select
}
fn pagination(&self) -> Option<Pagination> {
self.pagination
}
}
pub enum Delete {
ById(i64),
ByEmail(String),
}
impl DeleteFilter<Entity> for Delete {
fn to_select(self) -> Select<Entity> {
match self {
Delete::ById(id) => Entity::find_by_id(id),
Delete::ByEmail(email) => Entity::find().filter(Column::Email.eq(email)),
}
}
}
}
impl UserRepository {
pub fn new(db: Arc<DatabaseConnection>) -> Self {
Self { db }
}
pub async fn find_active_users(&self) -> Result<Vec<User>, DbErr> {
let result = self
.search(filter::Search {
active: Some(true),
..Default::default()
})
.await?;
Ok(result.items)
}
pub async fn find_by_username_pattern(&self, pattern: &str) -> Result<Vec<User>, DbErr> {
let result = self
.search(filter::Search {
username: Some(pattern.to_string()),
..Default::default()
})
.await?;
Ok(result.items)
}
pub async fn find_users_paginated(
&self,
page: u64,
page_size: u64,
) -> Result<SearchResult<User>, DbErr> {
self.search(filter::Search {
pagination: Some(Pagination::PageOffset {
page,
size: page_size,
}),
..Default::default()
})
.await
}
pub async fn total_count(&self) -> Result<u64, DbErr> {
use entities::user::Entity;
Entity::find().count(&*self.db).await
}
pub async fn email_exists(&self, email: &str) -> Result<bool, DbErr> {
Ok(self
.find(filter::Find::ByEmail(email.to_string()))
.await?
.is_some())
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let database_url =
std::env::var("DATABASE_URL").unwrap_or_else(|_| "sqlite::memory:".to_string());
let db = Database::connect(&database_url).await?;
let db = Arc::new(db);
let _repo = UserRepository::new(db.clone());
println!("🚀 Repository Pattern Example\n");
println!("📝 Example 1: Insert a new user");
let _new_user = User {
id: 0, username: "alice".to_string(),
email: "alice@example.com".to_string(),
active: true,
created_at: Utc::now().fixed_offset(),
};
println!("🔍 Example 2: Find a user by ID");
println!("🔍 Example 3: Find a user by email (must exist)");
println!("🔎 Example 4: Search users with filters");
println!("👥 Example 5: Find all active users");
println!("✏️ Example 6: Update a user");
println!("📦 Example 7: Batch insert");
println!("🔍 Example 8: Check if email exists");
println!("🔢 Example 9: Count users");
println!("🗑️ Example 10: Delete a user");
println!("✨ All examples completed!");
println!("\n💡 Note: Uncomment the actual database operations to run them.");
Ok(())
}