backend/model/entity/
drawings_impl.rs

1//! Contains the implementation of [`Drawing`].
2
3use crate::model::dto::drawings_impl::{DrawingWithProps, UpdateDrawingWithProps};
4use crate::model::entity::drawings::Drawing;
5
6use crate::schema::{drawings, layers};
7
8use crate::model::entity::drawing_properties_impl::{insert_props, load_props_for, update_props};
9use diesel::pg::Pg;
10use diesel::query_dsl::methods::FilterDsl;
11use diesel::{debug_query, ExpressionMethods, QueryDsl, QueryResult};
12use diesel_async::{AsyncConnection, AsyncPgConnection, RunQueryDsl};
13use log::debug;
14use uuid::Uuid;
15
16impl Drawing {
17    /// Get all drawings assosicated with one map.
18    ///
19    /// # Errors
20    /// * Unknown, diesel doesn't say why it might error.
21    pub async fn find(
22        map_id: i64,
23        conn: &mut AsyncPgConnection,
24    ) -> QueryResult<Vec<DrawingWithProps>> {
25        let query = FilterDsl::filter(
26            drawings::table.left_join(layers::table),
27            layers::map_id.eq(map_id),
28        )
29        .select(drawings::all_columns)
30        .into_boxed::<Pg>();
31
32        debug!("{}", debug_query::<Pg, _>(&query));
33
34        let base_rows: Vec<Self> = query.load::<Self>(conn).await?;
35
36        let mut out = Vec::with_capacity(base_rows.len());
37        for drawing in base_rows {
38            let variants = load_props_for(&drawing, conn).await?;
39
40            out.push(DrawingWithProps { drawing, variants });
41        }
42
43        Ok(out)
44    }
45
46    /// Get all drawings saved in one layer.
47    ///
48    /// # Errors
49    /// * Unknown, diesel doesn't say why it might error.
50    pub async fn find_in_layer(
51        layer_id: Uuid,
52        conn: &mut AsyncPgConnection,
53    ) -> QueryResult<Vec<DrawingWithProps>> {
54        let base_rows: Vec<Self> =
55            FilterDsl::filter(drawings::table, drawings::layer_id.eq(layer_id))
56                .load::<Self>(conn)
57                .await?;
58
59        // 2. Load props according to shape_type
60        let mut out = Vec::with_capacity(base_rows.len());
61
62        for drawing in base_rows {
63            let variants = load_props_for(&drawing, conn).await?;
64            out.push(DrawingWithProps { drawing, variants });
65        }
66
67        Ok(out)
68    }
69
70    /// Save new drawings into the database.
71    ///
72    /// # Errors
73    /// * Unknown, diesel doesn't say why it might error.
74    pub async fn create(
75        drawings: Vec<DrawingWithProps>,
76        conn: &mut AsyncPgConnection,
77    ) -> QueryResult<Vec<DrawingWithProps>> {
78        conn.transaction(|tx| {
79            Box::pin(async move {
80                let only_drawings: Vec<Self> =
81                    drawings.iter().map(|dwp| dwp.drawing.clone()).collect();
82
83                let query = diesel::insert_into(drawings::table).values(&only_drawings);
84
85                debug!("{}", debug_query::<Pg, _>(&query));
86
87                let inserted: Vec<Self> = query.get_results(tx).await?;
88
89                for dwp in &drawings {
90                    insert_props(tx, &dwp.variants).await?;
91                }
92
93                let result: Vec<DrawingWithProps> = inserted
94                    .into_iter()
95                    .zip(drawings.into_iter().map(|dwp| dwp.variants))
96                    .map(|(drawing, props)| DrawingWithProps {
97                        drawing,
98                        variants: props,
99                    })
100                    .collect();
101
102                Ok(result)
103            })
104        })
105        .await
106    }
107
108    /// Replace existing drawings in the database.
109    ///
110    /// # Errors
111    /// * Unknown, diesel doesn't say why it might error.
112    pub async fn update(
113        drawing_updates: Vec<UpdateDrawingWithProps>,
114        conn: &mut AsyncPgConnection,
115    ) -> QueryResult<Vec<DrawingWithProps>> {
116        conn.transaction(|tx| {
117            let drawing_updates = drawing_updates;
118            Box::pin(async move {
119                let ids: Vec<Uuid> = drawing_updates
120                    .iter()
121                    .map(|u| u.update_drawing.id)
122                    .collect();
123
124                for u in drawing_updates {
125                    diesel::update(drawings::table.find(u.update_drawing.id))
126                        .set(&u.update_drawing)
127                        .execute(tx)
128                        .await?;
129                    if let Some(props) = u.properties {
130                        update_props(tx, props).await?;
131                    }
132                }
133
134                let query = FilterDsl::filter(
135                    drawings::table.select(drawings::all_columns),
136                    drawings::id.eq_any(&ids),
137                );
138
139                debug!("{}", debug_query::<Pg, _>(&query));
140
141                let base_rows: Vec<Self> = query.load::<Self>(tx).await?;
142
143                let mut out = Vec::with_capacity(base_rows.len());
144                for drawing in base_rows {
145                    let props = load_props_for(&drawing, tx).await?;
146                    out.push(DrawingWithProps {
147                        drawing,
148                        variants: props,
149                    });
150                }
151
152                Ok(out) as QueryResult<Vec<DrawingWithProps>>
153            })
154        })
155        .await
156    }
157
158    /// Delete the drawings from the database.
159    ///
160    /// # Errors
161    /// * Unknown, diesel doesn't say why it might error.
162    pub async fn delete_by_ids(ids: Vec<Uuid>, conn: &mut AsyncPgConnection) -> QueryResult<usize> {
163        let query = diesel::delete(FilterDsl::filter(drawings::table, drawings::id.eq_any(ids)));
164        debug!("{}", debug_query::<Pg, _>(&query));
165        query.execute(conn).await
166    }
167}