feat: expand workspace to include libertas_infra and libertas_worker

feat(libertas_api): add dependency on libertas_infra and async-nats

refactor(libertas_api): consolidate config loading and add broker_url

refactor(libertas_api): integrate NATS client into app state and services

feat(libertas_core): introduce config module for database and server settings

fix(libertas_core): enhance error handling with detailed messages

feat(libertas_infra): create infrastructure layer with database repositories

feat(libertas_infra): implement Postgres repositories for media and albums

feat(libertas_worker): add worker service to process media jobs via NATS
This commit is contained in:
2025-11-02 10:22:38 +01:00
parent 7ea91da20a
commit a5a88c7f33
23 changed files with 1122 additions and 107 deletions

View File

@@ -0,0 +1,91 @@
use async_trait::async_trait;
use libertas_core::{
error::{CoreError, CoreResult},
models::Album,
repositories::AlbumRepository,
};
use sqlx::PgPool;
use uuid::Uuid;
#[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<Option<Album>> {
sqlx::query_as!(
Album,
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()))
}
async fn list_by_user(&self, user_id: Uuid) -> CoreResult<Vec<Album>> {
sqlx::query_as!(
Album,
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()))
}
async fn add_media_to_album(&self, album_id: Uuid, media_ids: &[Uuid]) -> CoreResult<()> {
// Use sqlx's `unnest` feature to pass the Vec<Uuid> 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(())
}
}