airlab_lib/model/
panel_element.rs

1use crate::ctx::Ctx;
2use crate::model::ModelManager;
3use crate::model::Result;
4use crate::model::base::{self, DbBmc};
5use modql::field::Fields;
6use modql::filter::{FilterNodes, ListOptions, OpValsInt64};
7use serde::{Deserialize, Serialize};
8use sqlx::FromRow;
9
10impl PanelElementBmc {
11    #[must_use]
12    pub fn get_create_sql(drop_table: bool) -> String {
13        let table = Self::TABLE;
14        format!(
15            r##"{}
16create table if not exists "{table}" (
17  id serial primary key,
18  panel_id integer NOT NULL,
19  conjugate_id integer NOT NULL,
20  dilution_type smallint DEFAULT 0 NOT NULL,
21  concentration real
22);
23ALTER TABLE ONLY panel_element
24  ADD CONSTRAINT "UQ_panel_element_panel_id_and_conjugate_id" UNIQUE (panel_id, conjugate_id);
25CREATE INDEX "IDX_panel_element_conjugate_id" ON panel_element USING btree (conjugate_id);
26CREATE INDEX "IDX_panel_element_panel_id" ON panel_element USING btree (panel_id);
27        "##,
28            if drop_table {
29                format!("drop table if exists {table};")
30            } else {
31                String::new()
32            }
33        )
34    }
35}
36
37#[derive(Debug, Clone, Fields, FromRow, Serialize, Deserialize, Default)]
38pub struct PanelElement {
39    pub id: i32,
40
41    #[serde(rename = "panelId")]
42    pub panel_id: i32,
43    #[serde(rename = "conjugateId")]
44    pub conjugate_id: i32,
45    #[serde(rename = "dilutionType")]
46    pub dilution_type: i16,
47    pub concentration: Option<f32>,
48}
49
50#[derive(Fields, Deserialize, Clone, Debug)]
51pub struct PanelElementForCreate {
52    #[serde(rename = "panelId")]
53    pub panel_id: i32,
54    #[serde(rename = "conjugateId")]
55    pub conjugate_id: i32,
56    #[serde(rename = "dilutionType")]
57    pub dilution_type: i32,
58    pub concentration: Option<f32>,
59}
60
61#[derive(Fields, Default, Deserialize, Debug)]
62pub struct PanelElementForUpdate {
63    #[serde(rename = "dilutionType")]
64    pub dilution_type: i32,
65    pub concentration: Option<f32>,
66}
67
68#[derive(FilterNodes, Deserialize, Default, Debug)]
69pub struct PanelElementFilter {
70    id: Option<OpValsInt64>,
71
72    panel_id: Option<OpValsInt64>,
73    conjugate_id: Option<OpValsInt64>,
74}
75
76pub struct PanelElementBmc;
77
78impl DbBmc for PanelElementBmc {
79    const TABLE: &'static str = "panel_element";
80}
81
82impl PanelElementBmc {
83    pub async fn create(
84        ctx: &Ctx,
85        mm: &ModelManager,
86        panel_element_c: PanelElementForCreate,
87    ) -> Result<i32> {
88        base::create::<Self, _>(ctx, mm, panel_element_c).await
89    }
90    pub async fn create_full(
91        ctx: &Ctx,
92        mm: &ModelManager,
93        panel_element_c: PanelElement,
94    ) -> Result<i32> {
95        base::create::<Self, _>(ctx, mm, panel_element_c).await
96    }
97
98    pub async fn get(ctx: &Ctx, mm: &ModelManager, id: i32) -> Result<PanelElement> {
99        base::get::<Self, _>(ctx, mm, id).await
100    }
101
102    pub async fn list(
103        ctx: &Ctx,
104        mm: &ModelManager,
105        filters: Option<Vec<PanelElementFilter>>,
106        list_options: Option<ListOptions>,
107    ) -> Result<Vec<PanelElement>> {
108        base::list::<Self, _, _>(ctx, mm, filters, list_options).await
109    }
110
111    pub async fn update(
112        ctx: &Ctx,
113        mm: &ModelManager,
114        id: i32,
115        panel_element_u: PanelElementForUpdate,
116    ) -> Result<()> {
117        base::update::<Self, _>(ctx, mm, id, panel_element_u).await
118    }
119
120    pub async fn delete(ctx: &Ctx, mm: &ModelManager, id: i32) -> Result<()> {
121        base::delete::<Self>(ctx, mm, id).await
122    }
123}
124
125#[cfg(test)]
126mod tests {
127    use super::*;
128    use crate::_dev_utils;
129    use crate::model::Error;
130    use anyhow::Result;
131    use serde_json::json;
132
133    #[ignore]
134    #[tokio::test]
135    async fn test_panel_element_create_ok() -> Result<()> {
136        let mm = ModelManager::new().await?;
137        let ctx = Ctx::root_ctx();
138        let _fx_name = "test_create_ok name";
139
140        let panel_element_c = PanelElementForCreate {
141            panel_id: 1815,
142            conjugate_id: 4292,
143            dilution_type: 1,
144            concentration: None,
145        };
146        let id = PanelElementBmc::create(&ctx, &mm, panel_element_c).await?;
147
148        let panel_element = PanelElementBmc::get(&ctx, &mm, id).await?;
149        assert_eq!(panel_element.id, 1);
150
151        PanelElementBmc::delete(&ctx, &mm, id).await?;
152
153        Ok(())
154    }
155
156    #[ignore]
157    #[tokio::test]
158    async fn test_panel_element_get_err_not_found() -> Result<()> {
159        let mm = ModelManager::new().await?;
160        let ctx = Ctx::root_ctx();
161        let fx_id = 100;
162
163        let res = PanelElementBmc::get(&ctx, &mm, fx_id).await;
164
165        assert!(
166            matches!(
167                res,
168                Err(Error::EntityNotFound {
169                    entity: "panel_element",
170                    id: 100
171                })
172            ),
173            "EntityNotFound not matching"
174        );
175
176        Ok(())
177    }
178
179    #[ignore]
180    #[tokio::test]
181    async fn test_panel_element_list_all_ok() -> Result<()> {
182        let mm = ModelManager::new().await?;
183        let ctx = Ctx::root_ctx();
184        let tname = "test_panel_element_list_all_ok";
185        let seeds = _dev_utils::get_panel_element_seed(tname);
186        _dev_utils::seed_panel_elements(&ctx, &mm, &seeds).await?;
187
188        let panel_elements = PanelElementBmc::list(&ctx, &mm, None, None).await?;
189
190        let panel_elements: Vec<PanelElement> =
191            panel_elements.into_iter().filter(|t| t.id == 1).collect();
192        assert_eq!(panel_elements.len(), 4, "number of seeded panel_elements.");
193
194        if false {
195            for panel_element in panel_elements.iter() {
196                PanelElementBmc::delete(&ctx, &mm, panel_element.id).await?;
197            }
198        }
199
200        Ok(())
201    }
202
203    #[ignore]
204    #[tokio::test]
205    async fn test_panel_element_list_by_filter_ok() -> Result<()> {
206        let mm = ModelManager::new().await?;
207        let ctx = Ctx::root_ctx();
208        let tname = "test_panel_element_list_all_ok";
209        let seeds = _dev_utils::get_panel_element_seed(tname);
210        _dev_utils::seed_panel_elements(&ctx, &mm, &seeds).await?;
211
212        let filters: Vec<PanelElementFilter> = serde_json::from_value(json!([
213            {
214                "name": {
215                    "$endsWith": ".a",
216                    "$containsAny": ["01", "02"]
217                }
218            },
219            {
220                "name": {"$contains": "03"}
221            }
222        ]))?;
223        let list_options = serde_json::from_value(json!({
224            "order_bys": "!id"
225        }))?;
226        let panel_elements =
227            PanelElementBmc::list(&ctx, &mm, Some(filters), Some(list_options)).await?;
228
229        assert_eq!(panel_elements.len(), 3);
230        assert!(panel_elements[0].id == 3);
231
232        if false {
233            let panel_elements = PanelElementBmc::list(
234                &ctx,
235                &mm,
236                Some(serde_json::from_value(json!([{
237                    "name": {"$startsWith": "test_list_by_filter_ok"}
238                }]))?),
239                None,
240            )
241            .await?;
242            assert_eq!(panel_elements.len(), 5);
243            for panel_element in panel_elements.iter() {
244                PanelElementBmc::delete(&ctx, &mm, panel_element.id).await?;
245            }
246        }
247
248        Ok(())
249    }
250
251    #[ignore]
252    #[tokio::test]
253    async fn test_panel_element_update_ok() -> Result<()> {
254        let mm = ModelManager::new().await?;
255        let ctx = Ctx::root_ctx();
256        let tname = "test_panel_element_list_all_ok";
257        let seeds = _dev_utils::get_panel_element_seed(tname);
258        let fx_panel_element = _dev_utils::seed_panel_elements(&ctx, &mm, &seeds)
259            .await?
260            .remove(0);
261
262        PanelElementBmc::update(
263            &ctx,
264            &mm,
265            fx_panel_element.id,
266            PanelElementForUpdate {
267                ..Default::default()
268            },
269        )
270        .await?;
271
272        let panel_element = PanelElementBmc::get(&ctx, &mm, fx_panel_element.id).await?;
273        assert_eq!(panel_element.id, 1);
274
275        Ok(())
276    }
277
278    #[ignore]
279    #[tokio::test]
280    async fn test_panel_element_delete_err_not_found() -> Result<()> {
281        let mm = ModelManager::new().await?;
282        let ctx = Ctx::root_ctx();
283        let fx_id = 100;
284
285        let res = PanelElementBmc::delete(&ctx, &mm, fx_id).await;
286
287        assert!(
288            matches!(
289                res,
290                Err(Error::EntityNotFound {
291                    entity: "panel_element",
292                    id: 100
293                })
294            ),
295            "EntityNotFound not matching"
296        );
297
298        Ok(())
299    }
300}