Skip to main content

nautilus_core/
delete.rs

1//! DELETE query AST and builder.
2
3use crate::column::ColumnMarker;
4use crate::error::{Error, Result};
5use crate::expr::Expr;
6
7/// DELETE query AST node.
8#[derive(Debug, Clone, PartialEq)]
9pub struct Delete {
10    /// Table name.
11    pub table: String,
12    /// WHERE clause.
13    pub filter: Option<Expr>,
14    /// Columns to return (RETURNING clause). Empty = no RETURNING.
15    pub returning: Vec<ColumnMarker>,
16}
17
18impl Delete {
19    /// Creates a new DELETE query builder for the given table.
20    pub fn from_table(table: impl Into<String>) -> DeleteBuilder {
21        DeleteBuilder {
22            table: table.into(),
23            filter: None,
24            returning: Vec::new(),
25        }
26    }
27}
28
29/// Builder for DELETE queries.
30#[derive(Debug, Clone)]
31pub struct DeleteBuilder {
32    table: String,
33    filter: Option<Expr>,
34    returning: Vec<ColumnMarker>,
35}
36
37impl DeleteBuilder {
38    /// Adds a WHERE clause filter.
39    #[must_use]
40    pub fn filter(mut self, expr: Expr) -> Self {
41        self.filter = Some(expr);
42        self
43    }
44
45    /// Sets the RETURNING clause columns.
46    #[must_use]
47    pub fn returning(mut self, columns: Vec<ColumnMarker>) -> Self {
48        self.returning = columns;
49        self
50    }
51
52    /// Builds the final DELETE query.
53    ///
54    /// # Errors
55    ///
56    /// Returns an error if the table name is empty.
57    pub fn build(self) -> Result<Delete> {
58        if self.table.is_empty() {
59            return Err(Error::MissingField("table".to_string()));
60        }
61
62        Ok(Delete {
63            table: self.table,
64            filter: self.filter,
65            returning: self.returning,
66        })
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73    use crate::value::Value;
74
75    #[test]
76    fn test_simple_delete() {
77        let delete = Delete::from_table("users").build().unwrap();
78
79        assert_eq!(delete.table, "users");
80        assert!(delete.filter.is_none());
81        assert!(delete.returning.is_empty());
82    }
83
84    #[test]
85    fn test_delete_with_filter() {
86        let delete = Delete::from_table("users")
87            .filter(Expr::column("id").eq(Expr::param(Value::I64(1))))
88            .build()
89            .unwrap();
90
91        assert!(delete.filter.is_some());
92    }
93
94    #[test]
95    fn test_delete_with_returning() {
96        let delete = Delete::from_table("users")
97            .returning(vec![
98                ColumnMarker::new("users", "id"),
99                ColumnMarker::new("users", "email"),
100            ])
101            .build()
102            .unwrap();
103
104        assert_eq!(delete.returning.len(), 2);
105        assert_eq!(delete.returning[0].name, "id");
106        assert_eq!(delete.returning[1].name, "email");
107    }
108
109    #[test]
110    fn test_delete_with_complex_filter() {
111        let filter = Expr::column("id")
112            .ge(Expr::param(Value::I64(10)))
113            .and(Expr::column("active").eq(Expr::param(Value::Bool(false))));
114
115        let delete = Delete::from_table("users")
116            .filter(filter)
117            .returning(vec![
118                ColumnMarker::new("users", "id"),
119                ColumnMarker::new("users", "email"),
120            ])
121            .build()
122            .unwrap();
123
124        assert!(delete.filter.is_some());
125        assert_eq!(delete.returning.len(), 2);
126    }
127
128    #[test]
129    fn test_missing_table() {
130        let result = Delete::from_table("").build();
131
132        assert!(result.is_err());
133    }
134}