use async_trait::async_trait; use libertas_core::{ error::{CoreError, CoreResult}, models::User, repositories::UserRepository, }; use sqlx::{Executor, PgPool, Postgres, SqlitePool, types::Uuid}; use crate::db_models::PostgresUser; #[derive(Clone)] pub struct PostgresUserRepository { pool: PgPool, } impl PostgresUserRepository { pub fn new(pool: PgPool) -> Self { Self { pool } } pub(crate) async fn update_storage_used_internal<'a>( exec: impl Executor<'a, Database = Postgres>, user_id: Uuid, bytes: i64, ) -> CoreResult<()> { sqlx::query!( r#" UPDATE users SET storage_used = storage_used + $1, updated_at = NOW() WHERE id = $2 "#, bytes, user_id ) .execute(exec) .await .map_err(|e| CoreError::Database(e.to_string()))?; Ok(()) } } #[derive(Clone)] pub struct SqliteUserRepository { _pool: SqlitePool, } impl SqliteUserRepository { pub fn new(pool: SqlitePool) -> Self { Self { _pool: pool } } } #[async_trait] impl UserRepository for PostgresUserRepository { async fn create(&self, user: User) -> CoreResult<()> { sqlx::query!( r#" INSERT INTO users (id, username, email, hashed_password, created_at, updated_at, role, storage_quota, storage_used) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) "#, user.id, user.username, user.email, user.hashed_password, user.created_at, user.updated_at, user.role.as_str(), user.storage_quota, user.storage_used ) .execute(&self.pool) .await .map_err(|e| CoreError::Database(e.to_string()))?; Ok(()) } async fn find_by_email(&self, email: &str) -> CoreResult> { let pg_user = sqlx::query_as!( PostgresUser, r#" SELECT id, username, email, hashed_password, created_at, updated_at, role, storage_quota, storage_used FROM users WHERE email = $1 "#, email ) .fetch_optional(&self.pool) .await .map_err(|e| CoreError::Database(e.to_string()))?; Ok(pg_user.map(|u| u.into())) } async fn find_by_username(&self, username: &str) -> CoreResult> { let pg_user = sqlx::query_as!( PostgresUser, r#" SELECT id, username, email, hashed_password, created_at, updated_at, role, storage_quota, storage_used FROM users WHERE username = $1 "#, username ) .fetch_optional(&self.pool) .await .map_err(|e| CoreError::Database(e.to_string()))?; Ok(pg_user.map(|u| u.into())) } async fn find_by_id(&self, id: Uuid) -> CoreResult> { let pg_user = sqlx::query_as!( PostgresUser, r#" SELECT id, username, email, hashed_password, created_at, updated_at, role, storage_quota, storage_used FROM users WHERE id = $1 "#, id ) .fetch_optional(&self.pool) .await .map_err(|e| CoreError::Database(e.to_string()))?; Ok(pg_user.map(|u| u.into())) } async fn update_storage_used(&self, user_id: Uuid, bytes: i64) -> CoreResult<()> { Self::update_storage_used_internal(&self.pool, user_id, bytes).await } } #[async_trait] impl UserRepository for SqliteUserRepository { async fn create(&self, _user: User) -> CoreResult<()> { println!("SQLITE REPO: Creating user"); Ok(()) } async fn find_by_email(&self, _email: &str) -> CoreResult> { println!("SQLITE REPO: Finding user by email"); Ok(None) } async fn find_by_username(&self, _username: &str) -> CoreResult> { println!("SQLITE REPO: Finding user by username"); Ok(None) } async fn find_by_id(&self, _id: Uuid) -> CoreResult> { println!("SQLITE REPO: Finding user by id"); Ok(None) } async fn update_storage_used(&self, _user_id: Uuid, _bytes: i64) -> CoreResult<()> { println!("SQLITE REPO: Updating user storage used"); Ok(()) } }