backend/model/entity/
layers_impl.rs1use chrono::Utc;
4use diesel::pg::Pg;
5use diesel::{debug_query, sql_query, ExpressionMethods, QueryDsl, QueryResult};
6use diesel_async::{AsyncConnection, AsyncPgConnection, RunQueryDsl};
7use futures::future::try_join_all;
8use futures::Future;
9use log::debug;
10use uuid::Uuid;
11
12use crate::{
13 model::{
14 dto::layers::{LayerDto, LayerRenameDto, LayerSearchParameters},
15 entity::layers::{Layer, UpdateLayerMarkedDeleted, UpdateLayerName, UpdateLayerOrderIndex},
16 },
17 schema::layers,
18};
19
20impl Layer {
21 pub async fn find(
27 search_parameters: LayerSearchParameters,
28 conn: &mut AsyncPgConnection,
29 ) -> QueryResult<Vec<LayerDto>> {
30 let mut query = layers::table.select(layers::all_columns).into_boxed();
31
32 if let Some(map_id_search) = search_parameters.map_id {
33 query = query.filter(layers::map_id.eq(map_id_search));
34 }
35 if let Some(type_search) = search_parameters.type_ {
36 query = query.filter(layers::type_.eq(type_search));
37 }
38 if let Some(is_alternative_search) = search_parameters.is_alternative {
39 query = query.filter(layers::is_alternative.eq(is_alternative_search));
40 }
41
42 if search_parameters.only_non_deleted.is_some() {
43 query = query.filter(layers::marked_deleted.is_null());
44 }
45
46 query = query.order((layers::order_index, layers::marked_deleted.desc()));
47
48 debug!("{}", debug_query::<Pg, _>(&query));
49 Ok(query
50 .load::<Self>(conn)
51 .await?
52 .into_iter()
53 .map(Into::into)
54 .collect())
55 }
56
57 pub async fn find_by_id(id: Uuid, conn: &mut AsyncPgConnection) -> QueryResult<Self> {
62 let query = layers::table.find(id);
63 debug!("{}", debug_query::<Pg, _>(&query));
64 query.first::<Self>(conn).await
65 }
66
67 async fn defer_unique_order_index_constraint(
73 transaction: &mut AsyncPgConnection,
74 ) -> QueryResult<()> {
75 sql_query("SET CONSTRAINTS layers_map_id_order_index_unique DEFERRED")
76 .execute(transaction)
77 .await?;
78 Ok(())
79 }
80
81 async fn shift_order_indices_by(
88 map_id: i32,
89 order_index: i32,
90 increment: bool,
91 transaction: &mut AsyncPgConnection,
92 ) -> QueryResult<()> {
93 let layer_ids = Self::find(
94 LayerSearchParameters {
95 is_alternative: None,
96 map_id: Some(map_id),
97 type_: None,
98 only_non_deleted: Some(()),
99 },
100 transaction,
101 )
102 .await?;
103 let updates = layer_ids
104 .into_iter()
105 .filter(|l| l.order_index >= order_index)
106 .map(|l| UpdateLayerOrderIndex {
107 id: l.id,
108 order_index: l.order_index + if increment { 1 } else { -1 },
109 })
110 .collect();
111 let futures = Self::do_order_update(updates, transaction);
112 try_join_all(futures).await?;
113 Ok(())
114 }
115
116 pub async fn create(
121 map_id: i32,
122 new_layer: LayerDto,
123 conn: &mut AsyncPgConnection,
124 ) -> QueryResult<LayerDto> {
125 let new_order_index = new_layer.order_index;
126 let new_layer = Self::from((map_id, new_layer));
127 let query = diesel::insert_into(layers::table).values(&new_layer);
128
129 let created_layer = conn
130 .transaction(|transaction| {
131 Box::pin(async move {
132 Self::shift_order_indices_by(map_id, new_order_index, true, transaction)
133 .await?;
134 debug!("{}", debug_query::<Pg, _>(&query));
135 let layer_dto = query.get_result::<Self>(transaction).await?.into();
136 Ok::<LayerDto, diesel::result::Error>(layer_dto)
137 })
138 })
139 .await?;
140 Ok(created_layer)
141 }
142
143 pub async fn reorder(new_order: Vec<Uuid>, conn: &mut AsyncPgConnection) -> QueryResult<()> {
149 let order_updates: Vec<UpdateLayerOrderIndex> = new_order
150 .into_iter()
151 .zip(0..)
152 .map(|(id, order_index)| UpdateLayerOrderIndex { id, order_index })
153 .collect();
154
155 conn.transaction(|transaction| {
156 Box::pin(async move {
157 Self::defer_unique_order_index_constraint(transaction).await?;
161 let futures = Self::do_order_update(order_updates, transaction);
162 try_join_all(futures).await?;
163 Ok::<(), diesel::result::Error>(())
164 })
165 })
166 .await?;
167
168 Ok(())
169 }
170
171 fn do_order_update(
173 updates: Vec<UpdateLayerOrderIndex>,
174 conn: &mut AsyncPgConnection,
175 ) -> Vec<impl Future<Output = QueryResult<usize>>> {
176 updates
177 .into_iter()
178 .map(|update| {
179 diesel::update(layers::table.find(update.id))
180 .set(update)
181 .execute(conn)
182 })
183 .collect()
184 }
185
186 pub async fn rename(dto: LayerRenameDto, conn: &mut AsyncPgConnection) -> QueryResult<()> {
191 let update: UpdateLayerName = dto.into();
192 let query = diesel::update(layers::table.find(update.id)).set(&update);
193 debug!("{}", debug_query::<Pg, _>(&query));
194 query.execute(conn).await?;
195 Ok(())
196 }
197
198 async fn set_marked_deleted(
203 drawing_layer_id: Uuid,
204 marked_deleted: bool,
205 conn: &mut AsyncPgConnection,
206 ) -> QueryResult<Self> {
207 let marked_deleted_timestamp = marked_deleted.then(|| Utc::now().naive_utc());
208 diesel::update(layers::table.find(drawing_layer_id))
209 .set(UpdateLayerMarkedDeleted {
210 id: drawing_layer_id,
211 marked_deleted: marked_deleted_timestamp,
212 })
213 .get_result::<Self>(conn)
214 .await
215 }
216
217 pub async fn delete(
223 map_id: i32,
224 layer_id: Uuid,
225 conn: &mut AsyncPgConnection,
226 ) -> QueryResult<()> {
227 conn.transaction(|transaction| {
228 Box::pin(async move {
229 let layer = Self::set_marked_deleted(layer_id, true, transaction).await?;
230 Self::shift_order_indices_by(map_id, layer.order_index, false, transaction).await?;
231 Ok(())
232 })
233 })
234 .await
235 }
236
237 pub async fn restore(
244 map_id: i32,
245 layer_id: Uuid,
246 conn: &mut AsyncPgConnection,
247 ) -> QueryResult<()> {
248 conn.transaction(|transaction| {
249 Box::pin(async move {
250 Self::defer_unique_order_index_constraint(transaction).await?;
251 let layer = Self::find_by_id(layer_id, transaction).await?;
252 Self::shift_order_indices_by(map_id, layer.order_index, true, transaction).await?;
253 _ = Self::set_marked_deleted(layer_id, false, transaction).await?;
254 Ok(())
255 })
256 })
257 .await
258 }
259}