use crate::adapters::entities::{prelude::Users, users};
use crate::error::{AppError, Result};
use crate::features::examples::models::{CreateUserRequest, UpdateUserRequest, User};
use chrono::Utc;
use sea_orm::{
ActiveModelTrait, ColumnTrait, DatabaseConnection, EntityTrait, PaginatorTrait, QueryFilter,
QueryOrder, Set,
};
use uuid::Uuid;
#[derive(Clone)]
pub struct UserRepository {
db: DatabaseConnection,
}
impl UserRepository {
pub fn new(db: DatabaseConnection) -> Self {
Self { db }
}
pub async fn find_by_id(&self, id: Uuid) -> Result<Option<User>> {
let user = Users::find_by_id(id).one(&self.db).await?;
Ok(user.map(|u| User {
id: u.id,
email: u.email,
name: u.name,
created_at: u.created_at,
updated_at: u.updated_at,
}))
}
pub async fn find_by_email(&self, email: &str) -> Result<Option<User>> {
let user = Users::find()
.filter(users::Column::Email.eq(email))
.one(&self.db)
.await?;
Ok(user.map(|u| User {
id: u.id,
email: u.email,
name: u.name,
created_at: u.created_at,
updated_at: u.updated_at,
}))
}
pub async fn list(&self, page: u64, per_page: u64) -> Result<(Vec<User>, u64)> {
let paginator = Users::find()
.order_by_desc(users::Column::CreatedAt)
.paginate(&self.db, per_page);
let total = paginator.num_items().await?;
let users = paginator.fetch_page(page.saturating_sub(1)).await?;
let users = users
.into_iter()
.map(|u| User {
id: u.id,
email: u.email,
name: u.name,
created_at: u.created_at,
updated_at: u.updated_at,
})
.collect();
Ok((users, total))
}
pub async fn create(&self, request: &CreateUserRequest) -> Result<User> {
let now = Utc::now();
let id = Uuid::new_v4();
let user = users::ActiveModel {
id: Set(id),
email: Set(request.email.clone()),
name: Set(request.name.clone()),
created_at: Set(now),
updated_at: Set(now),
};
let user = user.insert(&self.db).await?;
Ok(User {
id: user.id,
email: user.email,
name: user.name,
created_at: user.created_at,
updated_at: user.updated_at,
})
}
pub async fn update(&self, id: Uuid, request: &UpdateUserRequest) -> Result<User> {
let user = Users::find_by_id(id)
.one(&self.db)
.await?
.ok_or_else(|| AppError::NotFound(format!("User with id {} not found", id)))?;
let mut user: users::ActiveModel = user.into();
if let Some(email) = &request.email {
user.email = Set(email.clone());
}
if let Some(name) = &request.name {
user.name = Set(name.clone());
}
user.updated_at = Set(Utc::now());
let user = user.update(&self.db).await?;
Ok(User {
id: user.id,
email: user.email,
name: user.name,
created_at: user.created_at,
updated_at: user.updated_at,
})
}
pub async fn delete(&self, id: Uuid) -> Result<()> {
let result = Users::delete_by_id(id).exec(&self.db).await?;
if result.rows_affected == 0 {
return Err(AppError::NotFound(format!("User with id {} not found", id)));
}
Ok(())
}
pub async fn email_exists(&self, email: &str) -> Result<bool> {
let count = Users::find()
.filter(users::Column::Email.eq(email))
.count(&self.db)
.await?;
Ok(count > 0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_repository_compiles() {
}
}