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 mut search_query = &String::new();
55 if let Some(name_search) = &search_parameters.name {
56 search_query = name_search;
57 }
58
59 let mut query = seeds::table
60 .inner_join(plants::table)
61 .select((
62 greatest4(
63 similarity(name, search_query),
64 similarity(unique_name, search_query),
65 similarity(array_to_string(common_name_de, " "), search_query),
66 similarity(array_to_string(common_name_en, " "), search_query),
67 ),
68 all_columns,
69 ))
70 .into_boxed();
71
72 if let Some(harvest_year_search) = search_parameters.harvest_year {
73 query = query.filter(harvest_year.eq(harvest_year_search));
74 }
75
76 if search_parameters.name.is_some() {
77 query = query
78 .filter(
79 similarity(name, search_query)
80 .gt(0.1)
81 .or(similarity(array_to_string(common_name_de, " "), search_query).gt(0.1))
82 .or(similarity(array_to_string(common_name_en, " "), search_query).gt(0.1))
83 .or(similarity(unique_name, search_query).gt(0.1)),
84 )
85 .order(sql::<Float>("1").desc());
88 } else {
89 query = query.order((harvest_year.asc(), use_by.asc()));
91 }
92
93 let mut include_archived = IncludeArchivedSeeds::NotArchived;
94 if let Some(include_archived_) = search_parameters.archived {
95 include_archived = include_archived_;
96 }
97
98 if include_archived == IncludeArchivedSeeds::Archived {
100 query = query.filter(seeds::archived_at.is_not_null());
101 } else if include_archived == IncludeArchivedSeeds::NotArchived {
102 query = query.filter(seeds::archived_at.is_null());
103 }
104
105 query = query.filter(created_by.eq(user_id));
107
108 let query = query
109 .paginate(page_parameters.page)
110 .per_page(page_parameters.per_page);
111 debug!("{}", debug_query::<Pg, _>(&query));
112 query
113 .load_page::<(f32, Self)>(conn)
114 .await
115 .map(Page::from_entity)
116 }
117
118 pub async fn find_by_id(
123 id: i32,
124 user_id: Uuid,
125 conn: &mut AsyncPgConnection,
126 ) -> QueryResult<SeedDto> {
127 let mut query = seeds::table.select(all_columns).into_boxed();
128
129 query = query.filter(created_by.eq(user_id).and(seeds::id.eq(id)));
131
132 debug!("{}", debug_query::<Pg, _>(&query));
133 query.first::<Self>(conn).await.map(Into::into)
134 }
135
136 pub async fn create(
141 new_seed: NewSeedDto,
142 user_id: Uuid,
143 conn: &mut AsyncPgConnection,
144 ) -> QueryResult<SeedDto> {
145 let new_seed = NewSeed::from((new_seed, user_id));
146 let query = diesel::insert_into(seeds::table).values(&new_seed);
147 debug!("{}", debug_query::<Pg, _>(&query));
148 query.get_result::<Self>(conn).await.map(Into::into)
149 }
150
151 pub async fn edit(
156 id: i32,
157 user_id: Uuid,
158 new_seed: NewSeedDto,
159 conn: &mut AsyncPgConnection,
160 ) -> QueryResult<SeedDto> {
161 let new_seed = NewSeed::from((new_seed, user_id));
162 let query_result = diesel::update(seeds::table.filter(seeds::id.eq(id)))
163 .set((
164 seeds::name.eq(new_seed.name),
165 seeds::harvest_year.eq(new_seed.harvest_year),
166 seeds::plant_id.eq(new_seed.plant_id),
167 seeds::use_by.eq(new_seed.use_by),
168 seeds::origin.eq(new_seed.origin),
169 seeds::taste.eq(new_seed.taste),
170 seeds::yield_.eq(new_seed.yield_),
171 seeds::generation.eq(new_seed.generation),
172 seeds::price.eq(new_seed.price),
173 seeds::notes.eq(new_seed.notes),
174 seeds::quantity.eq(new_seed.quantity),
175 seeds::quality.eq(new_seed.quality),
176 ))
177 .get_result::<Self>(conn)
178 .await;
179 query_result.map(Into::into)
180 }
181
182 pub async fn delete_by_id(
187 id: i32,
188 user_id: Uuid,
189 conn: &mut AsyncPgConnection,
190 ) -> QueryResult<usize> {
191 let source = seeds::table.filter(created_by.eq(user_id).and(seeds::id.eq(id)));
193
194 let query = diesel::delete(source);
195 debug!("{}", debug_query::<Pg, _>(&query));
196 query.execute(conn).await
197 }
198
199 pub async fn archive(
204 id: i32,
205 archived_at: Option<NaiveDateTime>,
206 user_id: Uuid,
207 conn: &mut AsyncPgConnection,
208 ) -> QueryResult<SeedDto> {
209 let source = seeds::table.filter(created_by.eq(user_id).and(seeds::id.eq(id)));
210
211 let query_result = diesel::update(source)
212 .set(seeds::archived_at.eq(archived_at))
213 .get_result::<Self>(conn)
214 .await;
215 query_result.map(Into::into)
216 }
217}