use async_trait::async_trait; use libertas_core::{ error::{CoreError, CoreResult}, models::FaceEmbedding, repositories::FaceEmbeddingRepository, }; use sqlx::PgPool; use uuid::Uuid; use crate::db_models::PostgresFaceEmbedding; #[derive(Clone)] pub struct PostgresFaceEmbeddingRepository { pool: PgPool, } impl PostgresFaceEmbeddingRepository { pub fn new(pool: PgPool) -> Self { Self { pool } } } #[async_trait] impl FaceEmbeddingRepository for PostgresFaceEmbeddingRepository { async fn create(&self, embedding: &FaceEmbedding) -> CoreResult<()> { sqlx::query!( r#" INSERT INTO face_embeddings (id, face_region_id, model_id, embedding) VALUES ($1, $2, $3, $4) "#, embedding.id, embedding.face_region_id, embedding.model_id, embedding.embedding ) .execute(&self.pool) .await .map_err(|e| CoreError::Database(e.to_string()))?; Ok(()) } async fn find_by_face_region_id( &self, face_region_id: Uuid, ) -> CoreResult> { let pg_embedding = sqlx::query_as!( PostgresFaceEmbedding, r#" SELECT id, face_region_id, model_id, embedding FROM face_embeddings WHERE face_region_id = $1 "#, face_region_id ) .fetch_optional(&self.pool) .await .map_err(|e| CoreError::Database(e.to_string()))?; Ok(pg_embedding.map(FaceEmbedding::from)) } async fn list_unassigned_by_user(&self, user_id: Uuid) -> CoreResult> { let pg_embeddings = sqlx::query_as!( PostgresFaceEmbedding, r#" SELECT fe.id, fe.face_region_id, fe.model_id, fe.embedding FROM face_embeddings fe JOIN face_regions fr ON fe.face_region_id = fr.id JOIN media m ON fr.media_id = m.id WHERE fr.person_id IS NULL AND m.owner_id = $1 "#, user_id ) .fetch_all(&self.pool) .await .map_err(|e| CoreError::Database(e.to_string()))?; Ok(pg_embeddings.into_iter().map(FaceEmbedding::from).collect()) } }