pg_worm/query/
delete.rs

1use std::{
2    future::{Future, IntoFuture},
3    pin::Pin,
4};
5
6use tokio_postgres::types::ToSql;
7
8use super::{Executable, PushChunk, ToQuery, Where};
9
10/// A struct for building `DELETE` queries.
11pub struct Delete<'a> {
12    table: &'static str,
13    where_: Where<'a>,
14}
15
16impl<'a> ToQuery<'a, u64> for Delete<'a> {}
17
18impl<'a> Delete<'a> {
19    /// Start building a new `DELETE` query.
20    pub fn new(table: &'static str) -> Delete<'a> {
21        Delete {
22            table,
23            where_: Where::Empty,
24        }
25    }
26
27    /// Add a `WHERE` clause to your `DELETE` query.
28    ///
29    /// If called multiple times, the conditions are joined using `AND`.
30    pub fn where_(mut self, where_: Where<'a>) -> Delete<'a> {
31        self.where_ = self.where_.and(where_);
32
33        self
34    }
35
36    /// Add a raw `WHERE` clause to your query.
37    ///
38    /// You can reference the `params` by using the `?` placeholder in your statement.
39    ///
40    /// Note: you need to pass the exact types Postgres is expecting.
41    /// Failure to do so will result in (sometimes confusing) runtime errors.
42    ///
43    /// Otherwise this behaves exactly like `where_`.
44    ///
45    /// # Example
46    ///
47    /// ```ignore
48    /// Book::select()
49    ///     .where_(Book::id.neq(&3))
50    ///     .where_raw("complex_function(book.title, ?, ?)", vec![&true, &"Foobar"])
51    ///     .await?;
52    /// ```
53    pub fn where_raw(
54        self,
55        statement: impl Into<String>,
56        params: Vec<&'a (dyn ToSql + Sync)>,
57    ) -> Delete<'a> {
58        let where_ = Where::new(statement.into(), params);
59
60        self.where_(where_)
61    }
62}
63
64impl<'a> PushChunk<'a> for Delete<'a> {
65    fn push_to_buffer<T>(&mut self, buffer: &mut super::Query<'a, T>) {
66        buffer.0.push_str("DELETE FROM ");
67        buffer.0.push_str(self.table);
68
69        if !self.where_.is_empty() {
70            buffer.0.push_str(" WHERE ");
71            self.where_.push_to_buffer(buffer);
72        }
73    }
74}
75
76impl<'a> IntoFuture for Delete<'a> {
77    type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + 'a>>;
78    type Output = Result<u64, crate::Error>;
79
80    fn into_future(mut self) -> Self::IntoFuture {
81        let query = self.to_query();
82
83        Box::pin(async move { query.exec().await })
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    #![allow(dead_code)]
90
91    use pg_worm::prelude::*;
92
93    #[derive(Model)]
94    struct Book {
95        id: i64,
96        title: String,
97    }
98
99    #[test]
100    fn delete_statement() {
101        let q = Book::delete().to_query().0;
102        assert_eq!(q, "DELETE FROM book");
103    }
104
105    #[test]
106    fn delete_statement_with_where() {
107        let q = Book::delete().where_(Book::id.eq(&4)).to_query().0;
108
109        assert_eq!(q, "DELETE FROM book WHERE book.id = $1")
110    }
111}