Skip to main content

diesel/pg/query_builder/
batch_update.rs

1use crate::query_builder::update_statement::batch_update::{
2    BATCH_UPDATE_ALIAS, BatchAssignHelper, BatchKeyHelper, BatchUpdate, BatchValueHelper,
3};
4use crate::query_builder::update_statement::changeset::{Assign, ColumnWrapperForUpdate};
5use crate::query_builder::{AstPass, QueryFragment};
6use crate::result::EmptyChangeset;
7use crate::result::Error::QueryBuilderError;
8use crate::{QueryResult, Table};
9
10impl<C, T> BatchAssignHelper<crate::pg::Pg> for Assign<ColumnWrapperForUpdate<C>, T>
11where
12    ColumnWrapperForUpdate<C>: QueryFragment<crate::pg::Pg>,
13{
14    fn batch_assign_identifier<'b>(
15        &'b self,
16        mut out: AstPass<'_, 'b, crate::pg::Pg>,
17    ) -> QueryResult<()> {
18        self.target.walk_ast(out.reborrow())
19    }
20}
21
22impl<Tab, I, C> QueryFragment<crate::pg::Pg, crate::pg::backend::PostgresLikeBatchUpdateSupport>
23    for BatchUpdate<I, C, Tab::PrimaryKey, Tab>
24where
25    C: BatchValueHelper<crate::pg::Pg>,
26    I: BatchKeyHelper<Tab::PrimaryKey, crate::pg::Pg>,
27    Tab: Table,
28{
29    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, crate::pg::Pg>) -> QueryResult<()> {
30        // Always unsafe to cache since this does not have a static query id.
31        out.unsafe_to_cache_prepared();
32
33        let first = self
34            .values
35            .first()
36            .ok_or_else(|| QueryBuilderError(Box::new(EmptyChangeset)))?;
37
38        out.push_sql(" SET ");
39
40        // --- Create this statement with the following steps:
41        //
42        // UPDATE my_table AS tab
43        // SET
44        //      column_a = tmp.column_a,
45        //      column_c = tmp.column_c
46        // FROM ( VALUES
47        //      ('aa', 1, 11),
48        //      ('bb', 2, 22)
49        // ) AS tmp(column_a, column_b, column_c)
50        // WHERE
51        //      tab.column_b = tmp.column_b;
52
53        // --- Assign target columns from temporary columns
54        //
55        //      column_a = tmp.column_a,
56        //      column_c = tmp.column_c
57        BatchValueHelper::assign(&first.1, out.reborrow())?;
58
59        // --- List of values
60        //
61        // FROM ( VALUES
62        //      ('aa', 1, 11),
63        //      ('bb', 2, 22)
64        // )
65        out.push_sql(" FROM ( VALUES ");
66        let mut values = self.values.iter();
67        if let Some((key, value)) = values.next() {
68            out.push_sql("(");
69            BatchKeyHelper::bind_value(key, out.reborrow())?;
70            out.push_sql(", ");
71            BatchValueHelper::bind_value(value, out.reborrow())?;
72            out.push_sql(")");
73        }
74        for (key, value) in values {
75            out.push_sql(", (");
76            BatchKeyHelper::bind_value(key, out.reborrow())?;
77            out.push_sql(", ");
78            BatchValueHelper::bind_value(value, out.reborrow())?;
79            out.push_sql(")");
80        }
81        out.push_sql(" )");
82
83        // --- Set alias and its columns
84        //
85        //      AS tmp(column_a, column_b, column_c)
86        out.push_sql(" AS ");
87        out.push_identifier(BATCH_UPDATE_ALIAS)?;
88        out.push_sql("(");
89        BatchKeyHelper::column_name(&first.0, out.reborrow())?;
90        out.push_sql(", ");
91        BatchValueHelper::column_name(&first.1, out.reborrow())?;
92        out.push_sql(")");
93
94        // --- Set equality condition for primary key(s)
95        //
96        // WHERE tab.column_b = tmp.column_b;
97        out.push_sql(" WHERE ");
98        <I as BatchKeyHelper<Tab::PrimaryKey, crate::pg::Pg>>::assign(&self.primary_key, out)?;
99        Ok(())
100    }
101}