backend/service/
areas.rs

1//! Service layer for areas
2
3use actix_http::StatusCode;
4use chrono::Days;
5use uuid::Uuid;
6
7use crate::{
8    config::data::SharedPool,
9    error::ServiceError,
10    model::{
11        dto::{
12            areas::{AreaDto, AreaKind, AreaSearchParameters, NewAreaDto, UpdateAreaDto},
13            areas_impl::{
14                from_new_area_dto_to_hydrology, from_new_area_dto_to_shading,
15                from_new_area_dto_to_soil_texture, from_update_area_dto_to_update_hydrology,
16                from_update_area_dto_to_update_shading,
17                from_update_area_dto_to_update_soil_texture,
18            },
19            core::TimelinePage,
20        },
21        entity::{
22            areas::{Hydrology, Shading, SoilTexture},
23            areas_impl::{
24                create_hydrologies, create_shadings, create_soil_textures, delete_areas_by_ids,
25                find_area, update_hydrologies, update_shadings, update_soil_textures,
26                FindAreaParameters,
27            },
28        },
29    },
30};
31
32/// Time offset in days for loading areas in the timeline.
33pub const TIME_LINE_LOADING_OFFSET_DAYS: u64 = 356;
34
35/// Search areas from the database.
36///
37/// # Errors
38/// If the connection to the database could not be established.
39pub async fn find(
40    search_parameters: AreaSearchParameters,
41    pool: &SharedPool,
42) -> Result<TimelinePage<AreaDto>, ServiceError> {
43    let mut conn = pool.get().await?;
44
45    let from = search_parameters
46        .relative_to_date
47        .checked_sub_days(Days::new(TIME_LINE_LOADING_OFFSET_DAYS))
48        .ok_or_else(|| {
49            ServiceError::new(
50                StatusCode::BAD_REQUEST,
51                "Could not add days to relative_to_date",
52            )
53        })?;
54
55    let to = search_parameters
56        .relative_to_date
57        .checked_add_days(Days::new(TIME_LINE_LOADING_OFFSET_DAYS))
58        .ok_or_else(|| {
59            ServiceError::new(
60                StatusCode::BAD_REQUEST,
61                "Could not add days to relative_to_date",
62            )
63        })?;
64
65    let search_parameters = FindAreaParameters {
66        area_kind: search_parameters.kind,
67        layer_id: search_parameters.layer_id,
68        from,
69        to,
70    };
71    let result: Vec<_> = find_area(search_parameters, &mut conn).await?;
72
73    Ok(TimelinePage {
74        results: result,
75        from,
76        to,
77    })
78}
79
80/// Create a new area in the database.
81///
82/// # Errors
83/// If the connection to the database could not be established.
84pub async fn create(
85    area_kind: AreaKind,
86    dtos: Vec<NewAreaDto>,
87    pool: &SharedPool,
88) -> Result<Vec<AreaDto>, ServiceError> {
89    let mut conn = pool.get().await?;
90
91    let result = match area_kind {
92        AreaKind::Shade => {
93            let new_shadings: Vec<Shading> = from_new_area_dto_to_shading(dtos)?;
94            create_shadings(new_shadings, &mut conn).await?
95        }
96        AreaKind::Hydrology => {
97            let new_hydrologies: Vec<Hydrology> = from_new_area_dto_to_hydrology(dtos)?;
98            create_hydrologies(new_hydrologies, &mut conn).await?
99        }
100        AreaKind::SoilTexture => {
101            let new_soil_textures: Vec<SoilTexture> = from_new_area_dto_to_soil_texture(dtos)?;
102            create_soil_textures(new_soil_textures, &mut conn).await?
103        }
104    };
105    Ok(result)
106}
107
108/// Update the areas in the database.
109///
110/// # Errors
111/// If the connection to the database could not be established.
112pub async fn update(
113    area_kind: AreaKind,
114    dto: UpdateAreaDto,
115    pool: &SharedPool,
116) -> Result<Vec<AreaDto>, ServiceError> {
117    let mut conn = pool.get().await?;
118
119    let result = match area_kind {
120        AreaKind::Shade => {
121            let updates = from_update_area_dto_to_update_shading(dto)?;
122            update_shadings(updates, &mut conn).await?
123        }
124        AreaKind::Hydrology => {
125            let updates = from_update_area_dto_to_update_hydrology(dto)?;
126            update_hydrologies(updates, &mut conn).await?
127        }
128        AreaKind::SoilTexture => {
129            let updates = from_update_area_dto_to_update_soil_texture(dto)?;
130            update_soil_textures(updates, &mut conn).await?
131        }
132    };
133
134    Ok(result)
135}
136
137/// Delete the areas from the database.
138///
139/// # Errors
140/// If the connection to the database could not be established.
141pub async fn delete_by_ids(
142    area_kind: AreaKind,
143    dtos: Vec<Uuid>,
144    pool: &SharedPool,
145) -> Result<(), ServiceError> {
146    let mut conn = pool.get().await?;
147    delete_areas_by_ids(area_kind, dtos, &mut conn).await?;
148    Ok(())
149}