airlab_lib/model/
view_clone.rs

1use crate::ctx::Ctx;
2use crate::model::ModelManager;
3use crate::model::Result;
4use crate::model::clone::{Clone, CloneBmc, CloneFilter};
5use crate::model::protein::{Protein, ProteinBmc, ProteinFilter};
6use crate::model::species::{Species, SpeciesBmc, SpeciesFilter};
7use crate::model::validation::{MinValidation, ValidationBmc, ValidationFilter};
8use modql::filter::ListOptions;
9use serde::{Deserialize, Serialize};
10use serde_json::json;
11use std::collections::{HashMap, hash_map::Entry};
12
13#[derive(Serialize, Deserialize, Debug, Clone, Default)]
14pub struct ViewClone {
15    pub id: i32,
16    #[serde(rename = "createdBy")]
17    pub created_by: i32,
18    #[serde(rename = "updatedBy")]
19    pub updated_at: chrono::DateTime<chrono::Utc>,
20    #[serde(rename = "proteinId")]
21    pub protein_id: i32,
22    #[serde(rename = "speciesId")]
23    pub species_id: Option<i32>,
24    pub name: String,
25    pub isotype: Option<String>,
26    pub epitope: Option<String>,
27    #[serde(rename = "isPhospho")]
28    pub is_phospho: bool,
29    #[serde(rename = "isPolyclonal")]
30    pub is_polyclonal: bool,
31    pub reactivity: Option<Vec<i32>>,
32    pub application: Option<serde_json::Value>,
33    pub meta: Option<serde_json::Value>,
34    pub protein: Protein,
35    pub species: Option<Species>,
36    pub validations: Vec<MinValidation>,
37}
38
39pub struct ViewCloneBmc;
40
41impl ViewCloneBmc {
42    pub async fn get(ctx: &Ctx, mm: &ModelManager, id: i32) -> Result<ViewClone> {
43        let clone = CloneBmc::get(ctx, mm, id).await?;
44        let protein = ProteinBmc::get(ctx, mm, clone.protein_id).await?;
45        let species = match clone.species_id {
46            Some(sid) => Some(SpeciesBmc::get(ctx, mm, sid).await?),
47            None => None,
48        };
49        let ret = ViewClone {
50            id: clone.id,
51            application: clone.application,
52            created_by: clone.created_by,
53            epitope: clone.epitope,
54            is_phospho: clone.is_phospho,
55            updated_at: clone.updated_at,
56            protein_id: clone.protein_id,
57            species_id: clone.species_id,
58            name: clone.name,
59            isotype: clone.isotype,
60            is_polyclonal: clone.is_polyclonal,
61            reactivity: clone.reactivity,
62            meta: clone.meta,
63            protein,
64            species,
65            validations: vec![],
66        };
67        Ok(ret)
68    }
69
70    pub async fn list(
71        ctx: &Ctx,
72        mm: &ModelManager,
73        group_id: Option<i32>,
74        filters: Option<Vec<CloneFilter>>,
75        list_options: Option<ListOptions>,
76    ) -> Result<Vec<ViewClone>> {
77        let mut protein_map = HashMap::new();
78        let mut species_map = HashMap::new();
79        if let Some(group_id) = group_id {
80            let protein_filters: Option<Vec<ProteinFilter>> = match serde_json::from_value(json!([
81                {
82                    "group_id": {"$eq":group_id}
83                }
84            ])) {
85                Ok(ok) => Some(ok),
86                Err(_) => None,
87            };
88            let protein_op = ListOptions {
89                limit: Some(10_000),
90                ..Default::default()
91            };
92            let proteins: Vec<Protein> =
93                ProteinBmc::list(ctx, mm, protein_filters, Some(protein_op)).await?;
94            for protein in proteins {
95                protein_map.insert(protein.id, protein);
96            }
97
98            let species_filters: Option<Vec<SpeciesFilter>> = match serde_json::from_value(json!([
99                {
100                    "group_id": {"$eq": group_id}
101                }
102            ])) {
103                Ok(ok) => Some(ok),
104                Err(_) => None,
105            };
106            let speciess: Vec<Species> = SpeciesBmc::list(ctx, mm, species_filters, None).await?;
107            for species in speciess {
108                species_map.insert(species.id, species);
109            }
110        }
111
112        let clones: Vec<Clone> = CloneBmc::list(ctx, mm, filters, list_options).await?;
113        let filters: Option<Vec<ValidationFilter>> =
114            match serde_json::from_value(json!([{"group_id": { "$eq": group_id}}])) {
115                Ok(o) => Some(o),
116                Err(_) => None,
117            };
118        let valop = ListOptions {
119            limit: Some(10_000),
120            ..Default::default()
121        };
122        let mut val_map: HashMap<i32, Vec<MinValidation>> = HashMap::new();
123        let min_validations = ValidationBmc::minlist(ctx, mm, filters, Some(valop)).await?;
124        for val in min_validations {
125            let o = match val_map.entry(val.clone_id) {
126                Entry::Occupied(o) => o.into_mut(),
127                Entry::Vacant(v) => v.insert(vec![]),
128            };
129            o.push(val);
130        }
131        let mut returns = vec![];
132        for clone in clones {
133            let protein = match protein_map.get(&{ clone.protein_id }) {
134                Some(v) => v.clone(),
135                None => Protein {
136                    id: 0,
137                    group_id: 0,
138                    created_at: chrono::offset::Utc::now(),
139                    created_by: 0,
140                    description: None,
141                    ..Default::default()
142                },
143            };
144            let mut species = None;
145
146            if let Some(species_id) = &clone.species_id {
147                species = species_map.get(species_id).cloned();
148            }
149            let validations = match val_map.get(&clone.id) {
150                Some(s) => (*s).clone(),
151                None => vec![],
152            };
153            returns.push(ViewClone {
154                id: clone.id,
155                application: clone.application,
156                created_by: clone.created_by,
157                epitope: clone.epitope,
158                is_phospho: clone.is_phospho,
159                updated_at: clone.updated_at,
160                protein_id: clone.protein_id,
161                species_id: clone.species_id,
162                name: clone.name,
163                isotype: clone.isotype,
164                is_polyclonal: clone.is_polyclonal,
165                reactivity: clone.reactivity,
166                meta: clone.meta,
167                protein,
168                species,
169                validations,
170            });
171        }
172
173        Ok(returns)
174    }
175}
176
177#[cfg(test)]
178mod tests {
179    use super::*;
180    use anyhow::Result;
181
182    #[ignore]
183    #[tokio::test]
184    async fn test_view_clone_list_all_ok() -> Result<()> {
185        let mm = ModelManager::new().await?;
186        let ctx = Ctx::root_ctx();
187
188        let clones = ViewCloneBmc::list(&ctx, &mm, Some(1000), None, None).await?;
189
190        let _clones: Vec<ViewClone> = clones
191            .into_iter()
192            .filter(|t| t.name.starts_with("test_list_all_ok-clone"))
193            .collect();
194
195        Ok(())
196    }
197}