1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
//! Service layer for plantings.

use actix_http::StatusCode;
use actix_web::web::Data;
use chrono::Days;
use uuid::Uuid;

use crate::config::data::AppDataInner;
use crate::error::ServiceError;
use crate::model::dto::core::TimelinePage;
use crate::model::dto::plantings::{
    DeletePlantingDto, PlantingDto, PlantingSearchParameters, UpdatePlantingDto,
};
use crate::model::entity::plantings::Planting;
use crate::model::entity::plantings_impl::FindPlantingsParameters;

/// Time offset in days for loading plantings in the timeline.
pub const TIME_LINE_LOADING_OFFSET_DAYS: u64 = 356;

/// Search plantings from the database.
///
/// # Errors
/// If the connection to the database could not be established.
pub async fn find(
    search_parameters: PlantingSearchParameters,
    app_data: &Data<AppDataInner>,
) -> Result<TimelinePage<PlantingDto>, ServiceError> {
    let mut conn = app_data.pool.get().await?;

    let from = search_parameters
        .relative_to_date
        .checked_sub_days(Days::new(TIME_LINE_LOADING_OFFSET_DAYS))
        .ok_or_else(|| {
            ServiceError::new(
                StatusCode::BAD_REQUEST,
                "Could not add days to relative_to_date",
            )
        })?;

    let to = search_parameters
        .relative_to_date
        .checked_add_days(Days::new(TIME_LINE_LOADING_OFFSET_DAYS))
        .ok_or_else(|| {
            ServiceError::new(
                StatusCode::BAD_REQUEST,
                "Could not add days to relative_to_date",
            )
        })?;

    let search_parameters = FindPlantingsParameters {
        layer_id: search_parameters.layer_id,
        plant_id: search_parameters.plant_id,
        from,
        to,
    };
    let result = Planting::find(search_parameters, &mut conn).await?;

    Ok(TimelinePage {
        results: result,
        from,
        to,
    })
}

/// Get all plantings that have a specific seed id.
/// Also returns a plantings map id.
///
/// # Errors
/// If the connection to the database could not be established.
pub async fn find_by_seed_id(
    seed_id: i32,
    app_data: &Data<AppDataInner>,
) -> Result<Vec<PlantingDto>, ServiceError> {
    let mut conn = app_data.pool.get().await?;
    let result = Planting::find_by_seed_id(seed_id, &mut conn).await?;
    Ok(result)
}

/// Create a new planting in the database.
///
/// # Errors
/// If the connection to the database could not be established.
pub async fn create(
    dtos: Vec<PlantingDto>,
    map_id: i32,
    user_id: Uuid,
    app_data: &Data<AppDataInner>,
) -> Result<Vec<PlantingDto>, ServiceError> {
    let mut conn = app_data.pool.get().await?;
    let result = Planting::create(dtos, map_id, user_id, &mut conn).await?;
    Ok(result)
}

/// Update the planting in the database.
///
/// # Errors
/// If the connection to the database could not be established.
pub async fn update(
    dto: UpdatePlantingDto,
    map_id: i32,
    user_id: Uuid,
    app_data: &Data<AppDataInner>,
) -> Result<Vec<PlantingDto>, ServiceError> {
    let mut conn = app_data.pool.get().await?;
    let result = Planting::update(dto, map_id, user_id, &mut conn).await?;
    Ok(result)
}

/// Delete the planting from the database.
///
/// # Errors
/// If the connection to the database could not be established.
pub async fn delete_by_ids(
    dtos: Vec<DeletePlantingDto>,
    map_id: i32,
    user_id: Uuid,
    app_data: &Data<AppDataInner>,
) -> Result<(), ServiceError> {
    let mut conn = app_data.pool.get().await?;
    let _ = Planting::delete_by_ids(dtos, map_id, user_id, &mut conn).await?;
    Ok(())
}