Skip to main content

diesel/upsert/
on_conflict_extension.rs

1use crate::expression::Expression;
2use crate::query_builder::update_statement::SetAutoTypeHelper;
3use crate::query_builder::upsert::into_conflict_clause::IntoConflictValueClause;
4use crate::query_builder::upsert::on_conflict_actions::*;
5use crate::query_builder::upsert::on_conflict_clause::*;
6use crate::query_builder::upsert::on_conflict_target::*;
7pub use crate::query_builder::upsert::on_conflict_target_decorations::DecoratableTarget;
8use crate::query_builder::where_clause::{NoWhereClause, WhereAnd, WhereOr};
9use crate::query_builder::{AsChangeset, InsertStatement, UndecoratedInsertRecord};
10use crate::query_dsl::filter_dsl::FilterDsl;
11use crate::query_dsl::methods::OrFilterDsl;
12use crate::query_source::QuerySource;
13use crate::sql_types::BoolOrNullableBool;
14
15impl<T, U, Op, Ret> InsertStatement<T, U, Op, Ret>
16where
17    T: QuerySource,
18    U: UndecoratedInsertRecord<T> + IntoConflictValueClause,
19{
20    /// Adds `ON CONFLICT DO NOTHING` to the insert statement, without
21    /// specifying any columns or constraints to restrict the conflict to.
22    ///
23    /// # Examples
24    ///
25    /// ### Single Record
26    ///
27    /// ```rust
28    /// # include!("on_conflict_docs_setup.rs");
29    /// #
30    /// # fn main() {
31    /// #     run_test().unwrap()
32    /// # }
33    /// # fn run_test() -> QueryResult<()> {
34    /// #     use self::users::dsl::*;
35    /// #     let conn = &mut establish_connection();
36    /// #     #[cfg(any(feature = "postgres", feature = "mariadb"))]
37    /// #     diesel::sql_query("TRUNCATE TABLE users").execute(conn).unwrap();
38    /// #     #[cfg(any(feature = "__sqlite-shared", feature = "mysql"))]
39    /// #     diesel::sql_query("DELETE FROM users").execute(conn).unwrap();
40    /// let user = User {
41    ///     id: 1,
42    ///     name: "Sean",
43    /// };
44    ///
45    /// let user_count = users.count().get_result::<i64>(conn)?;
46    /// assert_eq!(user_count, 0);
47    ///
48    /// diesel::insert_into(users)
49    ///     .values(&user)
50    ///     .on_conflict_do_nothing()
51    ///     .execute(conn)?;
52    /// let user_count = users.count().get_result::<i64>(conn)?;
53    /// assert_eq!(user_count, 1);
54    ///
55    /// diesel::insert_into(users)
56    ///     .values(&user)
57    ///     .on_conflict_do_nothing()
58    ///     .execute(conn)?;
59    /// let user_count = users.count().get_result::<i64>(conn)?;
60    /// assert_eq!(user_count, 1);
61    /// # Ok(())
62    /// # }
63    /// ```
64    ///
65    /// ### Vec of Records
66    ///
67    /// ```rust
68    /// # include!("on_conflict_docs_setup.rs");
69    /// #
70    /// # fn main() {
71    /// #     run_test().unwrap()
72    /// # }
73    /// #
74    /// # fn run_test() -> diesel::QueryResult<()> {
75    /// #     use self::users::dsl::*;
76    /// #     let conn = &mut establish_connection();
77    /// #     #[cfg(any(feature = "postgres", feature = "mariadb"))]
78    /// #     diesel::sql_query("TRUNCATE TABLE users").execute(conn).unwrap();
79    /// #     #[cfg(any(feature = "mysql", feature = "__sqlite-shared"))]
80    /// #     diesel::sql_query("DELETE FROM users").execute(conn).unwrap();
81    /// # #[cfg(any(feature = "postgres", feature = "mysql", feature = "mariadb"))]
82    /// let user = User {
83    ///     id: 1,
84    ///     name: "Sean",
85    /// };
86    ///
87    /// # #[cfg(any(feature = "postgres", feature = "mysql", feature = "mariadb"))]
88    /// let inserted_row_count = diesel::insert_into(users)
89    ///     .values(&vec![user, user])
90    ///     .on_conflict_do_nothing()
91    ///     .execute(conn)?;
92    /// # #[cfg(any(feature = "postgres", feature = "mysql", feature = "mariadb"))]
93    /// let user_count = users.count().get_result::<i64>(conn)?;
94    /// # #[cfg(any(feature = "postgres", feature = "mysql", feature = "mariadb"))]
95    /// assert_eq!(user_count, 1);
96    /// # Ok(())
97    /// # }
98    /// ```
99    pub fn on_conflict_do_nothing(self) -> crate::dsl::OnConflictDoNothing<Self> {
100        self.replace_values(|values| OnConflictValues::do_nothing(values.into_value_clause()))
101    }
102
103    /// Adds an `ON CONFLICT` to the insert statement, if a conflict occurs
104    /// for the given unique constraint.
105    ///
106    /// `Target` can be one of:
107    ///
108    /// - A column
109    /// - A tuple of columns
110    /// - [`on_constraint("constraint_name")`][`on_constraint`]
111    ///
112    /// # Examples
113    ///
114    /// ### Specifying a column as the target
115    ///
116    /// This is supported by sqlite and postgres only
117    ///
118    /// ```rust
119    /// # include!("../doctest_setup.rs");
120    /// #
121    /// # table! {
122    /// #     users {
123    /// #         id -> Integer,
124    /// #         name -> VarChar,
125    /// #         hair_color -> VarChar,
126    /// #     }
127    /// # }
128    /// #
129    /// # #[derive(Clone, Copy, Insertable)]
130    /// # #[diesel(table_name = users)]
131    /// # struct User<'a> {
132    /// #     id: i32,
133    /// #     name: &'a str,
134    /// # }
135    /// #
136    /// # // Reading the query result requires reading memory allocated by the
137    /// # // native sqlite library, which miri cannot track provenance for.
138    /// # #[cfg(miri)]
139    /// # fn main() {}
140    /// # #[cfg(not(miri))]
141    /// # fn main() {
142    /// #    run_test().unwrap()
143    /// # }
144    /// # #[cfg(any(feature = "postgres", feature = "__sqlite-shared"))]
145    /// # fn run_test() -> diesel::QueryResult<()> {
146    /// #     use self::users::dsl::*;
147    /// use diesel::upsert::*;
148    ///
149    /// #     let conn = &mut establish_connection();
150    /// #     #[cfg(any(feature = "__sqlite-shared", feature = "postgres"))]
151    /// #     diesel::sql_query("DROP TABLE users").execute(conn).unwrap();
152    /// #     #[cfg(any(feature = "__sqlite-shared", feature = "postgres"))]
153    /// #     diesel::sql_query("CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT)").execute(conn).unwrap();
154    /// diesel::sql_query("CREATE UNIQUE INDEX users_name ON users (name)").execute(conn).unwrap();
155    /// let user = User { id: 1, name: "Sean" };
156    /// let same_name_different_id = User { id: 2, name: "Sean" };
157    /// let same_id_different_name = User { id: 1, name: "Pascal" };
158    /// assert_eq!(Ok(1), diesel::insert_into(users).values(&user).execute(conn));
159    ///
160    /// let query = diesel::insert_into(users)
161    ///     .values(&same_id_different_name)
162    ///     .on_conflict(id)
163    ///     .do_nothing()
164    ///     .execute(conn)?;
165    ///
166    /// let user_names = users.select(name).load::<String>(conn)?;
167    /// assert_eq!(user_names, vec![String::from("Sean")]);
168    ///
169    /// let idx_conflict_result = diesel::insert_into(users)
170    ///     .values(&same_name_different_id)
171    ///     .on_conflict(id)
172    ///     .do_nothing()
173    ///     .execute(conn);
174    /// assert!(idx_conflict_result.is_err());
175    /// # Ok(())
176    /// # }
177    /// #[cfg(any(feature = "mysql", feature = "mariadb"))]
178    /// fn run_test() -> diesel::QueryResult<()> { Ok(()) }
179    /// ```
180    ///
181    /// ### Specifying multiple columns as the target
182    ///
183    /// This is supported by sqlite and postgres only
184    ///
185    /// ```rust
186    /// # include!("../doctest_setup.rs");
187    /// #
188    /// # table! {
189    /// #     users {
190    /// #         id -> Integer,
191    /// #         name -> VarChar,
192    /// #         hair_color -> VarChar,
193    /// #     }
194    /// # }
195    /// #
196    /// # #[derive(Clone, Copy, Insertable)]
197    /// # #[diesel(table_name = users)]
198    /// # struct User<'a> {
199    /// #     id: i32,
200    /// #     name: &'a str,
201    /// #     hair_color: &'a str,
202    /// # }
203    /// #
204    /// # #[cfg(any(feature = "__sqlite-shared", feature = "postgres"))]
205    /// # fn main() {
206    /// #     use self::users::dsl::*;
207    /// use diesel::upsert::*;
208    ///
209    /// #     let conn = &mut establish_connection();
210    /// #     diesel::sql_query("DROP TABLE users").execute(conn).unwrap();
211    /// #     diesel::sql_query("CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT, hair_color TEXT)").execute(conn).unwrap();
212    /// diesel::sql_query("CREATE UNIQUE INDEX users_name_hair_color ON users (name, hair_color)").execute(conn).unwrap();
213    /// let user = User { id: 1, name: "Sean", hair_color: "black" };
214    /// let same_name_different_hair_color = User { id: 2, name: "Sean", hair_color: "brown" };
215    /// let same_name_same_hair_color = User { id: 3, name: "Sean", hair_color: "black" };
216    ///
217    /// assert_eq!(Ok(1), diesel::insert_into(users).values(&user).execute(conn));
218    ///
219    /// let inserted_row_count = diesel::insert_into(users)
220    ///     .values(&same_name_different_hair_color)
221    ///     .on_conflict((name, hair_color))
222    ///     .do_nothing()
223    ///     .execute(conn);
224    /// assert_eq!(Ok(1), inserted_row_count);
225    ///
226    /// let inserted_row_count = diesel::insert_into(users)
227    ///     .values(&same_name_same_hair_color)
228    ///     .on_conflict((name, hair_color))
229    ///     .do_nothing()
230    ///     .execute(conn);
231    /// assert_eq!(Ok(0), inserted_row_count);
232    /// # }
233    ///
234    /// #[cfg(any(feature = "mysql", feature = "mariadb"))]
235    /// fn main() {}
236    /// ```
237    ///
238    /// ### ON DUPLICATE KEY
239    ///
240    /// Mysql supports only catching all duplicated keys at once:
241    ///
242    /// ```
243    /// # include!("../doctest_setup.rs");
244    /// #
245    /// # table! {
246    /// #     users {
247    /// #         id -> Integer,
248    /// #         name -> VarChar,
249    /// #         hair_color -> VarChar,
250    /// #     }
251    /// # }
252    /// #
253    /// # #[derive(Clone, Copy, Insertable)]
254    /// # #[diesel(table_name = users)]
255    /// # struct User<'a> {
256    /// #     id: i32,
257    /// #     name: &'a str,
258    /// # }
259    /// #
260    /// # fn main() {
261    /// #    run_test().unwrap()
262    /// # }
263    /// # #[cfg(any(feature = "mysql", feature = "mariadb"))]
264    /// # fn run_test() -> diesel::QueryResult<()> {
265    /// #     use self::users::dsl::*;
266    /// use diesel::upsert::*;
267    ///
268    /// #     let conn = &mut establish_connection();
269    /// #     diesel::sql_query("DROP TABLE users").execute(conn).unwrap();
270    /// #     diesel::sql_query("CREATE TEMPORARY TABLE users (id SERIAL PRIMARY KEY, name VARCHAR(255), hair_color VARCHAR(255))").execute(conn).unwrap();
271    /// diesel::sql_query("CREATE UNIQUE INDEX users_name ON users (name)").execute(conn).unwrap();
272    /// let user = User { id: 1, name: "Sean" };
273    /// let same_name_different_id = User { id: 2, name: "Sean" };
274    /// let same_id_different_name = User { id: 1, name: "Pascal" };
275    ///
276    /// assert_eq!(Ok(1), diesel::insert_into(users).values(&user).execute(conn));
277    ///
278    /// # diesel::delete(users.filter(name.ne("Sean"))).execute(conn)?;
279    /// let user_names = users.select(name).load::<String>(conn)?;
280    /// assert_eq!(user_names, vec![String::from("Sean")]);
281    ///
282    /// let query = diesel::insert_into(users)
283    ///     .values(&same_id_different_name)
284    ///     .on_conflict(diesel::dsl::DuplicatedKeys)
285    ///     .do_nothing()
286    ///     .execute(conn)?;
287    ///
288    /// let user_names = users.select(name).load::<String>(conn)?;
289    /// assert_eq!(user_names, vec![String::from("Sean")]);
290    ///
291    /// let idx_conflict_result = diesel::insert_into(users)
292    ///     .values(&same_name_different_id)
293    ///     .on_conflict(diesel::dsl::DuplicatedKeys)
294    ///     .do_nothing()
295    ///     .execute(conn)?;
296    ///
297    /// let user_names = users.select(name).load::<String>(conn)?;
298    /// assert_eq!(user_names, vec![String::from("Sean")]);
299    /// # Ok(())
300    /// # }
301    /// #[cfg(not(any(feature = "mysql", feature = "mariadb")))]
302    /// fn run_test() -> diesel::QueryResult<()> {Ok(())}
303    /// ```
304    ///
305    /// See the documentation for [`on_constraint`], [`do_update`], and
306    /// [`filter_target`] for more examples.
307    ///
308    /// [`on_constraint`]: ../upsert/fn.on_constraint.html
309    /// [`do_update`]: crate::upsert::IncompleteOnConflict::do_update()
310    /// [`filter_target`]: crate::upsert::DecoratableTarget::filter_target()
311    pub fn on_conflict<Target>(self, target: Target) -> crate::dsl::OnConflict<Self, Target>
312    where
313        ConflictTarget<Target>: OnConflictTarget<T>,
314    {
315        IncompleteOnConflict {
316            stmt: self.replace_values(IntoConflictValueClause::into_value_clause),
317            target: ConflictTarget::new(target),
318        }
319    }
320}
321
322impl<Stmt, T, P> DecoratableTarget<P> for IncompleteOnConflict<Stmt, T>
323where
324    P: Expression,
325    P::SqlType: BoolOrNullableBool,
326    T: DecoratableTarget<P>,
327{
328    type FilterOutput = IncompleteOnConflict<Stmt, <T as DecoratableTarget<P>>::FilterOutput>;
329
330    /// Adds a `WHERE` predicate to the `ON CONFLICT` target, telling PostgreSQL
331    /// which unique index to check for conflicts.
332    ///
333    /// This generates `ON CONFLICT (target) WHERE predicate DO ...` SQL.
334    /// PostgreSQL selects unique indexes whose `WHERE` clause is implied by
335    /// the predicate. The predicate does not need to exactly match the index's
336    /// `WHERE` clause; implication is sufficient.
337    ///
338    /// Calling `.filter_target()` multiple times combines the predicates with
339    /// `AND`. PostgreSQL only.
340    ///
341    /// # Example
342    ///
343    /// ```rust
344    /// # include!("on_conflict_docs_setup.rs");
345    /// # #[cfg(feature = "postgres")]
346    /// # fn main() -> diesel::QueryResult<()> {
347    /// #     use self::users::dsl::*;
348    /// #     let conn = &mut establish_connection();
349    ///
350    /// diesel::sql_query(
351    ///     "CREATE UNIQUE INDEX users_name_active ON users (name) WHERE id > 5",
352    /// )
353    /// .execute(conn)?;
354    ///
355    /// let user = User { id: 10, name: "Sean" };
356    /// diesel::insert_into(users).values(&user).execute(conn)?;
357    ///
358    /// // id=11 satisfies the partial index predicate, so uniqueness is violated: does nothing.
359    /// let count = diesel::insert_into(users)
360    ///     .values(User { id: 11, name: "Sean" })
361    ///     .on_conflict(name)
362    ///     .filter_target(id.gt(5))
363    ///     .do_nothing()
364    ///     .execute(conn)?;
365    /// assert_eq!(count, 0);
366    ///
367    /// // id=3 does not satisfy the partial index predicate, so it is not covered by the index:
368    /// // no uniqueness violation, inserts normally.
369    /// let count = diesel::insert_into(users)
370    ///     .values(User { id: 3, name: "Sean" })
371    ///     .on_conflict(name)
372    ///     .filter_target(id.gt(5))
373    ///     .do_nothing()
374    ///     .execute(conn)?;
375    /// assert_eq!(count, 1);
376    /// # Ok(())
377    /// # }
378    /// # #[cfg(not(feature = "postgres"))]
379    /// # fn main() {}
380    /// ```
381    ///
382    /// ## Do update
383    ///
384    /// ```rust
385    /// # include!("on_conflict_docs_setup.rs");
386    /// # #[cfg(feature = "postgres")]
387    /// # fn main() -> diesel::QueryResult<()> {
388    /// #     use self::users::dsl::*;
389    /// #     let conn = &mut establish_connection();
390    ///
391    /// diesel::sql_query(
392    ///     "CREATE UNIQUE INDEX users_name_do_update ON users (name) WHERE id > 5",
393    /// )
394    /// .execute(conn)?;
395    ///
396    /// diesel::insert_into(users)
397    ///     .values(User { id: 10, name: "Sean" })
398    ///     .execute(conn)?;
399    ///
400    /// // id=11 satisfies the partial index predicate, so uniqueness is violated: name updated.
401    /// diesel::insert_into(users)
402    ///     .values(User { id: 11, name: "Sean" })
403    ///     .on_conflict(name)
404    ///     .filter_target(id.gt(5))
405    ///     .do_update()
406    ///     .set(name.eq("Updated"))
407    ///     .execute(conn)?;
408    ///
409    /// let names = users.filter(id.gt(5)).select(name).load::<String>(conn)?;
410    /// assert_eq!(names, vec!["Updated"]);
411    /// # Ok(())
412    /// # }
413    /// # #[cfg(not(feature = "postgres"))]
414    /// # fn main() {}
415    /// ```
416    ///
417    /// ## Chaining filter_target
418    ///
419    /// Calling `.filter_target()` multiple times combines the predicates with `AND`,
420    /// which is useful when the unique index `WHERE` clause has multiple conditions.
421    ///
422    /// ```rust
423    /// # include!("on_conflict_docs_setup.rs");
424    /// # #[cfg(feature = "postgres")]
425    /// # fn main() -> diesel::QueryResult<()> {
426    /// #     use self::users::dsl::*;
427    /// #     let conn = &mut establish_connection();
428    ///
429    /// diesel::sql_query(
430    ///     "CREATE UNIQUE INDEX users_name_range ON users (name) WHERE id > 5 AND id < 100",
431    /// )
432    /// .execute(conn)?;
433    ///
434    /// diesel::insert_into(users)
435    ///     .values(User { id: 10, name: "Sean" })
436    ///     .execute(conn)?;
437    ///
438    /// // Combined predicate matches the partial index, conflict detected: do nothing.
439    /// let count = diesel::insert_into(users)
440    ///     .values(User { id: 11, name: "Sean" })
441    ///     .on_conflict(name)
442    ///     .filter_target(id.gt(5))
443    ///     .filter_target(id.lt(100))
444    ///     .do_nothing()
445    ///     .execute(conn)?;
446    /// assert_eq!(count, 0);
447    /// # Ok(())
448    /// # }
449    /// # #[cfg(not(feature = "postgres"))]
450    /// # fn main() {}
451    /// ```
452    fn filter_target(self, predicate: P) -> Self::FilterOutput {
453        IncompleteOnConflict {
454            stmt: self.stmt,
455            target: self.target.filter_target(predicate),
456        }
457    }
458}
459
460/// A partially constructed `ON CONFLICT` clause.
461#[derive(#[automatically_derived]impl<Stmt: ::core::fmt::Debug,
    Target: ::core::fmt::Debug> ::core::fmt::Debug for
    IncompleteOnConflict<Stmt, Target> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f,
            "IncompleteOnConflict stmt target", &self.stmt, &&self.target)
    }
}Debug, #[automatically_derived]impl<Stmt: ::core::clone::Clone,
    Target: ::core::clone::Clone> ::core::clone::Clone for
    IncompleteOnConflict<Stmt, Target> {
    #[inline]
    fn clone(&self) -> Self {
        IncompleteOnConflict {
            stmt: ::core::clone::Clone::clone(&self.stmt),
            target: ::core::clone::Clone::clone(&self.target),
        }
    }
}Clone, #[automatically_derived]impl<Stmt: ::core::marker::Copy,
    Target: ::core::marker::Copy> ::core::marker::Copy for
    IncompleteOnConflict<Stmt, Target> {
}Copy)]
462pub struct IncompleteOnConflict<Stmt, Target> {
463    stmt: Stmt,
464    target: Target,
465}
466
467/// Helper trait for `#[auto_type]`
468///
469/// This trait allows extracting the internal types of a `IncompleteOnConflict`
470/// struct, which is needed to define the `DoNothing` and `DoUpdate` type aliases
471/// in `diesel::dsl`.
472#[allow(unreachable_pub)]
473pub trait OnConflictHelper {
474    /// The table on which the `INSERT` statement acts
475    type Table;
476    /// The `VALUES` clause of the `INSERT` statement
477    type Values;
478    /// The conflict target (e.g., column or constraint) specified in the `ON CONFLICT` clause
479    type Target;
480    /// The SQL definition of the insert operation
481    type Op;
482    /// The `RETURNING` clause of the statement
483    type Ret;
484}
485
486impl<T, U, Op, Ret, Target> OnConflictHelper
487    for IncompleteOnConflict<InsertStatement<T, U, Op, Ret>, Target>
488where
489    T: QuerySource,
490{
491    type Table = T;
492    type Values = U;
493    type Target = Target;
494    type Op = Op;
495    type Ret = Ret;
496}
497
498impl<Stmt, Target, Changes> SetAutoTypeHelper<Changes> for IncompleteDoUpdate<Stmt, Target>
499where
500    Stmt: crate::query_builder::insert_statement::InsertAutoTypeHelper,
501    <Stmt as crate::query_builder::insert_statement::InsertAutoTypeHelper>::Table: QuerySource,
502    Changes: AsChangeset<
503        Target = <Stmt as crate::query_builder::insert_statement::InsertAutoTypeHelper>::Table,
504    >,
505{
506    type Out = InsertStatement<
507        <Stmt as crate::query_builder::insert_statement::InsertAutoTypeHelper>::Table,
508        OnConflictValues<
509            <Stmt as crate::query_builder::insert_statement::InsertAutoTypeHelper>::Values,
510            Target,
511            DoUpdate<
512                Changes::Changeset,
513                <Stmt as crate::query_builder::insert_statement::InsertAutoTypeHelper>::Table,
514            >,
515        >,
516        <Stmt as crate::query_builder::insert_statement::InsertAutoTypeHelper>::Op,
517        <Stmt as crate::query_builder::insert_statement::InsertAutoTypeHelper>::Ret,
518    >;
519}
520
521impl<T: QuerySource, U, Op, Ret, Target>
522    IncompleteOnConflict<InsertStatement<T, U, Op, Ret>, Target>
523{
524    /// Creates a query with `ON CONFLICT (target) DO NOTHING`
525    ///
526    /// If you want to do nothing when *any* constraint conflicts, use
527    /// [`on_conflict_do_nothing`] instead. See [`on_conflict`] for usage
528    /// examples.
529    ///
530    /// [`on_conflict_do_nothing`]: crate::query_builder::InsertStatement::on_conflict_do_nothing()
531    /// [`on_conflict`]: crate::query_builder::InsertStatement::on_conflict()
532    pub fn do_nothing(self) -> crate::dsl::DoNothing<Self> {
533        let target = self.target;
534        self.stmt.replace_values(|values| {
535            OnConflictValues::new(values, target, DoNothing::new(), NoWhereClause)
536        })
537    }
538
539    /// Used to create a query in the form `ON CONFLICT (...) DO UPDATE ... [WHERE ...]`
540    ///
541    /// Call `.set` on the result of this function with the changes you want to
542    /// apply. The argument to `set` can be anything that implements `AsChangeset`
543    /// (e.g. anything you could pass to `set` on a normal update statement).
544    ///
545    /// Note: When inserting more than one row at a time, this query can still fail
546    /// if the rows being inserted conflict with each other.
547    ///
548    /// For some backends (PostgreSQL, SQLite) a `WHERE` clause can be used to limit the rows actually updated.
549    /// For PostgreSQL and SQLite you can use the `.filter()` method to add conditions like that.
550    ///
551    /// # Examples
552    ///
553    /// ## Set specific value on conflict
554    ///
555    /// PostgreSQL/SQLite:
556    ///
557    /// ```rust
558    /// # include!("on_conflict_docs_setup.rs");
559    /// #
560    /// # // Reading the query result requires reading memory allocated by the
561    /// # // native sqlite library, which miri cannot track provenance for.
562    /// # #[cfg(not(any(feature = "mysql", feature = "mariadb")))]
563    /// # #[cfg(miri)]
564    /// # fn main() {}
565    /// # #[cfg(all(not(miri), not(any(feature = "mysql", feature = "mariadb"))))]
566    /// # fn main() {
567    /// #     use self::users::dsl::*;
568    /// #     let conn = &mut establish_connection();
569    /// #     #[cfg(feature = "postgres")]
570    /// #     diesel::sql_query("TRUNCATE TABLE users").execute(conn).unwrap();
571    /// #     #[cfg(feature = "__sqlite-shared")]
572    /// #     diesel::sql_query("DELETE FROM users").execute(conn).unwrap();
573    /// let user = User {
574    ///     id: 1,
575    ///     name: "Pascal",
576    /// };
577    /// let user2 = User {
578    ///     id: 1,
579    ///     name: "Sean",
580    /// };
581    ///
582    /// assert_eq!(
583    ///     Ok(1),
584    ///     diesel::insert_into(users).values(&user).execute(conn)
585    /// );
586    ///
587    /// let insert_count = diesel::insert_into(users)
588    ///     .values(&user2)
589    ///     .on_conflict(id)
590    ///     .do_update()
591    ///     .set(name.eq("I DONT KNOW ANYMORE"))
592    ///     .execute(conn);
593    /// # #[cfg(any(feature = "__sqlite-shared", feature = "postgres"))]
594    /// assert_eq!(Ok(1), insert_count);
595    /// # #[cfg(any(feature = "mysql", feature = "mariadb"))]
596    /// assert_eq!(Ok(2), insert_count);
597    ///
598    /// let users_in_db = users.load(conn);
599    /// assert_eq!(
600    ///     Ok(vec![(1, "I DONT KNOW ANYMORE".to_string())]),
601    ///     users_in_db
602    /// );
603    /// # }
604    /// # #[cfg(any(feature = "mysql", feature = "mariadb"))]
605    /// # fn main() {}
606    /// ```
607    ///
608    /// MySQL:
609    ///
610    /// ```rust
611    /// # include!("on_conflict_docs_setup.rs");
612    /// #
613    /// # #[cfg(any(feature = "mysql", feature = "mariadb"))]
614    /// # fn main() -> diesel::QueryResult<()> {
615    /// #     use self::users::dsl::*;
616    /// #     let conn = &mut establish_connection();
617    /// #     diesel::sql_query("DELETE FROM users").execute(conn).unwrap();
618    /// let user = User {
619    ///     id: 1,
620    ///     name: "Pascal",
621    /// };
622    /// let user2 = User {
623    ///     id: 1,
624    ///     name: "Sean",
625    /// };
626    ///
627    /// assert_eq!(
628    ///     Ok(1),
629    ///     diesel::insert_into(users).values(&user).execute(conn)
630    /// );
631    ///
632    /// diesel::insert_into(users)
633    ///     .values(&user2)
634    ///     .on_conflict(diesel::dsl::DuplicatedKeys)
635    ///     .do_update()
636    ///     .set(name.eq("I DONT KNOW ANYMORE"))
637    ///     .execute(conn)?;
638    ///
639    /// let users_in_db = users.load(conn);
640    /// assert_eq!(
641    ///     Ok(vec![(1, "I DONT KNOW ANYMORE".to_string())]),
642    ///     users_in_db
643    /// );
644    /// # Ok(())
645    /// # }
646    /// # #[cfg(not(any(feature = "mysql", feature = "mariadb")))]
647    /// # fn main() {}
648    /// ```
649    ///
650    /// ## Set `AsChangeset` struct on conflict
651    ///
652    /// PostgreSQL & SQLite:
653    ///
654    /// ```rust
655    /// # include!("on_conflict_docs_setup.rs");
656    /// #
657    /// # // Reading the query result requires reading memory allocated by the
658    /// # // native sqlite library, which miri cannot track provenance for.
659    /// # #[cfg(not(any(feature = "mysql", feature = "mariadb")))]
660    /// # #[cfg(miri)]
661    /// # fn main() {}
662    /// # #[cfg(all(not(miri), not(any(feature = "mysql", feature = "mariadb"))))]
663    /// # fn main() {
664    /// #     use self::users::dsl::*;
665    /// #     let conn = &mut establish_connection();
666    /// #     #[cfg(feature = "postgres")]
667    /// #     diesel::sql_query("TRUNCATE TABLE users").execute(conn).unwrap();
668    /// #     #[cfg(feature = "__sqlite-shared")]
669    /// #     diesel::sql_query("DELETE FROM users").execute(conn).unwrap();
670    /// let user = User {
671    ///     id: 1,
672    ///     name: "Pascal",
673    /// };
674    /// let user2 = User {
675    ///     id: 1,
676    ///     name: "Sean",
677    /// };
678    ///
679    /// assert_eq!(
680    ///     Ok(1),
681    ///     diesel::insert_into(users).values(&user).execute(conn)
682    /// );
683    ///
684    /// let insert_count = diesel::insert_into(users)
685    ///     .values(&user2)
686    ///     .on_conflict(id)
687    ///     .do_update()
688    ///     .set(&user2)
689    ///     .execute(conn);
690    /// assert_eq!(Ok(1), insert_count);
691    ///
692    /// let users_in_db = users.load(conn);
693    /// assert_eq!(Ok(vec![(1, "Sean".to_string())]), users_in_db);
694    /// # }
695    /// # #[cfg(any(feature = "mysql", feature = "mariadb"))]
696    /// # fn main() {}
697    /// ```
698    ///
699    /// MySQL:
700    ///
701    /// ```rust
702    /// # include!("on_conflict_docs_setup.rs");
703    ///
704    /// # #[cfg(any(feature = "mysql", feature = "mariadb"))]
705    /// # fn main() -> diesel::QueryResult<()> {
706    /// #     use self::users::dsl::*;
707    /// #     let conn = &mut establish_connection();
708    /// #     diesel::sql_query("DELETE FROM users").execute(conn).unwrap();
709    /// let user = User {
710    ///     id: 1,
711    ///     name: "Pascal",
712    /// };
713    /// let user2 = User {
714    ///     id: 1,
715    ///     name: "Sean",
716    /// };
717    ///
718    /// assert_eq!(
719    ///     Ok(1),
720    ///     diesel::insert_into(users).values(&user).execute(conn)
721    /// );
722    ///
723    /// diesel::insert_into(users)
724    ///     .values(&user2)
725    ///     .on_conflict(diesel::dsl::DuplicatedKeys)
726    ///     .do_update()
727    ///     .set(&user2)
728    ///     .execute(conn)?;
729    ///
730    /// let users_in_db = users.load(conn);
731    /// assert_eq!(Ok(vec![(1, "Sean".to_string())]), users_in_db);
732    /// # Ok(())
733    /// # }
734    ///
735    /// # #[cfg(not(any(feature = "mysql", feature = "mariadb")))]
736    /// # fn main() {}
737    /// ```
738    ///
739    /// ## Use `excluded` to get the rejected value
740    ///
741    /// ```rust
742    /// # include!("on_conflict_docs_setup.rs");
743    /// #
744    /// # #[cfg(any(feature = "__sqlite-shared", feature = "postgres"))]
745    /// # fn main() {
746    /// #     use self::users::dsl::*;
747    /// use diesel::upsert::excluded;
748    ///
749    /// #     let conn = &mut establish_connection();
750    /// #     #[cfg(feature = "postgres")]
751    /// #     diesel::sql_query("TRUNCATE TABLE users").execute(conn).unwrap();
752    /// let user = User {
753    ///     id: 1,
754    ///     name: "Pascal",
755    /// };
756    /// let user2 = User {
757    ///     id: 1,
758    ///     name: "Sean",
759    /// };
760    /// let user3 = User {
761    ///     id: 2,
762    ///     name: "Tess",
763    /// };
764    ///
765    /// # #[cfg(feature = "postgres")]
766    /// assert_eq!(
767    ///     Ok(1),
768    ///     diesel::insert_into(users).values(&user).execute(conn)
769    /// );
770    ///
771    /// #[cfg(feature = "postgres")]
772    /// let insert_count = diesel::insert_into(users)
773    ///     .values(&vec![user2, user3])
774    ///     .on_conflict(id)
775    ///     .do_update()
776    ///     .set(name.eq(excluded(name)))
777    ///     .execute(conn);
778    /// # #[cfg(feature = "postgres")]
779    /// assert_eq!(Ok(2), insert_count);
780    ///
781    /// # #[cfg(feature = "postgres")]
782    /// let users_in_db = users.load(conn);
783    /// # #[cfg(feature = "postgres")]
784    /// assert_eq!(
785    ///     Ok(vec![(1, "Sean".to_string()), (2, "Tess".to_string())]),
786    ///     users_in_db
787    /// );
788    /// # }
789    /// # #[cfg(any(feature = "mysql", feature = "mariadb"))]
790    /// # fn main() {}
791    /// ```
792    ///
793    /// ## Use `.filter()`method to limit the rows actually updated
794    ///
795    /// ```rust
796    /// # include!("on_conflict_docs_setup.rs");
797    /// #
798    /// # // Reading the query result requires reading memory allocated by the
799    /// # // native sqlite library, which miri cannot track provenance for.
800    /// # #[cfg(not(any(feature = "mysql", feature = "mariadb")))]
801    /// # #[cfg(miri)]
802    /// # fn main() {}
803    /// # #[cfg(all(not(miri), not(any(feature = "mysql", feature = "mariadb"))))]
804    /// # fn main() {
805    /// #     use diesel::QueryDsl;
806    /// #     use diesel::query_dsl::methods::FilterDsl;
807    /// use self::users::dsl::*;
808    /// #     let conn = &mut establish_connection();
809    /// #     #[cfg(feature = "postgres")]
810    /// #     diesel::sql_query("TRUNCATE TABLE users").execute(conn).unwrap();
811    /// #     #[cfg(feature = "__sqlite-shared")]
812    /// #     diesel::delete(users).execute(conn).unwrap();
813    /// let user = User {
814    ///     id: 1,
815    ///     name: "Pascal",
816    /// };
817    /// let user2 = User {
818    ///     id: 1,
819    ///     name: "Sean",
820    /// };
821    ///
822    /// assert_eq!(
823    ///     Ok(1),
824    ///     diesel::insert_into(users).values(&user).execute(conn)
825    /// );
826    ///
827    /// let insert_count = diesel::insert_into(users)
828    ///     .values(&user2)
829    ///     .on_conflict(id)
830    ///     .do_update()
831    ///     .set(&user2)
832    ///     .filter(id.ge(5))
833    ///     .execute(conn);
834    /// assert_eq!(Ok(0), insert_count);
835    ///
836    /// let users_in_db = users.load(conn);
837    /// assert_eq!(Ok(vec![(1, "Pascal".to_string())]), users_in_db);
838    /// # }
839    /// # #[cfg(any(feature = "mysql", feature = "mariadb"))]
840    /// # fn main() {}
841    /// ```
842    pub fn do_update(self) -> crate::dsl::DoUpdate<Self> {
843        IncompleteDoUpdate {
844            stmt: self.stmt,
845            target: self.target,
846        }
847    }
848}
849
850/// A partially constructed `ON CONFLICT DO UPDATE` clause.
851#[derive(#[automatically_derived]impl<Stmt: ::core::fmt::Debug,
    Target: ::core::fmt::Debug> ::core::fmt::Debug for
    IncompleteDoUpdate<Stmt, Target> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f,
            "IncompleteDoUpdate stmt target", &self.stmt, &&self.target)
    }
}Debug, #[automatically_derived]impl<Stmt: ::core::clone::Clone,
    Target: ::core::clone::Clone> ::core::clone::Clone for
    IncompleteDoUpdate<Stmt, Target> {
    #[inline]
    fn clone(&self) -> Self {
        IncompleteDoUpdate {
            stmt: ::core::clone::Clone::clone(&self.stmt),
            target: ::core::clone::Clone::clone(&self.target),
        }
    }
}Clone, #[automatically_derived]impl<Stmt: ::core::marker::Copy,
    Target: ::core::marker::Copy> ::core::marker::Copy for
    IncompleteDoUpdate<Stmt, Target> {
}Copy)]
852pub struct IncompleteDoUpdate<Stmt, Target> {
853    stmt: Stmt,
854    target: Target,
855}
856
857impl<T: QuerySource, U, Op, Ret, Target>
858    IncompleteDoUpdate<InsertStatement<T, U, Op, Ret>, Target>
859{
860    /// See [`do_update`] for usage examples.
861    ///
862    /// [`do_update`]: IncompleteOnConflict::do_update()
863    pub fn set<Changes>(self, changes: Changes) -> crate::dsl::Set<Self, Changes>
864    where
865        T: QuerySource,
866        Changes: AsChangeset<Target = T>,
867    {
868        let target = self.target;
869        self.stmt.replace_values(|values| {
870            OnConflictValues::new(
871                values,
872                target,
873                DoUpdate::new(changes.as_changeset()),
874                NoWhereClause,
875            )
876        })
877    }
878}
879
880impl<T, U, Op, Ret, Target, Action, WhereClause, Predicate> FilterDsl<Predicate>
881    for InsertStatement<T, OnConflictValues<U, Target, Action, WhereClause>, Op, Ret>
882where
883    T: QuerySource,
884    WhereClause: WhereAnd<Predicate>,
885{
886    type Output =
887        InsertStatement<T, OnConflictValues<U, Target, Action, WhereClause::Output>, Op, Ret>;
888
889    fn filter(self, predicate: Predicate) -> Self::Output {
890        self.replace_values(|values| {
891            values.replace_where(|where_clause| where_clause.and(predicate))
892        })
893    }
894}
895
896impl<T, U, Op, Ret, Target, Action, WhereClause, Predicate> OrFilterDsl<Predicate>
897    for InsertStatement<T, OnConflictValues<U, Target, Action, WhereClause>, Op, Ret>
898where
899    T: QuerySource,
900    WhereClause: WhereOr<Predicate>,
901{
902    type Output =
903        InsertStatement<T, OnConflictValues<U, Target, Action, WhereClause::Output>, Op, Ret>;
904
905    fn or_filter(self, predicate: Predicate) -> Self::Output {
906        self.replace_values(|values| {
907            values.replace_where(|where_clause| where_clause.or(predicate))
908        })
909    }
910}