use async_trait::async_trait; use libertas_core::{ error::{CoreError, CoreResult}, models::Album, repositories::AlbumRepository, }; use sqlx::PgPool; use uuid::Uuid; use crate::db_models::PostgresAlbum; #[derive(Clone)] pub struct PostgresAlbumRepository { pool: PgPool, } impl PostgresAlbumRepository { pub fn new(pool: PgPool) -> Self { Self { pool } } } #[async_trait] impl AlbumRepository for PostgresAlbumRepository { async fn create(&self, album: Album) -> CoreResult<()> { sqlx::query!( r#" INSERT INTO albums (id, owner_id, name, description, is_public, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7) "#, album.id, album.owner_id, album.name, album.description, album.is_public, album.created_at, album.updated_at ) .execute(&self.pool) .await .map_err(|e| CoreError::Database(e.to_string()))?; Ok(()) } async fn find_by_id(&self, id: Uuid) -> CoreResult> { let pg_album = sqlx::query_as!( PostgresAlbum, r#" SELECT id, owner_id, name, description, is_public, created_at, updated_at FROM albums WHERE id = $1 "#, id ) .fetch_optional(&self.pool) .await .map_err(|e| CoreError::Database(e.to_string()))?; Ok(pg_album.map(|a| a.into())) } async fn list_by_user(&self, user_id: Uuid) -> CoreResult> { let pg_albums = sqlx::query_as!( PostgresAlbum, r#" SELECT id, owner_id, name, description, is_public, created_at, updated_at FROM albums WHERE owner_id = $1 "#, user_id ) .fetch_all(&self.pool) .await .map_err(|e| CoreError::Database(e.to_string()))?; Ok(pg_albums.into_iter().map(|a| a.into()).collect()) } async fn add_media_to_album(&self, album_id: Uuid, media_ids: &[Uuid]) -> CoreResult<()> { // Use sqlx's `unnest` feature to pass the Vec efficiently sqlx::query!( r#" INSERT INTO album_media (album_id, media_id) SELECT $1, media_id FROM unnest($2::uuid[]) as media_id ON CONFLICT (album_id, media_id) DO NOTHING "#, album_id, media_ids ) .execute(&self.pool) .await .map_err(|e| CoreError::Database(e.to_string()))?; Ok(()) } async fn update(&self, album: Album) -> CoreResult<()> { sqlx::query!( r#" UPDATE albums SET name = $1, description = $2, is_public = $3, updated_at = NOW() WHERE id = $4 "#, album.name, album.description, album.is_public, album.id ) .execute(&self.pool) .await .map_err(|e| CoreError::Database(e.to_string()))?; Ok(()) } async fn delete(&self, id: Uuid) -> CoreResult<()> { sqlx::query!( r#" DELETE FROM albums WHERE id = $1 "#, id ) .execute(&self.pool) .await .map_err(|e| CoreError::Database(e.to_string()))?; Ok(()) } }