Skip to main content

shared/domain/account/
repository.rs

1use std::sync::Arc;
2
3use crate::error::{
4    CoreError, CredentialField, InternalError, ResourceKind, Result, ValidationError,
5};
6
7use super::model::Account;
8use super::ports::database::DatabaseAdapter;
9use super::ports::query::QueryBuilder;
10
11#[derive(Clone)]
12pub struct AccountRepository {
13    adapter: Arc<dyn DatabaseAdapter<Account>>,
14}
15
16impl AccountRepository {
17    pub fn new(adapter: Arc<dyn DatabaseAdapter<Account>>) -> Self {
18        Self { adapter }
19    }
20}
21
22impl AccountRepository {
23    #[tracing::instrument(name = "db.account.insert", skip(self, account))]
24    pub async fn insert(&self, account: Account) -> Result<()> {
25        match self.adapter.insert(account).await {
26            Ok(_id) => Ok(()),
27            Err(err) => {
28                tracing::error!("Failed to insert account to database - {err}");
29                Err(CoreError::Internal(InternalError::Database(
30                    err.to_string(),
31                )))
32            }
33        }
34    }
35
36    #[tracing::instrument(name = "db.account.find", skip(self, user_id))]
37    pub async fn find(&self, user_id: &str) -> Result<Account> {
38        let filter = QueryBuilder::default().eq("userId", user_id);
39
40        match self.adapter.find_one(filter).await {
41            Ok(Some(session)) => Ok(session),
42            Ok(None) => Err(CoreError::NotFound(ResourceKind::User {
43                id: Some(user_id.into()),
44                email: None,
45            })),
46            Err(err) => {
47                tracing::error!(error_code = "InternalError::Database", error = %err, "Database query failed");
48                Err(err)
49            }
50        }
51    }
52
53    #[tracing::instrument(name = "db.account.update_password", skip(self, user_id, password))]
54    pub async fn update_password(&self, user_id: &str, password: &str) -> Result<Account> {
55        let filter = QueryBuilder::default().eq("userId", user_id);
56        let update = QueryBuilder::default().set("password", password);
57
58        match self.adapter.find_one_and_update(filter, update).await {
59            Ok(Some(account)) => Ok(account),
60            Ok(None) => Err(CoreError::Validation(ValidationError::Missing {
61                field: CredentialField::Password,
62            })),
63            Err(err) => {
64                tracing::error!(error_code = "InternalError::Database", error = %err, "Database query failed");
65                Err(err)
66            }
67        }
68    }
69
70    #[tracing::instrument(name = "db.account.lock_account", skip(self, user_id))]
71    pub async fn lock_account(&self, user_id: &str) -> Result<Account> {
72        let filter = QueryBuilder::default().eq("userId", user_id);
73        let update = QueryBuilder::default().set("locked", true);
74
75        match self.adapter.find_one_and_update(filter, update).await {
76            Ok(Some(account)) => Ok(account),
77            Ok(None) => Err(CoreError::Validation(ValidationError::Missing {
78                field: CredentialField::Username,
79            })),
80            Err(err) => {
81                tracing::error!(error_code = "InternalError::Database", error = %err, "Database query failed");
82                Err(err)
83            }
84        }
85    }
86    #[tracing::instrument(name = "db.account.unlock_account", skip(self, user_id))]
87    pub async fn unlock_account(&self, user_id: &str) -> Result<Account> {
88        let filter = QueryBuilder::default().eq("userId", user_id);
89        let update = QueryBuilder::default().set("locked", false);
90
91        match self.adapter.find_one_and_update(filter, update).await {
92            Ok(Some(account)) => Ok(account),
93            Ok(None) => Err(CoreError::Validation(ValidationError::Missing {
94                field: CredentialField::Username,
95            })),
96            Err(err) => {
97                tracing::error!(error_code = "InternalError::Database", error = %err, "Database query failed");
98                Err(err)
99            }
100        }
101    }
102
103    #[tracing::instrument(name = "db.user.validate_account", skip(self, user_id))]
104    pub async fn validate_account(&self, user_id: &str) -> Result<()> {
105        let filter = QueryBuilder::default().eq("id", user_id);
106        let update = QueryBuilder::default().set("verified", true);
107
108        match self.adapter.find_one_and_update(filter, update).await {
109            Ok(Some(_account)) => Ok(()),
110            Ok(None) => Err(CoreError::Validation(ValidationError::Missing {
111                field: CredentialField::ObjectId,
112            })),
113            Err(err) => {
114                tracing::error!(error_code = "InternalError::Database", error = %err, "Database query failed");
115                Err(err)
116            }
117        }
118    }
119}