-
Notifications
You must be signed in to change notification settings - Fork 20
/
Copy pathcategory.rs
156 lines (138 loc) · 4.86 KB
/
category.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//! Category service.
use std::sync::Arc;
use super::authorization::{self, ACTION};
use crate::databases::database::{Category, Database, Error as DatabaseError};
use crate::errors::ServiceError;
use crate::models::category::CategoryId;
use crate::models::user::UserId;
pub struct Service {
category_repository: Arc<DbCategoryRepository>,
authorization_service: Arc<authorization::Service>,
}
impl Service {
#[must_use]
pub fn new(category_repository: Arc<DbCategoryRepository>, authorization_service: Arc<authorization::Service>) -> Service {
Service {
category_repository,
authorization_service,
}
}
/// Adds a new category.
///
/// # Errors
///
/// It returns an error if:
///
/// * The user does not have the required permissions.
/// * The category name is empty.
/// * The category already exists.
/// * There is a database error.
pub async fn add_category(&self, category_name: &str, maybe_user_id: Option<UserId>) -> Result<i64, ServiceError> {
self.authorization_service
.authorize(ACTION::AddCategory, maybe_user_id)
.await?;
let trimmed_name = category_name.trim();
if trimmed_name.is_empty() {
return Err(ServiceError::CategoryNameEmpty);
}
// Try to get the category by name to check if it already exists
match self.category_repository.get_by_name(trimmed_name).await {
// Return ServiceError::CategoryAlreadyExists if the category exists
Ok(_) => Err(ServiceError::CategoryAlreadyExists),
Err(e) => match e {
// Otherwise try to create it
DatabaseError::CategoryNotFound => match self.category_repository.add(trimmed_name).await {
Ok(id) => Ok(id),
Err(_) => Err(ServiceError::DatabaseError),
},
_ => Err(ServiceError::DatabaseError),
},
}
}
/// Deletes a category.
///
/// # Errors
///
/// It returns an error if:
///
/// * The user does not have the required permissions.
/// * There is a database error.
pub async fn delete_category(&self, category_name: &str, maybe_user_id: Option<UserId>) -> Result<(), ServiceError> {
self.authorization_service
.authorize(ACTION::DeleteCategory, maybe_user_id)
.await?;
match self.category_repository.delete(category_name).await {
Ok(()) => Ok(()),
Err(e) => match e {
DatabaseError::CategoryNotFound => Err(ServiceError::CategoryNotFound),
_ => Err(ServiceError::DatabaseError),
},
}
}
/// Returns all the categories from the database
///
/// # Errors
///
/// It returns an error if:
///
/// * The user does not have the required permissions.
/// * There is a database error retrieving the categories.
pub async fn get_categories(&self, maybe_user_id: Option<UserId>) -> Result<Vec<Category>, ServiceError> {
self.authorization_service
.authorize(ACTION::GetCategories, maybe_user_id)
.await?;
self.category_repository
.get_all()
.await
.map_err(|_| ServiceError::DatabaseError)
}
}
pub struct DbCategoryRepository {
database: Arc<Box<dyn Database>>,
}
impl DbCategoryRepository {
#[must_use]
pub fn new(database: Arc<Box<dyn Database>>) -> Self {
Self { database }
}
/// It returns the categories.
///
/// # Errors
///
/// It returns an error if there is a database error.
pub async fn get_all(&self) -> Result<Vec<Category>, DatabaseError> {
self.database.get_categories().await
}
/// Adds a new category.
///
/// # Errors
///
/// It returns an error if there is a database error.
pub async fn add(&self, category_name: &str) -> Result<CategoryId, DatabaseError> {
self.database.insert_category_and_get_id(category_name).await
}
/// Deletes a new category.
///
/// # Errors
///
/// It returns an error if there is a database error.
pub async fn delete(&self, category_name: &str) -> Result<(), DatabaseError> {
self.database.delete_category(category_name).await
}
/// It finds a category by name
///
/// # Errors
///
/// It returns an error if there is a database error.
pub async fn get_by_name(&self, category_name: &str) -> Result<Category, DatabaseError> {
self.database.get_category_from_name(category_name).await
}
/// It finds a category by id
///
/// # Errors
///
/// It returns an error if there is a database error.
pub async fn get_by_id(&self, category_id: &CategoryId) -> Result<Category, DatabaseError> {
self.database.get_category_from_id(*category_id).await
}
}