backend/model/dto/
areas_impl.rs

1use actix_web::http::StatusCode;
2use chrono::Utc;
3use uuid::Uuid;
4
5use crate::{
6    error::ServiceError,
7    model::{
8        dto::areas::{AreaDto, AreaKind, AreaType, AreaUpdate, NewAreaDto, UpdateAreaDto},
9        entity::areas::{
10            Hydrology, Shading, SoilTexture, UpdateHydrology, UpdateShading, UpdateSoilTexture,
11        },
12    },
13};
14
15// From AreaDto => entity
16
17impl From<Shading> for AreaDto {
18    fn from(entity: Shading) -> Self {
19        Self {
20            id: entity.id,
21            layer_id: entity.layer_id,
22            area_type: AreaType::Shade(entity.shade),
23            geometry: entity.geometry,
24            add_date: entity.add_date,
25            remove_date: entity.remove_date,
26            notes: entity.notes,
27        }
28    }
29}
30
31impl From<Hydrology> for AreaDto {
32    fn from(entity: Hydrology) -> Self {
33        Self {
34            id: entity.id,
35            layer_id: entity.layer_id,
36            area_type: AreaType::Hydrology(entity.water_requirement),
37            geometry: entity.geometry,
38            add_date: entity.add_date,
39            remove_date: entity.remove_date,
40            notes: entity.notes,
41        }
42    }
43}
44
45impl From<SoilTexture> for AreaDto {
46    fn from(entity: SoilTexture) -> Self {
47        Self {
48            id: entity.id,
49            layer_id: entity.layer_id,
50            area_type: AreaType::SoilTexture(entity.soil_texture),
51            geometry: entity.geometry,
52            add_date: entity.add_date,
53            remove_date: entity.remove_date,
54            notes: entity.notes,
55        }
56    }
57}
58
59/// Error message when invalid area types are supplied.
60const INVALID_AREA_TYPE: &str = "invalid area type";
61
62/// Maps `NewAreaDto`s to `Shading`s.
63/// Precondition is that all `dtos` have `area_type == AreaType::Shade(_)`.
64///
65/// # Errors
66/// * Returns an error if any `dtos` have a different `area_type`.
67pub fn from_new_area_dto_to_shading(
68    dtos: Vec<NewAreaDto>,
69    user_id: Uuid,
70) -> Result<Vec<Shading>, ServiceError> {
71    dtos.into_iter()
72        .map(|dto| match dto.area_type {
73            AreaType::Shade(shade) => Ok(Shading {
74                id: dto.id,
75                layer_id: dto.layer_id,
76                shade,
77                geometry: dto.geometry,
78                add_date: dto.add_date,
79                remove_date: None,
80                notes: String::new(),
81                created_at: Utc::now().naive_utc(),
82                modified_at: Utc::now().naive_utc(),
83                created_by: user_id,
84                modified_by: user_id,
85            }),
86            _ => Err(ServiceError::new(
87                StatusCode::BAD_REQUEST,
88                INVALID_AREA_TYPE,
89            )),
90        })
91        .collect()
92}
93
94/// Maps `NewAreaDto`s to `Hydrology`s.
95/// Precondition is that all `dtos` have `area_type == AreaType::Hydrology(_)`.
96///
97/// # Errors
98/// * Returns an error if any `dtos` have a different `area_type`.
99pub fn from_new_area_dto_to_hydrology(
100    dtos: Vec<NewAreaDto>,
101    user_id: Uuid,
102) -> Result<Vec<Hydrology>, ServiceError> {
103    dtos.into_iter()
104        .map(|dto| match dto.area_type {
105            AreaType::Hydrology(water_requirement) => Ok(Hydrology {
106                id: dto.id,
107                layer_id: dto.layer_id,
108                water_requirement,
109                geometry: dto.geometry,
110                add_date: dto.add_date,
111                remove_date: None,
112                notes: String::new(),
113                created_at: Utc::now().naive_utc(),
114                modified_at: Utc::now().naive_utc(),
115                created_by: user_id,
116                modified_by: user_id,
117            }),
118            _ => Err(ServiceError::new(
119                StatusCode::BAD_REQUEST,
120                INVALID_AREA_TYPE,
121            )),
122        })
123        .collect()
124}
125
126/// Maps `NewAreaDto`s to `SoilTexture`s.
127/// Precondition is that all `dtos` have `area_type == AreaType::SoilTexture(_)`.
128///
129/// # Errors
130/// * Returns an error if any `dtos` have a different `area_type`.
131pub fn from_new_area_dto_to_soil_texture(
132    dtos: Vec<NewAreaDto>,
133    user_id: Uuid,
134) -> Result<Vec<SoilTexture>, ServiceError> {
135    dtos.into_iter()
136        .map(|dto| match dto.area_type {
137            AreaType::SoilTexture(soil_texture) => Ok(SoilTexture {
138                id: dto.id,
139                layer_id: dto.layer_id,
140                soil_texture,
141                geometry: dto.geometry,
142                add_date: dto.add_date,
143                remove_date: None,
144                notes: String::new(),
145                created_at: Utc::now().naive_utc(),
146                modified_at: Utc::now().naive_utc(),
147                created_by: user_id,
148                modified_by: user_id,
149            }),
150            _ => Err(ServiceError::new(
151                StatusCode::BAD_REQUEST,
152                INVALID_AREA_TYPE,
153            )),
154        })
155        .collect()
156}
157
158/// Maps `UpdateAreaDto` to `UpdateShading`s.
159/// Precondition is that the `dto` has `area_kind == AreaKind::Shade`.
160///
161/// # Errors
162/// * Returns an error if the `dto` has a different `area_kind`.
163pub fn from_update_area_dto_to_update_shading(
164    dto: UpdateAreaDto,
165    user_id: Uuid,
166) -> Result<Vec<UpdateShading>, ServiceError> {
167    if dto.area_kind == AreaKind::Shade {
168        match dto.update {
169            AreaUpdate::UpdateValue(geometry_vec) => Ok(geometry_vec
170                .into_iter()
171                .map(|v| UpdateShading {
172                    id: v.id,
173                    shade: match v.area_type {
174                        AreaType::Shade(shade) => Some(shade),
175                        _ => None,
176                    },
177                    modified_by: user_id,
178                    ..Default::default()
179                })
180                .collect()),
181            AreaUpdate::UpdateAddDate(add_date_vec) => Ok(add_date_vec
182                .into_iter()
183                .map(|v| UpdateShading {
184                    id: v.id,
185                    add_date: Some(v.add_date),
186                    modified_by: user_id,
187                    ..Default::default()
188                })
189                .collect()),
190            AreaUpdate::UpdateRemoveDate(remove_date_vec) => Ok(remove_date_vec
191                .into_iter()
192                .map(|v| UpdateShading {
193                    id: v.id,
194                    remove_date: Some(v.remove_date),
195                    modified_by: user_id,
196                    ..Default::default()
197                })
198                .collect()),
199            AreaUpdate::UpdateNotes(notes_vec) => Ok(notes_vec
200                .into_iter()
201                .map(|v| UpdateShading {
202                    id: v.id,
203                    notes: Some(v.notes),
204                    modified_by: user_id,
205                    ..Default::default()
206                })
207                .collect()),
208        }
209    } else {
210        Err(ServiceError::new(
211            StatusCode::BAD_REQUEST,
212            INVALID_AREA_TYPE,
213        ))
214    }
215}
216
217/// Maps `UpdateAreaDto` to `UpdateHydrology`s.
218/// Precondition is that the `dto` has `area_kind == AreaKind::Hydrology`.
219///
220/// # Errors
221/// * Returns an error if the `dto` has a different `area_kind`.
222pub fn from_update_area_dto_to_update_hydrology(
223    dto: UpdateAreaDto,
224    user_id: Uuid,
225) -> Result<Vec<UpdateHydrology>, ServiceError> {
226    if dto.area_kind == AreaKind::Hydrology {
227        match dto.update {
228            AreaUpdate::UpdateValue(geometry_vec) => Ok(geometry_vec
229                .into_iter()
230                .map(|v| UpdateHydrology {
231                    id: v.id,
232                    water_requirement: match v.area_type {
233                        AreaType::Hydrology(water_requirement) => Some(water_requirement),
234                        _ => None,
235                    },
236                    modified_by: user_id,
237                    ..Default::default()
238                })
239                .collect()),
240            AreaUpdate::UpdateAddDate(add_date_vec) => Ok(add_date_vec
241                .into_iter()
242                .map(|v| UpdateHydrology {
243                    id: v.id,
244                    add_date: Some(v.add_date),
245                    modified_by: user_id,
246                    ..Default::default()
247                })
248                .collect()),
249            AreaUpdate::UpdateRemoveDate(remove_date_vec) => Ok(remove_date_vec
250                .into_iter()
251                .map(|v| UpdateHydrology {
252                    id: v.id,
253                    remove_date: Some(v.remove_date),
254                    modified_by: user_id,
255                    ..Default::default()
256                })
257                .collect()),
258            AreaUpdate::UpdateNotes(notes_vec) => Ok(notes_vec
259                .into_iter()
260                .map(|v| UpdateHydrology {
261                    id: v.id,
262                    notes: Some(v.notes),
263                    modified_by: user_id,
264                    ..Default::default()
265                })
266                .collect()),
267        }
268    } else {
269        Err(ServiceError::new(
270            StatusCode::BAD_REQUEST,
271            INVALID_AREA_TYPE,
272        ))
273    }
274}
275
276/// Maps `UpdateAreaDto` to `UpdateSoilTexture`s.
277/// Precondition is that the `dto` has `area_kind == AreaKind::SoilTexture`.
278///
279/// # Errors
280/// * Returns an error if the `dto` has a different `area_kind`.
281pub fn from_update_area_dto_to_update_soil_texture(
282    dto: UpdateAreaDto,
283    user_id: Uuid,
284) -> Result<Vec<UpdateSoilTexture>, ServiceError> {
285    if dto.area_kind == AreaKind::SoilTexture {
286        match dto.update {
287            AreaUpdate::UpdateValue(geometry_vec) => Ok(geometry_vec
288                .into_iter()
289                .map(|v| UpdateSoilTexture {
290                    id: v.id,
291                    soil_texture: match v.area_type {
292                        AreaType::SoilTexture(soil_texture) => Some(soil_texture),
293                        _ => None,
294                    },
295                    modified_by: user_id,
296                    ..Default::default()
297                })
298                .collect()),
299            AreaUpdate::UpdateAddDate(add_date_vec) => Ok(add_date_vec
300                .into_iter()
301                .map(|v| UpdateSoilTexture {
302                    id: v.id,
303                    add_date: Some(v.add_date),
304                    modified_by: user_id,
305                    ..Default::default()
306                })
307                .collect()),
308            AreaUpdate::UpdateRemoveDate(remove_date_vec) => Ok(remove_date_vec
309                .into_iter()
310                .map(|v| UpdateSoilTexture {
311                    id: v.id,
312                    remove_date: Some(v.remove_date),
313                    modified_by: user_id,
314                    ..Default::default()
315                })
316                .collect()),
317            AreaUpdate::UpdateNotes(notes_vec) => Ok(notes_vec
318                .into_iter()
319                .map(|v| UpdateSoilTexture {
320                    id: v.id,
321                    notes: Some(v.notes),
322                    ..Default::default()
323                })
324                .collect()),
325        }
326    } else {
327        Err(ServiceError::new(
328            StatusCode::BAD_REQUEST,
329            INVALID_AREA_TYPE,
330        ))
331    }
332}