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