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.map(i64::from) {
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
39 if search_parameters.only_non_deleted.is_some() {
40 query = query.filter(layers::marked_deleted.is_null());
41 }
42
43 query = query.order((layers::order_index, layers::marked_deleted.desc()));
44
45 debug!("{}", debug_query::<Pg, _>(&query));
46 Ok(query
47 .load::<Self>(conn)
48 .await?
49 .into_iter()
50 .map(Into::into)
51 .collect())
52 }
53
54 pub async fn find_by_id(id: Uuid, conn: &mut AsyncPgConnection) -> QueryResult<Self> {
59 let query = layers::table.find(id);
60 debug!("{}", debug_query::<Pg, _>(&query));
61 query.first::<Self>(conn).await
62 }
63
64 async fn defer_unique_order_index_constraint(
70 transaction: &mut AsyncPgConnection,
71 ) -> QueryResult<()> {
72 sql_query("SET CONSTRAINTS layers_map_id_order_index_unique DEFERRED")
73 .execute(transaction)
74 .await?;
75 Ok(())
76 }
77
78 async fn shift_order_indices_by(
85 map_id: i64,
86 order_index: i32,
87 increment: bool,
88 transaction: &mut AsyncPgConnection,
89 ) -> QueryResult<()> {
90 let layer_ids = Self::find(
91 LayerSearchParameters {
92 is_alternative: None,
93 map_id: Some(i32::try_from(map_id).unwrap_or(-1)),
94 type_: None,
95 only_non_deleted: Some(()),
96 },
97 transaction,
98 )
99 .await?;
100 let updates = layer_ids
101 .into_iter()
102 .filter(|l| l.order_index >= order_index)
103 .map(|l| UpdateLayerOrderIndex {
104 id: l.id,
105 order_index: l.order_index + if increment { 1 } else { -1 },
106 })
107 .collect();
108 let futures = Self::do_order_update(updates, transaction);
109 try_join_all(futures).await?;
110 Ok(())
111 }
112
113 pub async fn create(
118 map_id: i64,
119 new_layer: LayerDto,
120 conn: &mut AsyncPgConnection,
121 ) -> QueryResult<LayerDto> {
122 let new_order_index = new_layer.order_index;
123 let new_layer = Self::from((map_id, new_layer));
124 let query = diesel::insert_into(layers::table).values(&new_layer);
125
126 let created_layer = conn
127 .transaction(|transaction| {
128 Box::pin(async move {
129 Self::shift_order_indices_by(map_id, new_order_index, true, transaction)
130 .await?;
131 debug!("{}", debug_query::<Pg, _>(&query));
132 let layer_dto = query.get_result::<Self>(transaction).await?.into();
133 Ok::<LayerDto, diesel::result::Error>(layer_dto)
134 })
135 })
136 .await?;
137 Ok(created_layer)
138 }
139
140 pub async fn reorder(new_order: Vec<Uuid>, conn: &mut AsyncPgConnection) -> QueryResult<()> {
146 let order_updates: Vec<UpdateLayerOrderIndex> = new_order
147 .into_iter()
148 .zip(0..)
149 .map(|(id, order_index)| UpdateLayerOrderIndex { id, order_index })
150 .collect();
151
152 conn.transaction(|transaction| {
153 Box::pin(async move {
154 Self::defer_unique_order_index_constraint(transaction).await?;
158 let futures = Self::do_order_update(order_updates, transaction);
159 try_join_all(futures).await?;
160 Ok::<(), diesel::result::Error>(())
161 })
162 })
163 .await?;
164
165 Ok(())
166 }
167
168 fn do_order_update(
170 updates: Vec<UpdateLayerOrderIndex>,
171 conn: &mut AsyncPgConnection,
172 ) -> Vec<impl Future<Output = QueryResult<usize>>> {
173 updates
174 .into_iter()
175 .map(|update| {
176 diesel::update(layers::table.find(update.id))
177 .set(update)
178 .execute(conn)
179 })
180 .collect()
181 }
182
183 pub async fn rename(dto: LayerRenameDto, conn: &mut AsyncPgConnection) -> QueryResult<()> {
188 let update: UpdateLayerName = dto.into();
189 let query = diesel::update(layers::table.find(update.id)).set(&update);
190 debug!("{}", debug_query::<Pg, _>(&query));
191 query.execute(conn).await?;
192 Ok(())
193 }
194
195 async fn set_marked_deleted(
200 drawing_layer_id: Uuid,
201 marked_deleted: bool,
202 conn: &mut AsyncPgConnection,
203 ) -> QueryResult<Self> {
204 let marked_deleted_timestamp = marked_deleted.then(|| Utc::now().naive_utc());
205 diesel::update(layers::table.find(drawing_layer_id))
206 .set(UpdateLayerMarkedDeleted {
207 id: drawing_layer_id,
208 marked_deleted: marked_deleted_timestamp,
209 })
210 .get_result::<Self>(conn)
211 .await
212 }
213
214 pub async fn delete(
220 map_id: i64,
221 layer_id: Uuid,
222 conn: &mut AsyncPgConnection,
223 ) -> QueryResult<()> {
224 conn.transaction(|transaction| {
225 Box::pin(async move {
226 let layer = Self::set_marked_deleted(layer_id, true, transaction).await?;
227 Self::shift_order_indices_by(map_id, layer.order_index, false, transaction).await?;
228 Ok(())
229 })
230 })
231 .await
232 }
233
234 pub async fn restore(
241 map_id: i64,
242 layer_id: Uuid,
243 conn: &mut AsyncPgConnection,
244 ) -> QueryResult<()> {
245 conn.transaction(|transaction| {
246 Box::pin(async move {
247 Self::defer_unique_order_index_constraint(transaction).await?;
248 let layer = Self::find_by_id(layer_id, transaction).await?;
249 Self::shift_order_indices_by(map_id, layer.order_index, true, transaction).await?;
250 _ = Self::set_marked_deleted(layer_id, false, transaction).await?;
251 Ok(())
252 })
253 })
254 .await
255 }
256}