grafbase_sql_ast/ast/
update.rs

1use crate::ast::{Column, ConditionTree, Expression, Query, Table};
2
3type Type<'a> = Column<'a>;
4
5/// A builder for an `UPDATE` statement.
6#[derive(Debug, PartialEq, Clone)]
7pub struct Update<'a> {
8    pub(crate) table: Table<'a>,
9    pub(crate) columns: Vec<Column<'a>>,
10    pub(crate) values: Vec<Expression<'a>>,
11    pub(crate) conditions: Option<ConditionTree<'a>>,
12    pub(crate) returning: Option<Vec<Type<'a>>>,
13}
14
15impl<'a> From<Update<'a>> for Query<'a> {
16    fn from(update: Update<'a>) -> Self {
17        Query::Update(Box::new(update))
18    }
19}
20
21impl<'a> Update<'a> {
22    /// Creates the basis for an `UPDATE` statement to the given table.
23    pub fn table<T>(table: T) -> Self
24    where
25        T: Into<Table<'a>>,
26    {
27        Self {
28            table: table.into(),
29            columns: Vec::new(),
30            values: Vec::new(),
31            conditions: None,
32            returning: None,
33        }
34    }
35
36    /// Add another column value assignment to the query
37    ///
38    /// ```rust
39    /// # use grafbase_sql_ast::{ast::*, renderer::{Renderer, self}};
40    /// # fn main() {
41    /// let mut query = Update::table("users");
42    /// query.set("foo", 10);
43    /// query.set("bar", false);
44    ///
45    /// let (sql, params) = renderer::Postgres::build(query);
46    /// assert_eq!(r#"UPDATE "users" SET "foo" = $1, "bar" = $2"#, sql);
47    ///
48    /// assert_eq!(
49    ///     vec![
50    ///         Value::from(10),
51    ///         Value::from(false),
52    ///     ],
53    ///     params,
54    /// );
55    /// # }
56    /// ```
57    pub fn set<K, V>(&mut self, column: K, value: V)
58    where
59        K: Into<Column<'a>>,
60        V: Into<Expression<'a>>,
61    {
62        self.columns.push(column.into());
63        self.values.push(value.into());
64    }
65
66    /// Adds `WHERE` conditions to the query. See
67    /// [Comparable](trait.Comparable.html#required-methods) for more examples.
68    ///
69    /// ```rust
70    /// # use grafbase_sql_ast::{ast::*, renderer::{Renderer, self}};
71    /// # fn main() {
72    /// let mut query = Update::table("users");
73    /// query.set("foo", 1);
74    /// query.so_that("bar".equals(false));
75    ///
76    /// let (sql, params) = renderer::Postgres::build(query);
77    ///
78    /// assert_eq!(r#"UPDATE "users" SET "foo" = $1 WHERE "bar" = $2"#, sql);
79    ///
80    /// assert_eq!(
81    ///     vec![
82    ///         Value::from(1),
83    ///         Value::from(false),
84    ///     ],
85    ///     params,
86    /// );
87    /// # }
88    /// ```
89    ///
90    /// We can also use a nested `SELECT` in the conditions.
91    ///
92    /// ```rust
93    /// # use grafbase_sql_ast::{ast::*, renderer::{Renderer, self}};
94    /// # fn main() {
95    /// let mut select = Select::from_table("bars");
96    /// select.column("id");
97    /// select.so_that("uniq_val".equals(3));
98    ///
99    /// let mut query = Update::table("users");
100    /// query.set("foo", 1);
101    /// query.so_that("bar".equals(select));
102    ///
103    /// let (sql, params) = renderer::Postgres::build(query);
104    ///
105    /// assert_eq!(
106    ///     r#"UPDATE "users" SET "foo" = $1 WHERE "bar" = (SELECT "id" FROM "bars" WHERE "uniq_val" = $2)"#,
107    ///     sql
108    /// );
109    ///
110    /// assert_eq!(
111    ///     vec![
112    ///         Value::from(1),
113    ///         Value::from(3),
114    ///     ],
115    ///     params,
116    /// );
117    /// # }
118    /// ```
119    pub fn so_that<T>(&mut self, conditions: T)
120    where
121        T: Into<ConditionTree<'a>>,
122    {
123        self.conditions = Some(conditions.into());
124    }
125
126    /// Sets the returned columns.
127    ///
128    /// ```rust
129    /// # use grafbase_sql_ast::{ast::*, renderer::{Renderer, self}};
130    /// # fn main() {
131    /// let mut update = Update::table("users");
132    /// update.set("foo", 10);
133    /// update.returning(vec!["id"]);
134    ///
135    /// let (sql, _) = renderer::Postgres::build(update);
136    ///
137    /// assert_eq!(r#"UPDATE "users" SET "foo" = $1 RETURNING "id""#, sql);
138    /// # }
139    /// ```
140    #[cfg(feature = "postgresql")]
141    pub fn returning<K, I>(&mut self, columns: I)
142    where
143        K: Into<Column<'a>>,
144        I: IntoIterator<Item = K>,
145    {
146        self.returning = Some(columns.into_iter().map(|k| k.into()).collect());
147    }
148}