diesel/upsert/
on_conflict_extension.rs

1use crate::expression::Expression;
2use crate::query_builder::upsert::into_conflict_clause::IntoConflictValueClause;
3use crate::query_builder::upsert::on_conflict_actions::*;
4use crate::query_builder::upsert::on_conflict_clause::*;
5use crate::query_builder::upsert::on_conflict_target::*;
6pub use crate::query_builder::upsert::on_conflict_target_decorations::DecoratableTarget;
7use crate::query_builder::where_clause::{NoWhereClause, WhereAnd, WhereOr};
8use crate::query_builder::{AsChangeset, InsertStatement, UndecoratedInsertRecord};
9use crate::query_dsl::filter_dsl::FilterDsl;
10use crate::query_dsl::methods::OrFilterDsl;
11use crate::query_source::QuerySource;
12use crate::sql_types::BoolOrNullableBool;
13
14impl<T, U, Op, Ret> InsertStatement<T, U, Op, Ret>
15where
16    T: QuerySource,
17    U: UndecoratedInsertRecord<T> + IntoConflictValueClause,
18{
19    /// Adds `ON CONFLICT DO NOTHING` to the insert statement, without
20    /// specifying any columns or constraints to restrict the conflict to.
21    ///
22    /// # Examples
23    ///
24    /// ### Single Record
25    ///
26    /// ```rust
27    /// # include!("on_conflict_docs_setup.rs");
28    /// #
29    /// # fn main() {
30    /// #     run_test().unwrap()
31    /// # }
32    /// # fn run_test() -> QueryResult<()> {
33    /// #     use self::users::dsl::*;
34    /// #     let conn = &mut establish_connection();
35    /// #     #[cfg(feature = "postgres")]
36    /// #     diesel::sql_query("TRUNCATE TABLE users").execute(conn).unwrap();
37    /// #     #[cfg(any(feature = "sqlite", feature = "mysql"))]
38    /// #     diesel::sql_query("DELETE FROM users").execute(conn).unwrap();
39    /// let user = User {
40    ///     id: 1,
41    ///     name: "Sean",
42    /// };
43    ///
44    /// let user_count = users.count().get_result::<i64>(conn)?;
45    /// assert_eq!(user_count, 0);
46    ///
47    /// diesel::insert_into(users)
48    ///     .values(&user)
49    ///     .on_conflict_do_nothing()
50    ///     .execute(conn)?;
51    /// let user_count = users.count().get_result::<i64>(conn)?;
52    /// assert_eq!(user_count, 1);
53    ///
54    /// diesel::insert_into(users)
55    ///     .values(&user)
56    ///     .on_conflict_do_nothing()
57    ///     .execute(conn)?;
58    /// let user_count = users.count().get_result::<i64>(conn)?;
59    /// assert_eq!(user_count, 1);
60    /// # Ok(())
61    /// # }
62    /// ```
63    ///
64    /// ### Vec of Records
65    ///
66    /// ```rust
67    /// # include!("on_conflict_docs_setup.rs");
68    /// #
69    /// # fn main() {
70    /// #     run_test().unwrap()
71    /// # }
72    /// #
73    /// # fn run_test() -> diesel::QueryResult<()> {
74    /// #     use self::users::dsl::*;
75    /// #     let conn = &mut establish_connection();
76    /// #     #[cfg(feature = "postgres")]
77    /// #     diesel::sql_query("TRUNCATE TABLE users").execute(conn).unwrap();
78    /// #     #[cfg(any(feature = "mysql", feature = "sqlite"))]
79    /// #     diesel::sql_query("DELETE FROM users").execute(conn).unwrap();
80    /// # #[cfg(any(feature = "postgres", feature = "mysql"))]
81    /// let user = User {
82    ///     id: 1,
83    ///     name: "Sean",
84    /// };
85    ///
86    /// # #[cfg(any(feature = "postgres", feature = "mysql"))]
87    /// let inserted_row_count = diesel::insert_into(users)
88    ///     .values(&vec![user, user])
89    ///     .on_conflict_do_nothing()
90    ///     .execute(conn)?;
91    /// # #[cfg(any(feature = "postgres", feature = "mysql"))]
92    /// let user_count = users.count().get_result::<i64>(conn)?;
93    /// # #[cfg(any(feature = "postgres", feature = "mysql"))]
94    /// assert_eq!(user_count, 1);
95    /// # Ok(())
96    /// # }
97    /// ```
98    pub fn on_conflict_do_nothing(
99        self,
100    ) -> InsertStatement<T, OnConflictValues<U::ValueClause, NoConflictTarget, DoNothing<T>>, Op, Ret>
101    {
102        self.replace_values(|values| OnConflictValues::do_nothing(values.into_value_clause()))
103    }
104
105    /// Adds an `ON CONFLICT` to the insert statement, if a conflict occurs
106    /// for the given unique constraint.
107    ///
108    /// `Target` can be one of:
109    ///
110    /// - A column
111    /// - A tuple of columns
112    /// - [`on_constraint("constraint_name")`][`on_constraint`]
113    ///
114    /// # Examples
115    ///
116    /// ### Specifying a column as the target
117    ///
118    /// This is supported by sqlite and postgres only
119    ///
120    /// ```rust
121    /// # include!("../doctest_setup.rs");
122    /// #
123    /// # table! {
124    /// #     users {
125    /// #         id -> Integer,
126    /// #         name -> VarChar,
127    /// #         hair_color -> VarChar,
128    /// #     }
129    /// # }
130    /// #
131    /// # #[derive(Clone, Copy, Insertable)]
132    /// # #[diesel(table_name = users)]
133    /// # struct User<'a> {
134    /// #     id: i32,
135    /// #     name: &'a str,
136    /// # }
137    /// #
138    /// # fn main() {
139    /// #    run_test().unwrap()
140    /// # }
141    /// # #[cfg(any(feature = "postgres", feature = "sqlite"))]
142    /// # fn run_test() -> diesel::QueryResult<()> {
143    /// #     use self::users::dsl::*;
144    /// use diesel::upsert::*;
145    ///
146    /// #     let conn = &mut establish_connection();
147    /// #     #[cfg(any(feature = "sqlite", feature = "postgres"))]
148    /// #     diesel::sql_query("DROP TABLE users").execute(conn).unwrap();
149    /// #     #[cfg(any(feature = "sqlite", feature = "postgres"))]
150    /// #     diesel::sql_query("CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT)").execute(conn).unwrap();
151    /// diesel::sql_query("CREATE UNIQUE INDEX users_name ON users (name)").execute(conn).unwrap();
152    /// let user = User { id: 1, name: "Sean" };
153    /// let same_name_different_id = User { id: 2, name: "Sean" };
154    /// let same_id_different_name = User { id: 1, name: "Pascal" };
155    /// assert_eq!(Ok(1), diesel::insert_into(users).values(&user).execute(conn));
156    ///
157    /// let query = diesel::insert_into(users)
158    ///     .values(&same_id_different_name)
159    ///     .on_conflict(id)
160    ///     .do_nothing()
161    ///     .execute(conn)?;
162    ///
163    /// let user_names = users.select(name).load::<String>(conn)?;
164    /// assert_eq!(user_names, vec![String::from("Sean")]);
165    ///
166    /// let idx_conflict_result = diesel::insert_into(users)
167    ///     .values(&same_name_different_id)
168    ///     .on_conflict(id)
169    ///     .do_nothing()
170    ///     .execute(conn);
171    /// assert!(idx_conflict_result.is_err());
172    /// # Ok(())
173    /// # }
174    /// #[cfg(feature = "mysql")]
175    /// fn run_test() -> diesel::QueryResult<()> { Ok(()) }
176    /// ```
177    ///
178    /// ### Specifying multiple columns as the target
179    ///
180    /// This is supported by sqlite and postgres only
181    ///
182    /// ```rust
183    /// # include!("../doctest_setup.rs");
184    /// #
185    /// # table! {
186    /// #     users {
187    /// #         id -> Integer,
188    /// #         name -> VarChar,
189    /// #         hair_color -> VarChar,
190    /// #     }
191    /// # }
192    /// #
193    /// # #[derive(Clone, Copy, Insertable)]
194    /// # #[diesel(table_name = users)]
195    /// # struct User<'a> {
196    /// #     id: i32,
197    /// #     name: &'a str,
198    /// #     hair_color: &'a str,
199    /// # }
200    /// #
201    /// # #[cfg(any(feature = "sqlite", feature = "postgres"))]
202    /// # fn main() {
203    /// #     use self::users::dsl::*;
204    /// use diesel::upsert::*;
205    ///
206    /// #     let conn = &mut establish_connection();
207    /// #     diesel::sql_query("DROP TABLE users").execute(conn).unwrap();
208    /// #     diesel::sql_query("CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT, hair_color TEXT)").execute(conn).unwrap();
209    /// diesel::sql_query("CREATE UNIQUE INDEX users_name_hair_color ON users (name, hair_color)").execute(conn).unwrap();
210    /// let user = User { id: 1, name: "Sean", hair_color: "black" };
211    /// let same_name_different_hair_color = User { id: 2, name: "Sean", hair_color: "brown" };
212    /// let same_name_same_hair_color = User { id: 3, name: "Sean", hair_color: "black" };
213    ///
214    /// assert_eq!(Ok(1), diesel::insert_into(users).values(&user).execute(conn));
215    ///
216    /// let inserted_row_count = diesel::insert_into(users)
217    ///     .values(&same_name_different_hair_color)
218    ///     .on_conflict((name, hair_color))
219    ///     .do_nothing()
220    ///     .execute(conn);
221    /// assert_eq!(Ok(1), inserted_row_count);
222    ///
223    /// let inserted_row_count = diesel::insert_into(users)
224    ///     .values(&same_name_same_hair_color)
225    ///     .on_conflict((name, hair_color))
226    ///     .do_nothing()
227    ///     .execute(conn);
228    /// assert_eq!(Ok(0), inserted_row_count);
229    /// # }
230    ///
231    /// #[cfg(feature = "mysql")]
232    /// fn main() {}
233    /// ```
234    ///
235    /// ### ON DUPLICATE KEY
236    ///
237    /// Mysql supports only catching all duplicated keys at once:
238    ///
239    /// ```
240    /// # include!("../doctest_setup.rs");
241    /// #
242    /// # table! {
243    /// #     users {
244    /// #         id -> Integer,
245    /// #         name -> VarChar,
246    /// #         hair_color -> VarChar,
247    /// #     }
248    /// # }
249    /// #
250    /// # #[derive(Clone, Copy, Insertable)]
251    /// # #[diesel(table_name = users)]
252    /// # struct User<'a> {
253    /// #     id: i32,
254    /// #     name: &'a str,
255    /// # }
256    /// #
257    /// # fn main() {
258    /// #    run_test().unwrap()
259    /// # }
260    /// # #[cfg(feature = "mysql")]
261    /// # fn run_test() -> diesel::QueryResult<()> {
262    /// #     use self::users::dsl::*;
263    /// use diesel::upsert::*;
264    ///
265    /// #     let conn = &mut establish_connection();
266    /// #     diesel::sql_query("DROP TABLE users").execute(conn).unwrap();
267    /// #     diesel::sql_query("CREATE TEMPORARY TABLE users (id SERIAL PRIMARY KEY, name VARCHAR(255), hair_color VARCHAR(255))").execute(conn).unwrap();
268    /// diesel::sql_query("CREATE UNIQUE INDEX users_name ON users (name)").execute(conn).unwrap();
269    /// let user = User { id: 1, name: "Sean" };
270    /// let same_name_different_id = User { id: 2, name: "Sean" };
271    /// let same_id_different_name = User { id: 1, name: "Pascal" };
272    ///
273    /// assert_eq!(Ok(1), diesel::insert_into(users).values(&user).execute(conn));
274    ///
275    /// # diesel::delete(users.filter(name.ne("Sean"))).execute(conn)?;
276    /// let user_names = users.select(name).load::<String>(conn)?;
277    /// assert_eq!(user_names, vec![String::from("Sean")]);
278    ///
279    /// let query = diesel::insert_into(users)
280    ///     .values(&same_id_different_name)
281    ///     .on_conflict(diesel::dsl::DuplicatedKeys)
282    ///     .do_nothing()
283    ///     .execute(conn)?;
284    ///
285    /// let user_names = users.select(name).load::<String>(conn)?;
286    /// assert_eq!(user_names, vec![String::from("Sean")]);
287    ///
288    /// let idx_conflict_result = diesel::insert_into(users)
289    ///     .values(&same_name_different_id)
290    ///     .on_conflict(diesel::dsl::DuplicatedKeys)
291    ///     .do_nothing()
292    ///     .execute(conn)?;
293    ///
294    /// let user_names = users.select(name).load::<String>(conn)?;
295    /// assert_eq!(user_names, vec![String::from("Sean")]);
296    /// # Ok(())
297    /// # }
298    /// #[cfg(not(feature = "mysql"))]
299    /// fn run_test() -> diesel::QueryResult<()> {Ok(())}
300    /// ```
301    ///
302    /// See the documentation for [`on_constraint`] and [`do_update`] for
303    /// more examples.
304    ///
305    /// [`on_constraint`]: ../upsert/fn.on_constraint.html
306    /// [`do_update`]: crate::upsert::IncompleteOnConflict::do_update()
307    pub fn on_conflict<Target>(
308        self,
309        target: Target,
310    ) -> IncompleteOnConflict<InsertStatement<T, U::ValueClause, Op, Ret>, ConflictTarget<Target>>
311    where
312        ConflictTarget<Target>: OnConflictTarget<T>,
313    {
314        IncompleteOnConflict {
315            stmt: self.replace_values(IntoConflictValueClause::into_value_clause),
316            target: ConflictTarget(target),
317        }
318    }
319}
320
321impl<Stmt, T, P> DecoratableTarget<P> for IncompleteOnConflict<Stmt, T>
322where
323    P: Expression,
324    P::SqlType: BoolOrNullableBool,
325    T: DecoratableTarget<P>,
326{
327    type FilterOutput = IncompleteOnConflict<Stmt, <T as DecoratableTarget<P>>::FilterOutput>;
328    fn filter_target(self, predicate: P) -> Self::FilterOutput {
329        IncompleteOnConflict {
330            stmt: self.stmt,
331            target: self.target.filter_target(predicate),
332        }
333    }
334}
335
336/// A partially constructed `ON CONFLICT` clause.
337#[derive(Debug, Clone, Copy)]
338pub struct IncompleteOnConflict<Stmt, Target> {
339    stmt: Stmt,
340    target: Target,
341}
342
343impl<T: QuerySource, U, Op, Ret, Target>
344    IncompleteOnConflict<InsertStatement<T, U, Op, Ret>, Target>
345{
346    /// Creates a query with `ON CONFLICT (target) DO NOTHING`
347    ///
348    /// If you want to do nothing when *any* constraint conflicts, use
349    /// [`on_conflict_do_nothing`] instead. See [`on_conflict`] for usage
350    /// examples.
351    ///
352    /// [`on_conflict_do_nothing`]: crate::query_builder::InsertStatement::on_conflict_do_nothing()
353    /// [`on_conflict`]: crate::query_builder::InsertStatement::on_conflict()
354    pub fn do_nothing(
355        self,
356    ) -> InsertStatement<T, OnConflictValues<U, Target, DoNothing<T>>, Op, Ret> {
357        let target = self.target;
358        self.stmt.replace_values(|values| {
359            OnConflictValues::new(values, target, DoNothing::new(), NoWhereClause)
360        })
361    }
362}
363
364impl<Stmt, Target> IncompleteOnConflict<Stmt, Target> {
365    /// Used to create a query in the form `ON CONFLICT (...) DO UPDATE ... [WHERE ...]`
366    ///
367    /// Call `.set` on the result of this function with the changes you want to
368    /// apply. The argument to `set` can be anything that implements `AsChangeset`
369    /// (e.g. anything you could pass to `set` on a normal update statement).
370    ///
371    /// Note: When inserting more than one row at a time, this query can still fail
372    /// if the rows being inserted conflict with each other.
373    ///
374    /// For some backends (PostgreSQL, SQLite) a `WHERE` clause can be used to limit the rows actually updated.
375    /// For PostgreSQL and SQLite you can use the `.filter()` method to add conditions like that.
376    ///
377    /// # Examples
378    ///
379    /// ## Set specific value on conflict
380    ///
381    /// PostgreSQL/SQLite:
382    ///
383    /// ```rust
384    /// # include!("on_conflict_docs_setup.rs");
385    /// #
386    /// # #[cfg(not(feature = "mysql"))]
387    /// # fn main() {
388    /// #     use self::users::dsl::*;
389    /// #     let conn = &mut establish_connection();
390    /// #     #[cfg(feature = "postgres")]
391    /// #     diesel::sql_query("TRUNCATE TABLE users").execute(conn).unwrap();
392    /// #     #[cfg(feature = "sqlite")]
393    /// #     diesel::sql_query("DELETE FROM users").execute(conn).unwrap();
394    /// let user = User {
395    ///     id: 1,
396    ///     name: "Pascal",
397    /// };
398    /// let user2 = User {
399    ///     id: 1,
400    ///     name: "Sean",
401    /// };
402    ///
403    /// assert_eq!(
404    ///     Ok(1),
405    ///     diesel::insert_into(users).values(&user).execute(conn)
406    /// );
407    ///
408    /// let insert_count = diesel::insert_into(users)
409    ///     .values(&user2)
410    ///     .on_conflict(id)
411    ///     .do_update()
412    ///     .set(name.eq("I DONT KNOW ANYMORE"))
413    ///     .execute(conn);
414    /// # #[cfg(any(feature = "sqlite", feature = "postgres"))]
415    /// assert_eq!(Ok(1), insert_count);
416    /// # #[cfg(feature = "mysql")]
417    /// assert_eq!(Ok(2), insert_count);
418    ///
419    /// let users_in_db = users.load(conn);
420    /// assert_eq!(
421    ///     Ok(vec![(1, "I DONT KNOW ANYMORE".to_string())]),
422    ///     users_in_db
423    /// );
424    /// # }
425    /// # #[cfg(feature = "mysql")]
426    /// # fn main() {}
427    /// ```
428    ///
429    /// MySQL:
430    ///
431    /// ```rust
432    /// # include!("on_conflict_docs_setup.rs");
433    /// #
434    /// # #[cfg(feature = "mysql")]
435    /// # fn main() -> diesel::QueryResult<()> {
436    /// #     use self::users::dsl::*;
437    /// #     let conn = &mut establish_connection();
438    /// #     diesel::sql_query("DELETE FROM users").execute(conn).unwrap();
439    /// let user = User {
440    ///     id: 1,
441    ///     name: "Pascal",
442    /// };
443    /// let user2 = User {
444    ///     id: 1,
445    ///     name: "Sean",
446    /// };
447    ///
448    /// assert_eq!(
449    ///     Ok(1),
450    ///     diesel::insert_into(users).values(&user).execute(conn)
451    /// );
452    ///
453    /// diesel::insert_into(users)
454    ///     .values(&user2)
455    ///     .on_conflict(diesel::dsl::DuplicatedKeys)
456    ///     .do_update()
457    ///     .set(name.eq("I DONT KNOW ANYMORE"))
458    ///     .execute(conn)?;
459    ///
460    /// let users_in_db = users.load(conn);
461    /// assert_eq!(
462    ///     Ok(vec![(1, "I DONT KNOW ANYMORE".to_string())]),
463    ///     users_in_db
464    /// );
465    /// # Ok(())
466    /// # }
467    /// # #[cfg(not(feature = "mysql"))]
468    /// # fn main() {}
469    /// ```
470    ///
471    /// ## Set `AsChangeset` struct on conflict
472    ///
473    /// PostgreSQL & SQLite:
474    ///
475    /// ```rust
476    /// # include!("on_conflict_docs_setup.rs");
477    /// #
478    /// # #[cfg(not(feature = "mysql"))]
479    /// # fn main() {
480    /// #     use self::users::dsl::*;
481    /// #     let conn = &mut establish_connection();
482    /// #     #[cfg(feature = "postgres")]
483    /// #     diesel::sql_query("TRUNCATE TABLE users").execute(conn).unwrap();
484    /// #     #[cfg(feature = "sqlite")]
485    /// #     diesel::sql_query("DELETE FROM users").execute(conn).unwrap();
486    /// let user = User {
487    ///     id: 1,
488    ///     name: "Pascal",
489    /// };
490    /// let user2 = User {
491    ///     id: 1,
492    ///     name: "Sean",
493    /// };
494    ///
495    /// assert_eq!(
496    ///     Ok(1),
497    ///     diesel::insert_into(users).values(&user).execute(conn)
498    /// );
499    ///
500    /// let insert_count = diesel::insert_into(users)
501    ///     .values(&user2)
502    ///     .on_conflict(id)
503    ///     .do_update()
504    ///     .set(&user2)
505    ///     .execute(conn);
506    /// assert_eq!(Ok(1), insert_count);
507    ///
508    /// let users_in_db = users.load(conn);
509    /// assert_eq!(Ok(vec![(1, "Sean".to_string())]), users_in_db);
510    /// # }
511    /// # #[cfg(feature = "mysql")]
512    /// # fn main() {}
513    /// ```
514    ///
515    /// MySQL:
516    ///
517    /// ```rust
518    /// # include!("on_conflict_docs_setup.rs");
519    ///
520    /// # #[cfg(feature = "mysql")]
521    /// # fn main() -> diesel::QueryResult<()> {
522    /// #     use self::users::dsl::*;
523    /// #     let conn = &mut establish_connection();
524    /// #     diesel::sql_query("DELETE FROM users").execute(conn).unwrap();
525    /// let user = User {
526    ///     id: 1,
527    ///     name: "Pascal",
528    /// };
529    /// let user2 = User {
530    ///     id: 1,
531    ///     name: "Sean",
532    /// };
533    ///
534    /// assert_eq!(
535    ///     Ok(1),
536    ///     diesel::insert_into(users).values(&user).execute(conn)
537    /// );
538    ///
539    /// diesel::insert_into(users)
540    ///     .values(&user2)
541    ///     .on_conflict(diesel::dsl::DuplicatedKeys)
542    ///     .do_update()
543    ///     .set(&user2)
544    ///     .execute(conn)?;
545    ///
546    /// let users_in_db = users.load(conn);
547    /// assert_eq!(Ok(vec![(1, "Sean".to_string())]), users_in_db);
548    /// # Ok(())
549    /// # }
550    ///
551    /// # #[cfg(not(feature = "mysql"))]
552    /// # fn main() {}
553    /// ```
554    ///
555    /// ## Use `excluded` to get the rejected value
556    ///
557    /// ```rust
558    /// # include!("on_conflict_docs_setup.rs");
559    /// #
560    /// # #[cfg(any(feature = "sqlite", feature = "postgres"))]
561    /// # fn main() {
562    /// #     use self::users::dsl::*;
563    /// use diesel::upsert::excluded;
564    ///
565    /// #     let conn = &mut establish_connection();
566    /// #     #[cfg(feature = "postgres")]
567    /// #     diesel::sql_query("TRUNCATE TABLE users").execute(conn).unwrap();
568    /// let user = User {
569    ///     id: 1,
570    ///     name: "Pascal",
571    /// };
572    /// let user2 = User {
573    ///     id: 1,
574    ///     name: "Sean",
575    /// };
576    /// let user3 = User {
577    ///     id: 2,
578    ///     name: "Tess",
579    /// };
580    ///
581    /// # #[cfg(feature = "postgres")]
582    /// assert_eq!(
583    ///     Ok(1),
584    ///     diesel::insert_into(users).values(&user).execute(conn)
585    /// );
586    ///
587    /// #[cfg(feature = "postgres")]
588    /// let insert_count = diesel::insert_into(users)
589    ///     .values(&vec![user2, user3])
590    ///     .on_conflict(id)
591    ///     .do_update()
592    ///     .set(name.eq(excluded(name)))
593    ///     .execute(conn);
594    /// # #[cfg(feature = "postgres")]
595    /// assert_eq!(Ok(2), insert_count);
596    ///
597    /// # #[cfg(feature = "postgres")]
598    /// let users_in_db = users.load(conn);
599    /// # #[cfg(feature = "postgres")]
600    /// assert_eq!(
601    ///     Ok(vec![(1, "Sean".to_string()), (2, "Tess".to_string())]),
602    ///     users_in_db
603    /// );
604    /// # }
605    /// # #[cfg(feature = "mysql")]
606    /// # fn main() {}
607    /// ```
608    ///
609    /// ## Use `.filter()`method to limit the rows actually updated
610    ///
611    /// ```rust
612    /// # include!("on_conflict_docs_setup.rs");
613    /// #
614    /// # #[cfg(not(feature = "mysql"))]
615    /// # fn main() {
616    /// #     use diesel::QueryDsl;
617    /// #     use diesel::query_dsl::methods::FilterDsl;
618    /// use self::users::dsl::*;
619    /// #     let conn = &mut establish_connection();
620    /// #     #[cfg(feature = "postgres")]
621    /// #     diesel::sql_query("TRUNCATE TABLE users").execute(conn).unwrap();
622    /// #     #[cfg(feature = "sqlite")]
623    /// #     diesel::delete(users).execute(conn).unwrap();
624    /// let user = User {
625    ///     id: 1,
626    ///     name: "Pascal",
627    /// };
628    /// let user2 = User {
629    ///     id: 1,
630    ///     name: "Sean",
631    /// };
632    ///
633    /// assert_eq!(
634    ///     Ok(1),
635    ///     diesel::insert_into(users).values(&user).execute(conn)
636    /// );
637    ///
638    /// let insert_count = diesel::insert_into(users)
639    ///     .values(&user2)
640    ///     .on_conflict(id)
641    ///     .do_update()
642    ///     .set(&user2)
643    ///     .filter(id.ge(5))
644    ///     .execute(conn);
645    /// assert_eq!(Ok(0), insert_count);
646    ///
647    /// let users_in_db = users.load(conn);
648    /// assert_eq!(Ok(vec![(1, "Pascal".to_string())]), users_in_db);
649    /// # }
650    /// # #[cfg(feature = "mysql")]
651    /// # fn main() {}
652    /// ```
653    pub fn do_update(self) -> IncompleteDoUpdate<Stmt, Target> {
654        IncompleteDoUpdate {
655            stmt: self.stmt,
656            target: self.target,
657        }
658    }
659}
660
661/// A partially constructed `ON CONFLICT DO UPDATE` clause.
662#[derive(Debug, Clone, Copy)]
663pub struct IncompleteDoUpdate<Stmt, Target> {
664    stmt: Stmt,
665    target: Target,
666}
667
668impl<T: QuerySource, U, Op, Ret, Target>
669    IncompleteDoUpdate<InsertStatement<T, U, Op, Ret>, Target>
670{
671    /// See [`do_update`] for usage examples.
672    ///
673    /// [`do_update`]: IncompleteOnConflict::do_update()
674    pub fn set<Changes>(
675        self,
676        changes: Changes,
677    ) -> InsertStatement<T, OnConflictValues<U, Target, DoUpdate<Changes::Changeset, T>>, Op, Ret>
678    where
679        T: QuerySource,
680        Changes: AsChangeset<Target = T>,
681    {
682        let target = self.target;
683        self.stmt.replace_values(|values| {
684            OnConflictValues::new(
685                values,
686                target,
687                DoUpdate::new(changes.as_changeset()),
688                NoWhereClause,
689            )
690        })
691    }
692}
693
694impl<T, U, Op, Ret, Target, Action, WhereClause, Predicate> FilterDsl<Predicate>
695    for InsertStatement<T, OnConflictValues<U, Target, Action, WhereClause>, Op, Ret>
696where
697    T: QuerySource,
698    WhereClause: WhereAnd<Predicate>,
699{
700    type Output =
701        InsertStatement<T, OnConflictValues<U, Target, Action, WhereClause::Output>, Op, Ret>;
702
703    fn filter(self, predicate: Predicate) -> Self::Output {
704        self.replace_values(|values| {
705            values.replace_where(|where_clause| where_clause.and(predicate))
706        })
707    }
708}
709
710impl<T, U, Op, Ret, Target, Action, WhereClause, Predicate> OrFilterDsl<Predicate>
711    for InsertStatement<T, OnConflictValues<U, Target, Action, WhereClause>, Op, Ret>
712where
713    T: QuerySource,
714    WhereClause: WhereOr<Predicate>,
715{
716    type Output =
717        InsertStatement<T, OnConflictValues<U, Target, Action, WhereClause::Output>, Op, Ret>;
718
719    fn or_filter(self, predicate: Predicate) -> Self::Output {
720        self.replace_values(|values| {
721            values.replace_where(|where_clause| where_clause.or(predicate))
722        })
723    }
724}