Skip to main content

diesel/mysql_like/query_builder/
batch_update.rs

1use crate::mysql_like::MysqlLikeBackend;
2use crate::query_builder::update_statement::batch_update::{
3    BATCH_UPDATE_ALIAS, BatchAssignHelper, BatchKeyHelper, BatchUpdate, BatchValueHelper,
4};
5use crate::query_builder::update_statement::changeset::{Assign, ColumnWrapperForUpdate};
6use crate::query_builder::{AstPass, QueryFragment};
7use crate::result::EmptyChangeset;
8use crate::result::Error::QueryBuilderError;
9use crate::{QueryResult, Table};
10
11impl<DB: MysqlLikeBackend, C, T> BatchAssignHelper<DB> for Assign<ColumnWrapperForUpdate<C>, T>
12where
13    C: QueryFragment<DB>,
14{
15    fn batch_assign_identifier<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
16        self.target.0.walk_ast(out.reborrow())
17    }
18}
19
20impl<DB: MysqlLikeBackend, I, C, Tab>
21    QueryFragment<DB, crate::mysql_like::query_fragments::MySqlLikeBatchUpdateSupport>
22    for BatchUpdate<I, C, Tab::PrimaryKey, Tab>
23where
24    I: BatchKeyHelper<Tab::PrimaryKey, DB>,
25    C: BatchValueHelper<DB>,
26    Tab: Table,
27{
28    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
29        // Always unsafe to cache since this does not have a static query id.
30        out.unsafe_to_cache_prepared();
31
32        // UPDATE my_table AS tab
33        // JOIN ( WITH CTE (column_b, column_a, column_c) AS(
34        //      SELECT 1, 10, 20
35        //      UNION ALL SELECT 2, 5, 10
36        //      UNION ALL SELECT 3, 15, 30) SELECT * FROM CTE
37        // ) AS tmp
38        // ON
39        //      tab.column_b = tmp.column_b
40        // SET
41        //      tab.column_a = tmp.column_a,
42        //      tab.column_c = tmp.column_c;
43
44        let first = self
45            .values
46            .first()
47            .ok_or_else(|| QueryBuilderError(Box::new(EmptyChangeset)))?;
48
49        out.push_sql(" JOIN ( WITH  ");
50        out.push_identifier("CTE")?;
51        out.push_sql("(");
52        BatchKeyHelper::column_name(&first.0, out.reborrow())?;
53        out.push_sql(", ");
54        BatchValueHelper::column_name(&first.1, out.reborrow())?;
55        out.push_sql(") AS (");
56        let mut values = self.values.iter();
57        if let Some((key, value)) = values.next() {
58            out.push_sql(" SELECT ");
59            BatchKeyHelper::bind_value(key, out.reborrow())?;
60            out.push_sql(", ");
61            BatchValueHelper::bind_value(value, out.reborrow())?;
62        }
63        for (key, value) in values {
64            out.push_sql(" UNION ALL SELECT ");
65            BatchKeyHelper::bind_value(key, out.reborrow())?;
66            out.push_sql(", ");
67            BatchValueHelper::bind_value(value, out.reborrow())?;
68        }
69        out.push_sql(" ) SELECT * FROM ");
70        out.push_identifier("CTE")?;
71        out.push_sql(")");
72
73        out.push_sql(" AS ");
74        out.push_identifier(BATCH_UPDATE_ALIAS)?;
75
76        out.push_sql(" ON ");
77
78        <I as BatchKeyHelper<Tab::PrimaryKey, DB>>::assign(&self.primary_key, out.reborrow())?;
79        out.push_sql(" SET ");
80        BatchValueHelper::assign(&first.1, out.reborrow())?;
81
82        Ok(())
83    }
84}