Skip to main content

koprogo_api/infrastructure/database/repositories/
lien_notaire_repository_impl.rs

1//! PostgreSQL implementation of [`LienNotaireRepository`] (#845 — ADR 0051).
2//!
3//! All `sqlx::Error` paths are wrapped in `AppError::Database(_)` — no
4//! `Result<_, String>` debt (CRITICAL.md #4).
5
6use crate::application::error::AppError;
7use crate::application::ports::LienNotaireRepository;
8use crate::domain::entities::LienNotaire;
9use crate::infrastructure::database::pool::DbPool;
10use async_trait::async_trait;
11use sqlx::Row;
12use uuid::Uuid;
13
14pub struct PostgresLienNotaireRepository {
15    pool: DbPool,
16}
17
18impl PostgresLienNotaireRepository {
19    pub fn new(pool: DbPool) -> Self {
20        Self { pool }
21    }
22
23    fn row_to_lien(row: &sqlx::postgres::PgRow) -> LienNotaire {
24        LienNotaire {
25            id: row.get("id"),
26            etat_date_id: row.get("etat_date_id"),
27            token_hash: row.get("token_hash"),
28            emis_par: row.get("emis_par"),
29            cree_le: row.get("cree_le"),
30            expire_le: row.get("expire_le"),
31            revoque_le: row.get("revoque_le"),
32            revoque_par: row.get("revoque_par"),
33            renouvele_le: row.get("renouvele_le"),
34            mis_a_jour_le: row.get("mis_a_jour_le"),
35        }
36    }
37}
38
39#[async_trait]
40impl LienNotaireRepository for PostgresLienNotaireRepository {
41    async fn save(&self, lien: &LienNotaire) -> Result<(), AppError> {
42        sqlx::query(
43            r#"
44            INSERT INTO liens_notaire (
45                id, token_hash, etat_date_id, emis_par,
46                cree_le, expire_le, revoque_le, revoque_par,
47                renouvele_le, mis_a_jour_le
48            )
49            VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
50            "#,
51        )
52        .bind(lien.id)
53        .bind(&lien.token_hash)
54        .bind(lien.etat_date_id)
55        .bind(lien.emis_par)
56        .bind(lien.cree_le)
57        .bind(lien.expire_le)
58        .bind(lien.revoque_le)
59        .bind(lien.revoque_par)
60        .bind(lien.renouvele_le)
61        .bind(lien.mis_a_jour_le)
62        .execute(&self.pool)
63        .await
64        .map_err(|e| AppError::Database(e.to_string()))?;
65
66        Ok(())
67    }
68
69    async fn find_by_token_hash(&self, token_hash: &str) -> Result<Option<LienNotaire>, AppError> {
70        let row = sqlx::query(
71            r#"
72            SELECT id, token_hash, etat_date_id, emis_par,
73                   cree_le, expire_le, revoque_le, revoque_par,
74                   renouvele_le, mis_a_jour_le
75            FROM liens_notaire
76            WHERE token_hash = $1
77            "#,
78        )
79        .bind(token_hash)
80        .fetch_optional(&self.pool)
81        .await
82        .map_err(|e| AppError::Database(e.to_string()))?;
83
84        Ok(row.map(|r| Self::row_to_lien(&r)))
85    }
86
87    async fn find_active_by_etat_date_id(
88        &self,
89        etat_date_id: Uuid,
90    ) -> Result<Option<LienNotaire>, AppError> {
91        let row = sqlx::query(
92            r#"
93            SELECT id, token_hash, etat_date_id, emis_par,
94                   cree_le, expire_le, revoque_le, revoque_par,
95                   renouvele_le, mis_a_jour_le
96            FROM liens_notaire
97            WHERE etat_date_id = $1 AND revoque_le IS NULL
98            ORDER BY cree_le DESC
99            LIMIT 1
100            "#,
101        )
102        .bind(etat_date_id)
103        .fetch_optional(&self.pool)
104        .await
105        .map_err(|e| AppError::Database(e.to_string()))?;
106
107        Ok(row.map(|r| Self::row_to_lien(&r)))
108    }
109
110    async fn update(&self, lien: &LienNotaire) -> Result<(), AppError> {
111        sqlx::query(
112            r#"
113            UPDATE liens_notaire
114            SET expire_le = $2,
115                revoque_le = $3,
116                revoque_par = $4,
117                renouvele_le = $5,
118                mis_a_jour_le = $6
119            WHERE id = $1
120            "#,
121        )
122        .bind(lien.id)
123        .bind(lien.expire_le)
124        .bind(lien.revoque_le)
125        .bind(lien.revoque_par)
126        .bind(lien.renouvele_le)
127        .bind(lien.mis_a_jour_le)
128        .execute(&self.pool)
129        .await
130        .map_err(|e| AppError::Database(e.to_string()))?;
131
132        Ok(())
133    }
134}