1use crate::ctx::Ctx;
2use crate::model::ModelManager;
3use crate::model::Result;
4use crate::model::base::{self, DbBmc};
5use modql::field::Fields;
7use modql::filter::{FilterNodes, ListOptions, OpValsInt64, OpValsString};
8use serde::{Deserialize, Serialize};
9use sqlx::FromRow;
10
11impl ValidationFileBmc {
12 #[must_use]
13 pub fn get_create_sql(drop_table: bool) -> String {
14 let table = Self::TABLE;
15 format!(
16 r##"{}
17create table if not exists "{table}" (
18 id serial primary key,
19 validation_id integer NOT NULL,
20 created_by integer NOT NULL,
21 hash character varying NOT NULL,
22 size integer,
23 name character varying,
24 extension character varying NOT NULL,
25 description character varying,
26 meta jsonb,
27 created_at timestamp with time zone DEFAULT now() NOT NULL
28);
29CREATE INDEX "IDX_validation_file_created_by" ON validation_file USING btree (created_by);
30CREATE INDEX "IDX_validation_file_hash" ON validation_file USING btree (hash);
31CREATE INDEX "IDX_validation_file_validation_id" ON validation_file USING btree (validation_id);
32 "##,
33 if drop_table {
34 format!("drop table if exists {table};")
35 } else {
36 String::new()
37 }
38 )
39 }
40}
41
42#[derive(Debug, Clone, Fields, FromRow, Serialize, Deserialize)]
43pub struct ValidationFile {
44 pub id: i32,
45
46 #[serde(rename = "validationId")]
47 pub validation_id: i32,
48 #[serde(rename = "createdBy")]
49 pub created_by: i32,
50 pub hash: String,
51 pub size: i32,
52 pub name: Option<String>,
53 pub extension: String,
54 pub description: Option<String>,
55 pub meta: Option<serde_json::Value>,
56 #[serde(rename = "createdAt")]
57 pub created_at: chrono::DateTime<chrono::Utc>,
58}
59
60#[derive(Fields, Deserialize, Clone, Debug)]
61pub struct ValidationFileForCreate {
62 #[serde(rename = "validationId")]
63 pub validation_id: i32,
64 #[serde(rename = "createdBy")]
65 pub created_by: i32,
66 pub hash: String,
67 pub size: i32,
68 pub name: Option<String>,
69 pub extension: String,
70 pub description: Option<String>,
71 #[serde(rename = "createdAt")]
73 pub created_at: chrono::DateTime<chrono::Utc>,
74}
75
76#[derive(Fields, Default, Deserialize, Debug)]
77pub struct ValidationFileForUpdate {
78 pub hash: String,
79 pub size: i32,
80 pub name: Option<String>,
81 pub extension: Option<String>,
82 pub description: Option<String>,
83}
84
85#[derive(FilterNodes, Deserialize, Default, Debug)]
86pub struct ValidationFileFilter {
87 id: Option<OpValsInt64>,
88 validation_id: Option<OpValsInt64>,
89
90 name: Option<OpValsString>,
91}
92
93pub struct ValidationFileBmc;
94
95impl DbBmc for ValidationFileBmc {
96 const TABLE: &'static str = "validation_file";
97}
98
99impl ValidationFileBmc {
100 pub async fn create(
101 ctx: &Ctx,
102 mm: &ModelManager,
103 validation_file_c: ValidationFileForCreate,
104 ) -> Result<i32> {
105 base::create::<Self, _>(ctx, mm, validation_file_c).await
106 }
107 pub async fn create_full(
108 ctx: &Ctx,
109 mm: &ModelManager,
110 validation_file_c: ValidationFile,
111 ) -> Result<i32> {
112 base::create::<Self, _>(ctx, mm, validation_file_c).await
113 }
114
115 pub async fn get(ctx: &Ctx, mm: &ModelManager, id: i32) -> Result<ValidationFile> {
116 base::get::<Self, _>(ctx, mm, id).await
117 }
118
119 pub async fn list(
120 ctx: &Ctx,
121 mm: &ModelManager,
122 filters: Option<Vec<ValidationFileFilter>>,
123 list_options: Option<ListOptions>,
124 ) -> Result<Vec<ValidationFile>> {
125 base::list::<Self, _, _>(ctx, mm, filters, list_options).await
126 }
127
128 pub async fn update(
129 ctx: &Ctx,
130 mm: &ModelManager,
131 id: i32,
132 validation_file_u: ValidationFileForUpdate,
133 ) -> Result<()> {
134 base::update::<Self, _>(ctx, mm, id, validation_file_u).await
135 }
136
137 pub async fn delete(ctx: &Ctx, mm: &ModelManager, id: i32) -> Result<()> {
138 base::delete::<Self>(ctx, mm, id).await
139 }
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145 use crate::_dev_utils;
146 use crate::model::Error;
147 use anyhow::Result;
148 use serde_json::json;
149
150 #[ignore]
151 #[tokio::test]
152 async fn test_validation_file_create_ok() -> Result<()> {
153 let mm = ModelManager::new().await?;
154 let ctx = Ctx::root_ctx();
155 let fx_name = "test_create_ok name";
156
157 let validation_file_c = ValidationFileForCreate {
158 name: None,
159 created_by: 261,
160 validation_id: 2221,
161 hash: String::new(),
162 size: 0,
163 extension: "pdf".into(),
164 description: None,
165 created_at: chrono::offset::Utc::now(),
166 };
167 let id = ValidationFileBmc::create(&ctx, &mm, validation_file_c).await?;
168
169 let validation_file = ValidationFileBmc::get(&ctx, &mm, id).await?;
170 assert_eq!(validation_file.name, Some(fx_name.into()));
171
172 ValidationFileBmc::delete(&ctx, &mm, id).await?;
173
174 Ok(())
175 }
176
177 #[ignore]
178 #[tokio::test]
179 async fn test_validation_file_get_err_not_found() -> Result<()> {
180 let mm = ModelManager::new().await?;
181 let ctx = Ctx::root_ctx();
182 let fx_id = 100;
183
184 let res = ValidationFileBmc::get(&ctx, &mm, fx_id).await;
185
186 assert!(
187 matches!(
188 res,
189 Err(Error::EntityNotFound {
190 entity: "validation_file",
191 id: 100
192 })
193 ),
194 "EntityNotFound not matching"
195 );
196
197 Ok(())
198 }
199
200 #[ignore]
201 #[tokio::test]
202 async fn test_validation_file_list_all_ok() -> Result<()> {
203 let mm = ModelManager::new().await?;
204 let ctx = Ctx::root_ctx();
205 let tname = "test_validation_file_list_all_ok";
206 let seeds = _dev_utils::get_validation_file_seed(tname);
207 _dev_utils::seed_validation_files(&ctx, &mm, &seeds).await?;
208
209 let validation_files = ValidationFileBmc::list(&ctx, &mm, None, None).await?;
210
211 let validation_files: Vec<ValidationFile> = validation_files.into_iter().collect();
212 assert_eq!(
213 validation_files.len(),
214 4,
215 "number of seeded validation_files."
216 );
217
218 if false {
219 for validation_file in validation_files.iter() {
220 ValidationFileBmc::delete(&ctx, &mm, validation_file.id).await?;
221 }
222 }
223
224 Ok(())
225 }
226
227 #[ignore]
228 #[tokio::test]
229 async fn test_validation_file_list_by_filter_ok() -> Result<()> {
230 let mm = ModelManager::new().await?;
231 let ctx = Ctx::root_ctx();
232 let tname = "test_validation_file_list_by_filter_ok";
233 let seeds = _dev_utils::get_validation_file_seed(tname);
234 _dev_utils::seed_validation_files(&ctx, &mm, &seeds).await?;
235
236 let filters: Vec<ValidationFileFilter> = serde_json::from_value(json!([
237 {
238 "name": {
239 "$endsWith": ".a",
240 "$containsAny": ["01", "02"]
241 }
242 },
243 {
244 "name": {"$contains": "03"}
245 }
246 ]))?;
247 let list_options = serde_json::from_value(json!({
248 "order_bys": "!id"
249 }))?;
250 let validation_files =
251 ValidationFileBmc::list(&ctx, &mm, Some(filters), Some(list_options)).await?;
252
253 assert_eq!(validation_files.len(), 3);
254 assert_eq!(validation_files[0].name, Some("wrong".into()));
255
256 if false {
257 let validation_files = ValidationFileBmc::list(
258 &ctx,
259 &mm,
260 Some(serde_json::from_value(json!([{
261 "name": {"$startsWith": "test_list_by_filter_ok"}
262 }]))?),
263 None,
264 )
265 .await?;
266 assert_eq!(validation_files.len(), 5);
267 for validation_file in validation_files.iter() {
268 ValidationFileBmc::delete(&ctx, &mm, validation_file.id).await?;
269 }
270 }
271
272 Ok(())
273 }
274
275 #[ignore]
276 #[tokio::test]
277 async fn test_validation_file_update_ok() -> Result<()> {
278 let mm = ModelManager::new().await?;
279 let ctx = Ctx::root_ctx();
280 let tname = "test_validation_file_update_ok";
281 let seeds = _dev_utils::get_validation_file_seed(tname);
282 let fx_name_new = "test_update_ok - validation_file 01 - new";
283 let fx_validation_file = _dev_utils::seed_validation_files(&ctx, &mm, &seeds)
284 .await?
285 .remove(0);
286
287 ValidationFileBmc::update(
288 &ctx,
289 &mm,
290 fx_validation_file.id,
291 ValidationFileForUpdate {
292 name: Some(fx_name_new.to_string()),
293 ..Default::default()
294 },
295 )
296 .await?;
297
298 let validation_file = ValidationFileBmc::get(&ctx, &mm, fx_validation_file.id).await?;
299 assert_eq!(validation_file.name, Some(fx_name_new.into()));
300
301 Ok(())
302 }
303
304 #[ignore]
305 #[tokio::test]
306 async fn test_validation_file_delete_err_not_found() -> Result<()> {
307 let mm = ModelManager::new().await?;
308 let ctx = Ctx::root_ctx();
309 let fx_id = 100;
310
311 let res = ValidationFileBmc::delete(&ctx, &mm, fx_id).await;
312
313 assert!(
314 matches!(
315 res,
316 Err(Error::EntityNotFound {
317 entity: "validation_file",
318 id: 100
319 })
320 ),
321 "EntityNotFound not matching"
322 );
323
324 Ok(())
325 }
326}