backend/service/
seed.rs

1//! Service layer for seeds.
2
3use chrono::Utc;
4use uuid::Uuid;
5
6use crate::{
7    config::data::SharedPool,
8    error::ServiceError,
9    model::{
10        dto::{ArchiveSeedDto, NewSeedDto, Page, PageParameters, SeedDto, SeedSearchParameters},
11        entity::Seed,
12    },
13};
14
15/// Search seeds from the database.
16/// Seeds are returned in ascending order of their `use_by` dates.
17/// If that is not available, the harvest year is used instead.
18///
19/// By default, archived seeds will not be returned.
20/// This behaviour can be changed using `search_parameters`.
21///
22/// # Errors
23/// If the connection to the database could not be established.
24pub async fn find(
25    search_parameters: SeedSearchParameters,
26    page_parameters: PageParameters,
27    user_id: Uuid,
28    pool: &SharedPool,
29) -> Result<Page<SeedDto>, ServiceError> {
30    let mut conn = pool.get().await?;
31    let result = Seed::find(search_parameters, user_id, page_parameters, &mut conn).await?;
32    Ok(result)
33}
34
35/// Find the seed by id from the database.
36///
37/// # Errors
38/// If the connection to the database could not be established.
39pub async fn find_by_id(
40    id: i32,
41    user_id: Uuid,
42    pool: &SharedPool,
43) -> Result<SeedDto, ServiceError> {
44    let mut conn = pool.get().await?;
45    let result = Seed::find_by_id(id, user_id, &mut conn).await?;
46    Ok(result)
47}
48
49/// Create a new seed in the database.
50///
51/// # Errors
52/// If the connection to the database could not be established.
53pub async fn create(
54    new_seed: NewSeedDto,
55    user_id: Uuid,
56    pool: &SharedPool,
57) -> Result<SeedDto, ServiceError> {
58    let mut conn = pool.get().await?;
59
60    let seed_trimmed_name = NewSeedDto {
61        name: new_seed.name.trim().to_owned(),
62        ..new_seed
63    };
64
65    let result = Seed::create(seed_trimmed_name, user_id, &mut conn).await?;
66    Ok(result)
67}
68
69/// Edits a seed in the database.
70///
71/// # Errors
72/// If the connection to the database could not be established.
73pub async fn edit(
74    id: i32,
75    user_id: Uuid,
76    new_seed: NewSeedDto,
77    pool: &SharedPool,
78) -> Result<SeedDto, ServiceError> {
79    let mut conn = pool.get().await?;
80    let result = Seed::edit(id, user_id, new_seed, &mut conn).await?;
81    Ok(result)
82}
83
84/// Delete the seed from the database.
85///
86/// # Errors
87/// If the connection to the database could not be established.
88pub async fn delete_by_id(id: i32, user_id: Uuid, pool: &SharedPool) -> Result<(), ServiceError> {
89    let mut conn = pool.get().await?;
90    let _ = Seed::delete_by_id(id, user_id, &mut conn).await?;
91    Ok(())
92}
93
94/// Archive or unarchive a seed in the database.
95///
96/// # Errors
97/// If the connection to the database could not be established.
98pub async fn archive(
99    id: i32,
100    user_id: Uuid,
101    archive_seed: ArchiveSeedDto,
102    pool: &SharedPool,
103) -> Result<SeedDto, ServiceError> {
104    // Retrieve the seed before getting the db connection to avoid deadlocks when
105    // fetching two database connections at the same time.
106    let current_seed = find_by_id(id, user_id, pool).await?;
107    let mut conn = pool.get().await?;
108
109    let current_naive_date_time = archive_seed.archived.then(|| Utc::now().naive_utc());
110
111    // Don't archive a seed twice
112    if archive_seed.archived && current_seed.archived_at.is_some() {
113        return Ok(current_seed);
114    }
115
116    let result = Seed::archive(id, current_naive_date_time, user_id, &mut conn).await?;
117    Ok(result)
118}