sqlx_ledger/account/
repo.rs

1use serde::Serialize;
2use sqlx::{Pool, Postgres, Transaction};
3use tracing::instrument;
4
5use super::entity::*;
6use crate::{error::*, primitives::*};
7
8/// Repository for working with `Account` entities.
9#[derive(Debug, Clone)]
10pub struct Accounts {
11    pool: Pool<Postgres>,
12}
13
14impl Accounts {
15    pub fn new(pool: &Pool<Postgres>) -> Self {
16        Self { pool: pool.clone() }
17    }
18
19    pub async fn create(&self, new_account: NewAccount) -> Result<AccountId, SqlxLedgerError> {
20        let mut tx = self.pool.begin().await?;
21        let res = self.create_in_tx(&mut tx, new_account).await?;
22        tx.commit().await?;
23        Ok(res)
24    }
25
26    #[instrument(name = "sqlx_ledger.accounts.create", skip(self, tx))]
27    pub async fn create_in_tx<'a>(
28        &self,
29        tx: &mut Transaction<'a, Postgres>,
30        new_account: NewAccount,
31    ) -> Result<AccountId, SqlxLedgerError> {
32        let NewAccount {
33            id,
34            code,
35            name,
36            normal_balance_type,
37            description,
38            status,
39            metadata,
40        } = new_account;
41        let record = sqlx::query!(
42            r#"INSERT INTO sqlx_ledger_accounts (id, code, name, normal_balance_type, description, status, metadata)
43            VALUES ($1, $2, $3, $4, $5, $6, $7)
44            RETURNING id, version, created_at"#,
45            id as AccountId,
46            code,
47            name,
48            normal_balance_type as DebitOrCredit,
49            description,
50            status as Status,
51            metadata
52        )
53        .fetch_one(&mut **tx)
54        .await?;
55        Ok(AccountId::from(record.id))
56    }
57
58    #[instrument(name = "sqlx_ledger.accounts.update", skip(self))]
59    pub async fn update<T: Serialize + std::fmt::Debug>(
60        &self,
61        id: AccountId,
62        description: Option<String>,
63        metadata: Option<T>,
64    ) -> Result<AccountId, SqlxLedgerError> {
65        let metadata_json = match metadata {
66            Some(m) => Some(serde_json::to_value(m)?),
67            None => None,
68        };
69        sqlx::query_file!(
70            "src/account/sql/update-account.sql",
71            id as AccountId,
72            description,
73            metadata_json
74        )
75        .execute(&self.pool)
76        .await?;
77        Ok(id)
78    }
79
80    #[instrument(name = "sqlx_ledger.accounts.find_by_code", skip(self))]
81    pub async fn find_by_code(&self, code: &str) -> Result<Option<AccountId>, SqlxLedgerError> {
82        let record = sqlx::query!(
83            r#"SELECT id FROM sqlx_ledger_accounts WHERE code = $1 LIMIT 1"#,
84            code
85        )
86        .fetch_optional(&self.pool)
87        .await?;
88        Ok(record.map(|r| AccountId::from(r.id)))
89    }
90}