Skip to main content

diesel/query_builder/update_statement/
batch_update.rs

1#[cfg(doc)]
2use crate::backend::SqlDialect;
3use crate::backend::{Backend, sql_dialect};
4use crate::query_builder::{AstPass, QueryFragment};
5use crate::{QueryResult, query_builder::*};
6use core::marker::PhantomData;
7
8#[cfg(any(
9    feature = "__sqlite-shared",
10    feature = "postgres_backend",
11    feature = "mysql_backend"
12))]
13pub(crate) const BATCH_UPDATE_ALIAS: &str = "__diesel_internal_temp_values";
14
15#[cfg(any(
16    feature = "__sqlite-shared",
17    feature = "postgres_backend",
18    feature = "mysql_backend"
19))]
20pub trait BatchValueHelper<DB: Backend> {
21    fn assign<'b>(&'b self, out: AstPass<'_, 'b, DB>) -> QueryResult<()>;
22
23    fn column_name<'b>(&'b self, out: AstPass<'_, 'b, DB>) -> QueryResult<()>;
24
25    fn bind_value<'b>(&'b self, out: AstPass<'_, 'b, DB>) -> QueryResult<()>;
26}
27
28#[cfg(any(
29    feature = "__sqlite-shared",
30    feature = "postgres_backend",
31    feature = "mysql_backend"
32))]
33pub trait BatchAssignHelper<DB: Backend> {
34    fn batch_assign_identifier<'a>(&'a self, out: AstPass<'_, 'a, DB>) -> QueryResult<()>;
35}
36
37#[cfg(any(
38    feature = "__sqlite-shared",
39    feature = "postgres_backend",
40    feature = "mysql_backend"
41))]
42pub trait BatchKeyHelper<PK, DB: Backend> {
43    fn bind_value<'b>(&'b self, out: AstPass<'_, 'b, DB>) -> QueryResult<()>;
44
45    fn column_name<'b>(&'b self, out: AstPass<'_, 'b, DB>) -> QueryResult<()>;
46
47    fn assign<'b>(pk: &'b PK, out: AstPass<'_, 'b, DB>) -> QueryResult<()>;
48}
49
50#[cfg(any(
51    feature = "__sqlite-shared",
52    feature = "postgres_backend",
53    feature = "mysql_backend"
54))]
55impl<PK, DB, C> BatchKeyHelper<PK, DB> for C
56where
57    DB: Backend + crate::sql_types::HasSqlType<PK::SqlType>,
58    C: crate::serialize::ToSql<PK::SqlType, DB>,
59    PK: crate::expression::Expression + crate::Column + QueryFragment<DB>,
60    PK::SqlType: crate::sql_types::SingleValue,
61{
62    fn bind_value<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
63        out.push_bind_param(self)
64    }
65
66    fn column_name<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
67        out.push_identifier(PK::NAME)
68    }
69
70    fn assign<'b>(pk: &'b PK, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
71        pk.walk_ast(out.reborrow())?;
72        out.push_sql(" = ");
73        out.push_identifier(BATCH_UPDATE_ALIAS)?;
74        out.push_sql(".");
75        out.push_identifier(PK::NAME)?;
76        Ok(())
77    }
78}
79
80/// This type represents a batch update clause, which allows
81/// to update multiple rows at once.
82///
83/// Custom backends can specialize the [`QueryFragment`]
84/// implementation via [`SqlDialect::BatchUpdateSupport`]
85/// or provide fully custom [`ExecuteDsl`](crate::query_dsl::methods::ExecuteDsl)
86/// and [`LoadQuery`](crate::query_dsl::methods::LoadQuery) implementations
87#[cfg_attr(
88    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
89    cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")
90)]
91// warn(dead_code) is a false positive for the fields 'values' and 'primary_key' as
92// specialized implementations for the backends actually use them.
93#[allow(dead_code)]
94#[derive(#[automatically_derived]
#[allow(dead_code)]
impl<I: ::core::fmt::Debug, C: ::core::fmt::Debug, PK: ::core::fmt::Debug,
    Tab: ::core::fmt::Debug> ::core::fmt::Debug for BatchUpdate<I, C, PK, Tab>
    {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field3_finish(f, "BatchUpdate",
            "values", &self.values, "primary_key", &self.primary_key,
            "_marker", &&self._marker)
    }
}Debug)]
95pub struct BatchUpdate<I, C, PK, Tab> {
96    // values.0 -> I: Identifier from Identifiable::Id
97    // values.1 -> V: Changeset from AsChangeset::Changeset
98    pub(crate) values: Vec<(I, C)>,
99    // PK: PrimaryKey will have same SqlType as I
100    pub(crate) primary_key: PK,
101    _marker: PhantomData<Tab>,
102}
103
104impl<I, C, PK, Tab> BatchUpdate<I, C, PK, Tab> {
105    /// Docs
106    pub fn new(values: Vec<(I, C)>, primary_key: PK) -> Self {
107        Self {
108            values,
109            primary_key,
110            _marker: PhantomData,
111        }
112    }
113}
114
115impl<I, C, PK, Tab, DB> QueryFragment<DB> for BatchUpdate<I, C, PK, Tab>
116where
117    DB: Backend,
118    DB::BatchUpdateSupport: sql_dialect::batch_update_support::SupportsBatchUpdate,
119    Self: QueryFragment<DB, DB::BatchUpdateSupport>,
120{
121    fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
122        <Self as QueryFragment<DB, DB::BatchUpdateSupport>>::walk_ast(self, pass)
123    }
124}