backend/model/entity/
map_impl.rs1use chrono::{Datelike, Months, NaiveDate, NaiveDateTime, Utc};
4use diesel::dsl::{exists, sql};
5use diesel::pg::Pg;
6use diesel::sql_types::Float;
7use diesel::{
8 debug_query, select, BoolExpressionMethods, ExpressionMethods, PgTextExpressionMethods,
9 QueryDsl, QueryResult,
10};
11use diesel_async::{AsyncPgConnection, RunQueryDsl};
12use log::debug;
13use uuid::Uuid;
14
15use crate::db::function::{similarity, PgTrgmExpressionMethods};
16use crate::db::pagination::Paginate;
17use crate::model::dto::{
18 MapSearchParameters, Page, PageParameters, UpdateMapDto, UpdateMapGeometryDto,
19};
20use crate::model::entity::{UpdateMap, UpdateMapGeometry};
21use crate::{
22 model::dto::{MapDto, NewMapDto},
23 schema::maps::{self, all_columns, created_by, deletion_date, is_inactive, name, privacy},
24};
25
26use super::{Map, NewMap};
27
28impl Map {
29 pub async fn find(
40 search_parameters: MapSearchParameters,
41 page_parameters: PageParameters,
42 conn: &mut AsyncPgConnection,
43 ) -> QueryResult<Page<MapDto>> {
44 let mut query = maps::table
45 .select((
46 similarity(name, search_parameters.name.clone().unwrap_or_default()),
47 all_columns,
48 ))
49 .into_boxed();
50
51 if let Some(search_query) = &search_parameters.name {
52 if !search_query.is_empty() {
53 query = query.filter(
54 name.fuzzy(search_query)
55 .or(name.ilike(format!("%{search_query}%"))),
56 );
57 }
58 }
59 if let Some(is_inactive_search) = search_parameters.is_inactive {
60 query = query.filter(is_inactive.eq(is_inactive_search));
61 }
62 if let Some(privacy_search) = search_parameters.privacy {
63 query = query.filter(privacy.eq(privacy_search));
64 }
65 if let Some(created_by_search) = search_parameters.created_by {
66 query = query.filter(created_by.eq(created_by_search));
67 }
68
69 let query = query
70 .filter(deletion_date.is_null())
71 .order(sql::<Float>("1").desc())
72 .paginate(page_parameters.page)
73 .per_page(page_parameters.per_page);
74 debug!("{}", debug_query::<Pg, _>(&query));
75 query
76 .load_page::<(f32, Self)>(conn)
77 .await
78 .map(Page::from_entity)
79 }
80
81 pub async fn find_by_id(id: i32, conn: &mut AsyncPgConnection) -> QueryResult<MapDto> {
86 let query = maps::table.find(id).filter(deletion_date.is_null());
87 debug!("{}", debug_query::<Pg, _>(&query));
88 query.first::<Self>(conn).await.map(Into::into)
89 }
90
91 pub async fn is_name_taken(map_name: &str, conn: &mut AsyncPgConnection) -> QueryResult<bool> {
96 let query = select(exists(maps::table.filter(name.eq(map_name))));
97 debug!("{}", debug_query::<Pg, _>(&query));
98 query.get_result(conn).await
99 }
100
101 pub async fn create(
106 new_map: NewMapDto,
107 user_id: Uuid,
108 conn: &mut AsyncPgConnection,
109 ) -> QueryResult<MapDto> {
110 let new_map = NewMap::from((new_map, user_id));
111 let query = diesel::insert_into(maps::table).values(&new_map);
112 debug!("{}", debug_query::<Pg, _>(&query));
113 query.get_result::<Self>(conn).await.map(Into::into)
114 }
115
116 pub async fn update(
121 map_update: UpdateMapDto,
122 id: i32,
123 conn: &mut AsyncPgConnection,
124 ) -> QueryResult<MapDto> {
125 let map_update = UpdateMap::from(map_update);
126 let query = diesel::update(maps::table.find(id)).set(&map_update);
127 debug!("{}", debug_query::<Pg, _>(&query));
128 query.get_result::<Self>(conn).await.map(Into::into)
129 }
130
131 pub async fn mark_for_deletion(id: i32, conn: &mut AsyncPgConnection) -> QueryResult<MapDto> {
136 let now = Utc::now().naive_utc();
137 let in_one_month = now + Months::new(1);
138 let in_one_month_as_naive_date = NaiveDate::from_ymd_opt(
140 in_one_month.year(),
141 in_one_month.month(),
142 in_one_month.day(),
143 );
144
145 let map = Self::find_by_id(id, conn).await?;
146
147 let query = diesel::update(maps::table.find(id)).set((
148 deletion_date.eq(in_one_month_as_naive_date),
149 name.eq(format!("{} __DELETED {}", map.name, now)),
151 ));
152 debug!("{}", debug_query::<Pg, _>(&query));
153 query.get_result::<Self>(conn).await.map(Into::into)
154 }
155
156 pub async fn update_geometry(
161 map_update_bounds: UpdateMapGeometryDto,
162 id: i32,
163 conn: &mut AsyncPgConnection,
164 ) -> QueryResult<MapDto> {
165 let map_update = UpdateMapGeometry::from(map_update_bounds);
166 let query = diesel::update(maps::table.find(id)).set(&map_update);
167 debug!("{}", debug_query::<Pg, _>(&query));
168 query.get_result::<Self>(conn).await.map(Into::into)
169 }
170
171 pub async fn update_modified_metadata(
176 id: i32,
177 user_id: Uuid,
178 time: NaiveDateTime,
179 conn: &mut AsyncPgConnection,
180 ) -> QueryResult<()> {
181 diesel::update(maps::table.find(id))
182 .set((maps::modified_at.eq(time), maps::modified_by.eq(user_id)))
183 .execute(conn)
184 .await?;
185 Ok(())
186 }
187}