1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
//! Contains the implementation of [`Drawing`].

use diesel::pg::Pg;
use diesel::query_dsl::methods::FilterDsl;
use diesel::{debug_query, ExpressionMethods, QueryDsl, QueryResult};
use diesel_async::{AsyncConnection, AsyncPgConnection, RunQueryDsl};
use futures_util::Future;
use log::debug;
use uuid::Uuid;

use crate::model::entity::drawings::{Drawing, UpdateDrawing};
use crate::schema::{drawings, layers};

impl Drawing {
    /// Get all drawings assosicated with one map.
    ///
    /// # Errors
    /// * Unknown, diesel doesn't say why it might error.
    pub async fn find(map_id: i32, conn: &mut AsyncPgConnection) -> QueryResult<Vec<Self>> {
        let query = FilterDsl::filter(
            drawings::table.left_join(layers::table),
            layers::map_id.eq(map_id),
        )
        .select(drawings::all_columns)
        .into_boxed();

        debug!("{}", debug_query::<Pg, _>(&query));

        query.load::<Self>(conn).await
    }

    /// Get all drawings saved in one layer.
    ///
    /// # Errors
    /// * Unknown, diesel doesn't say why it might error.
    pub async fn find_in_layer(
        layer_id: Uuid,
        conn: &mut AsyncPgConnection,
    ) -> QueryResult<Vec<Self>> {
        let query = FilterDsl::filter(drawings::table, drawings::layer_id.eq(layer_id));

        debug!("{}", debug_query::<Pg, _>(&query));

        query.load::<Self>(conn).await
    }

    /// Save new drawings into the database.
    ///
    /// # Errors
    /// * Unknown, diesel doesn't say why it might error.
    pub async fn create(
        drawings: Vec<Self>,
        conn: &mut AsyncPgConnection,
    ) -> QueryResult<Vec<Self>> {
        let query = diesel::insert_into(drawings::table).values(&drawings);

        debug!("{}", debug_query::<Pg, _>(&query));

        query.get_results::<Self>(conn).await
    }

    /// Replace existing drawings in the database.
    ///
    /// # Errors
    /// * Unknown, diesel doesn't say why it might error.
    pub async fn update(
        drawing_updates: Vec<UpdateDrawing>,
        conn: &mut AsyncPgConnection,
    ) -> QueryResult<Vec<Self>> {
        conn.transaction(|transaction| {
            Box::pin(async {
                let ids: Vec<Uuid> = drawing_updates.iter().map(|u| u.id).collect();

                let futures = Self::do_update(drawing_updates, transaction);

                futures_util::future::try_join_all(futures).await?;

                let results = FilterDsl::filter(
                    drawings::table.select(drawings::all_columns),
                    drawings::id.eq_any(ids),
                )
                .load::<Self>(transaction)
                .await?;

                Ok(results) as QueryResult<Vec<Self>>
            })
        })
        .await
    }

    /// Helper that performs the actual update of the drawings.
    fn do_update(
        updates: Vec<UpdateDrawing>,
        conn: &mut AsyncPgConnection,
    ) -> Vec<impl Future<Output = QueryResult<Self>>> {
        let mut futures = Vec::with_capacity(updates.len());

        for update in updates {
            let updated_drawings = diesel::update(drawings::table.find(update.id))
                .set(update)
                .get_result::<Self>(conn);

            futures.push(updated_drawings);
        }

        futures
    }

    /// Delete the drawings from the database.
    ///
    /// # Errors
    /// * Unknown, diesel doesn't say why it might error.
    pub async fn delete_by_ids(ids: Vec<Uuid>, conn: &mut AsyncPgConnection) -> QueryResult<usize> {
        let query = diesel::delete(FilterDsl::filter(drawings::table, drawings::id.eq_any(ids)));
        debug!("{}", debug_query::<Pg, _>(&query));
        query.execute(conn).await
    }
}