1use diesel::pg::Pg;
4use diesel::{debug_query, BoolExpressionMethods, ExpressionMethods, QueryDsl, QueryResult};
5use diesel_async::{AsyncPgConnection, RunQueryDsl};
6use log::debug;
7use uuid::Uuid;
8
9use crate::db::{
10 function::{array_to_string, greatest4, similarity},
11 pagination::Paginate,
12};
13use crate::model::dto::{Page, PageParameters, SeedSearchParameters};
14use crate::{
15 model::dto::{NewSeedDto, SeedDto},
16 schema::{
17 plants::{self, common_name_de, common_name_en, unique_name},
18 seeds::{self, all_columns, created_by, harvest_year, name, use_by},
19 },
20};
21
22use crate::model::r#enum::include_archived_seeds::IncludeArchivedSeeds;
23use chrono::NaiveDateTime;
24use diesel::dsl::sql;
25use diesel::sql_types::Float;
26
27use super::{NewSeed, Seed};
28
29impl Seed {
30 pub async fn find(
46 search_parameters: SeedSearchParameters,
47 user_id: Uuid,
48 page_parameters: PageParameters,
49 conn: &mut AsyncPgConnection,
50 ) -> QueryResult<Page<SeedDto>> {
51 let search_query = search_parameters.name.as_deref().unwrap_or("");
55
56 let mut query = seeds::table
57 .inner_join(plants::table)
58 .select((
59 greatest4(
60 similarity(name, search_query),
61 similarity(unique_name, search_query),
62 similarity(array_to_string(common_name_de, " "), search_query),
63 similarity(array_to_string(common_name_en, " "), search_query),
64 ),
65 all_columns,
66 ))
67 .into_boxed();
68
69 if let Some(harvest_year_search) = search_parameters.harvest_year {
70 query = query.filter(harvest_year.eq(harvest_year_search));
71 }
72
73 if search_parameters.name.is_some() {
74 query = query
75 .filter(
76 similarity(name, search_query)
77 .gt(0.1)
78 .or(similarity(array_to_string(common_name_de, " "), search_query).gt(0.1))
79 .or(similarity(array_to_string(common_name_en, " "), search_query).gt(0.1))
80 .or(similarity(unique_name, search_query).gt(0.1)),
81 )
82 .order(sql::<Float>("1").desc());
85 } else {
86 query = query.order((harvest_year.asc(), use_by.asc()));
88 }
89
90 let include_archived = search_parameters
91 .archived
92 .unwrap_or(IncludeArchivedSeeds::NotArchived);
93
94 if include_archived == IncludeArchivedSeeds::Archived {
96 query = query.filter(seeds::archived_at.is_not_null());
97 } else if include_archived == IncludeArchivedSeeds::NotArchived {
98 query = query.filter(seeds::archived_at.is_null());
99 }
100
101 query = query.filter(created_by.eq(user_id));
103
104 let query = query
105 .paginate(page_parameters.page)
106 .per_page(page_parameters.per_page);
107 debug!("{}", debug_query::<Pg, _>(&query));
108 query
109 .load_page::<(f32, Self)>(conn)
110 .await
111 .map(Page::from_entity)
112 }
113
114 pub async fn find_by_id(
119 id: i32,
120 user_id: Uuid,
121 conn: &mut AsyncPgConnection,
122 ) -> QueryResult<SeedDto> {
123 let mut query = seeds::table.select(all_columns).into_boxed();
124
125 query = query.filter(created_by.eq(user_id).and(seeds::id.eq(id)));
127
128 debug!("{}", debug_query::<Pg, _>(&query));
129 query.first::<Self>(conn).await.map(Into::into)
130 }
131
132 pub async fn create(
137 new_seed: NewSeedDto,
138 user_id: Uuid,
139 conn: &mut AsyncPgConnection,
140 ) -> QueryResult<SeedDto> {
141 let new_seed = NewSeed::from((new_seed, user_id));
142 let query = diesel::insert_into(seeds::table).values(&new_seed);
143 debug!("{}", debug_query::<Pg, _>(&query));
144 query.get_result::<Self>(conn).await.map(Into::into)
145 }
146
147 pub async fn edit(
152 id: i32,
153 user_id: Uuid,
154 new_seed: NewSeedDto,
155 conn: &mut AsyncPgConnection,
156 ) -> QueryResult<SeedDto> {
157 let new_seed = NewSeed::from((new_seed, user_id));
158 let query_result = diesel::update(seeds::table.filter(seeds::id.eq(id)))
159 .set((
160 seeds::name.eq(new_seed.name),
161 seeds::harvest_year.eq(new_seed.harvest_year),
162 seeds::plant_id.eq(new_seed.plant_id),
163 seeds::use_by.eq(new_seed.use_by),
164 seeds::origin.eq(new_seed.origin),
165 seeds::taste.eq(new_seed.taste),
166 seeds::yield_.eq(new_seed.yield_),
167 seeds::generation.eq(new_seed.generation),
168 seeds::price.eq(new_seed.price),
169 seeds::notes.eq(new_seed.notes),
170 seeds::quantity.eq(new_seed.quantity),
171 seeds::quality.eq(new_seed.quality),
172 ))
173 .get_result::<Self>(conn)
174 .await;
175 query_result.map(Into::into)
176 }
177
178 pub async fn delete_by_id(
183 id: i32,
184 user_id: Uuid,
185 conn: &mut AsyncPgConnection,
186 ) -> QueryResult<usize> {
187 let source = seeds::table.filter(created_by.eq(user_id).and(seeds::id.eq(id)));
189
190 let query = diesel::delete(source);
191 debug!("{}", debug_query::<Pg, _>(&query));
192 query.execute(conn).await
193 }
194
195 pub async fn archive(
200 id: i32,
201 archived_at: Option<NaiveDateTime>,
202 user_id: Uuid,
203 conn: &mut AsyncPgConnection,
204 ) -> QueryResult<SeedDto> {
205 let source = seeds::table.filter(created_by.eq(user_id).and(seeds::id.eq(id)));
206
207 let query_result = diesel::update(source)
208 .set(seeds::archived_at.eq(archived_at))
209 .get_result::<Self>(conn)
210 .await;
211 query_result.map(Into::into)
212 }
213}