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("DROP TABLE users").execute(conn).unwrap();
261    /// #     diesel::sql_query("CREATE TEMPORARY TABLE users (id SERIAL PRIMARY KEY, name VARCHAR(255), hair_color VARCHAR(255))").execute(conn).unwrap();
262    /// diesel::sql_query("CREATE UNIQUE INDEX users_name ON users (name)").execute(conn).unwrap();
263    /// let user = User { id: 1, name: "Sean" };
264    /// let same_name_different_id = User { id: 2, name: "Sean" };
265    /// let same_id_different_name = User { id: 1, name: "Pascal" };
266    ///
267    /// assert_eq!(Ok(1), diesel::insert_into(users).values(&user).execute(conn));
268    ///
269    /// # diesel::delete(users.filter(name.ne("Sean"))).execute(conn)?;
270    /// let user_names = users.select(name).load::<String>(conn)?;
271    /// assert_eq!(user_names, vec![String::from("Sean")]);
272    ///
273    /// let query = diesel::insert_into(users)
274    ///     .values(&same_id_different_name)
275    ///     .on_conflict(diesel::dsl::DuplicatedKeys)
276    ///     .do_nothing()
277    ///     .execute(conn)?;
278    ///
279    /// let user_names = users.select(name).load::<String>(conn)?;
280    /// assert_eq!(user_names, vec![String::from("Sean")]);
281    ///
282    /// let idx_conflict_result = diesel::insert_into(users)
283    ///     .values(&same_name_different_id)
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    /// # Ok(())
291    /// # }
292    /// #[cfg(not(feature = "mysql"))]
293    /// fn run_test() -> diesel::QueryResult<()> {Ok(())}
294    /// ```
295    ///
296    /// See the documentation for [`on_constraint`] and [`do_update`] for
297    /// more examples.
298    ///
299    /// [`on_constraint`]: ../upsert/fn.on_constraint.html
300    /// [`do_update`]: crate::upsert::IncompleteOnConflict::do_update()
301    pub fn on_conflict<Target>(
302        self,
303        target: Target,
304    ) -> IncompleteOnConflict<InsertStatement<T, U::ValueClause, Op, Ret>, ConflictTarget<Target>>
305    where
306        ConflictTarget<Target>: OnConflictTarget<T>,
307    {
308        IncompleteOnConflict {
309            stmt: self.replace_values(IntoConflictValueClause::into_value_clause),
310            target: ConflictTarget(target),
311        }
312    }
313}
314
315impl<Stmt, T, P> DecoratableTarget<P> for IncompleteOnConflict<Stmt, T>
316where
317    P: Expression,
318    P::SqlType: BoolOrNullableBool,
319    T: DecoratableTarget<P>,
320{
321    type FilterOutput = IncompleteOnConflict<Stmt, <T as DecoratableTarget<P>>::FilterOutput>;
322    fn filter_target(self, predicate: P) -> Self::FilterOutput {
323        IncompleteOnConflict {
324            stmt: self.stmt,
325            target: self.target.filter_target(predicate),
326        }
327    }
328}
329
330/// A partially constructed `ON CONFLICT` clause.
331#[derive(Debug, Clone, Copy)]
332pub struct IncompleteOnConflict<Stmt, Target> {
333    stmt: Stmt,
334    target: Target,
335}
336
337impl<T: QuerySource, U, Op, Ret, Target>
338    IncompleteOnConflict<InsertStatement<T, U, Op, Ret>, Target>
339{
340    /// Creates a query with `ON CONFLICT (target) DO NOTHING`
341    ///
342    /// If you want to do nothing when *any* constraint conflicts, use
343    /// [`on_conflict_do_nothing`] instead. See [`on_conflict`] for usage
344    /// examples.
345    ///
346    /// [`on_conflict_do_nothing`]: crate::query_builder::InsertStatement::on_conflict_do_nothing()
347    /// [`on_conflict`]: crate::query_builder::InsertStatement::on_conflict()
348    pub fn do_nothing(
349        self,
350    ) -> InsertStatement<T, OnConflictValues<U, Target, DoNothing<T>>, Op, Ret> {
351        let target = self.target;
352        self.stmt.replace_values(|values| {
353            OnConflictValues::new(values, target, DoNothing::new(), NoWhereClause)
354        })
355    }
356}
357
358impl<Stmt, Target> IncompleteOnConflict<Stmt, Target> {
359    /// Used to create a query in the form `ON CONFLICT (...) DO UPDATE ... [WHERE ...]`
360    ///
361    /// Call `.set` on the result of this function with the changes you want to
362    /// apply. The argument to `set` can be anything that implements `AsChangeset`
363    /// (e.g. anything you could pass to `set` on a normal update statement).
364    ///
365    /// Note: When inserting more than one row at a time, this query can still fail
366    /// if the rows being inserted conflict with each other.
367    ///
368    /// Some backends (PostgreSQL) support `WHERE` clause is used to limit the rows actually updated.
369    /// For PostgreSQL you can use the `.filter()` method to add conditions like this.
370    ///
371    /// # Examples
372    ///
373    /// ## Set specific value on conflict
374    ///
375    /// PostgreSQL/SQLite:
376    ///
377    /// ```rust
378    /// # include!("on_conflict_docs_setup.rs");
379    /// #
380    /// # #[cfg(not(feature = "mysql"))]
381    /// # fn main() {
382    /// #     use self::users::dsl::*;
383    /// #     let conn = &mut establish_connection();
384    /// #     #[cfg(feature = "postgres")]
385    /// #     diesel::sql_query("TRUNCATE TABLE users").execute(conn).unwrap();
386    /// #     #[cfg(feature = "sqlite")]
387    /// #     diesel::sql_query("DELETE FROM users").execute(conn).unwrap();
388    /// let user = User { id: 1, name: "Pascal" };
389    /// let user2 = User { id: 1, name: "Sean" };
390    ///
391    /// assert_eq!(Ok(1), diesel::insert_into(users).values(&user).execute(conn));
392    ///
393    /// let insert_count = diesel::insert_into(users)
394    ///     .values(&user2)
395    ///     .on_conflict(id)
396    ///     .do_update()
397    ///     .set(name.eq("I DONT KNOW ANYMORE"))
398    ///     .execute(conn);
399    /// # #[cfg(any(feature = "sqlite", feature = "postgres"))]
400    /// assert_eq!(Ok(1), insert_count);
401    /// # #[cfg(feature = "mysql")]
402    /// assert_eq!(Ok(2), insert_count);
403    ///
404    /// let users_in_db = users.load(conn);
405    /// assert_eq!(Ok(vec![(1, "I DONT KNOW ANYMORE".to_string())]), users_in_db);
406    /// # }
407    /// # #[cfg(feature = "mysql")]
408    /// # fn main() {}
409    /// ```
410    ///
411    /// MySQL:
412    ///
413    /// ```rust
414    /// # include!("on_conflict_docs_setup.rs");
415    /// #
416    /// # #[cfg(feature = "mysql")]
417    /// # fn main() -> diesel::QueryResult<()> {
418    /// #     use self::users::dsl::*;
419    /// #     let conn = &mut establish_connection();
420    /// #     diesel::sql_query("DELETE FROM users").execute(conn).unwrap();
421    /// let user = User { id: 1, name: "Pascal" };
422    /// let user2 = User { id: 1, name: "Sean" };
423    ///
424    /// assert_eq!(Ok(1), diesel::insert_into(users).values(&user).execute(conn));
425    ///
426    /// diesel::insert_into(users)
427    ///     .values(&user2)
428    ///     .on_conflict(diesel::dsl::DuplicatedKeys)
429    ///     .do_update()
430    ///     .set(name.eq("I DONT KNOW ANYMORE"))
431    ///     .execute(conn)?;
432    ///
433    /// let users_in_db = users.load(conn);
434    /// assert_eq!(Ok(vec![(1, "I DONT KNOW ANYMORE".to_string())]), users_in_db);
435    /// # Ok(())
436    /// # }
437    /// # #[cfg(not(feature = "mysql"))]
438    /// # fn main() {}
439    /// ```
440    ///
441    /// ## Set `AsChangeset` struct on conflict
442    ///
443    /// PostgreSQL & SQLite:
444    ///
445    /// ```rust
446    /// # include!("on_conflict_docs_setup.rs");
447    /// #
448    /// # #[cfg(not(feature = "mysql"))]
449    /// # fn main() {
450    /// #     use self::users::dsl::*;
451    /// #     let conn = &mut establish_connection();
452    /// #     #[cfg(feature = "postgres")]
453    /// #     diesel::sql_query("TRUNCATE TABLE users").execute(conn).unwrap();
454    /// #     #[cfg(feature = "sqlite")]
455    /// #     diesel::sql_query("DELETE FROM users").execute(conn).unwrap();
456    /// let user = User { id: 1, name: "Pascal" };
457    /// let user2 = User { id: 1, name: "Sean" };
458    ///
459    /// assert_eq!(Ok(1), diesel::insert_into(users).values(&user).execute(conn));
460    ///
461    /// let insert_count = diesel::insert_into(users)
462    ///     .values(&user2)
463    ///     .on_conflict(id)
464    ///     .do_update()
465    ///     .set(&user2)
466    ///     .execute(conn);
467    /// assert_eq!(Ok(1), insert_count);
468    ///
469    /// let users_in_db = users.load(conn);
470    /// assert_eq!(Ok(vec![(1, "Sean".to_string())]), users_in_db);
471    /// # }
472    /// # #[cfg(feature = "mysql")]
473    /// # fn main() {}
474    /// ```
475    ///
476    /// MySQL:
477    ///
478    /// ```rust
479    /// # include!("on_conflict_docs_setup.rs");
480    ///
481    /// # #[cfg(feature = "mysql")]
482    /// # fn main() -> diesel::QueryResult<()> {
483    /// #     use self::users::dsl::*;
484    /// #     let conn = &mut establish_connection();
485    /// #     diesel::sql_query("DELETE FROM users").execute(conn).unwrap();
486    /// let user = User { id: 1, name: "Pascal" };
487    /// let user2 = User { id: 1, name: "Sean" };
488    ///
489    /// assert_eq!(Ok(1), diesel::insert_into(users).values(&user).execute(conn));
490    ///
491    /// diesel::insert_into(users)
492    ///     .values(&user2)
493    ///     .on_conflict(diesel::dsl::DuplicatedKeys)
494    ///     .do_update()
495    ///     .set(&user2)
496    ///     .execute(conn)?;
497    ///
498    /// let users_in_db = users.load(conn);
499    /// assert_eq!(Ok(vec![(1, "Sean".to_string())]), users_in_db);
500    /// # Ok(())
501    /// # }
502    ///
503    /// # #[cfg(not(feature = "mysql"))]
504    /// # fn main() {}
505    /// ```
506    ///
507    /// ## Use `excluded` to get the rejected value
508    ///
509    /// ```rust
510    /// # include!("on_conflict_docs_setup.rs");
511    /// #
512    /// # #[cfg(any(feature = "sqlite", feature = "postgres"))]
513    /// # fn main() {
514    /// #     use self::users::dsl::*;
515    /// use diesel::upsert::excluded;
516    ///
517    /// #     let conn = &mut establish_connection();
518    /// #     #[cfg(feature = "postgres")]
519    /// #     diesel::sql_query("TRUNCATE TABLE users").execute(conn).unwrap();
520    /// let user = User { id: 1, name: "Pascal" };
521    /// let user2 = User { id: 1, name: "Sean" };
522    /// let user3 = User { id: 2, name: "Tess" };
523    ///
524    /// # #[cfg(feature = "postgres")]
525    /// assert_eq!(Ok(1), diesel::insert_into(users).values(&user).execute(conn));
526    ///
527    /// #[cfg(feature = "postgres")]
528    /// let insert_count = diesel::insert_into(users)
529    ///     .values(&vec![user2, user3])
530    ///     .on_conflict(id)
531    ///     .do_update()
532    ///     .set(name.eq(excluded(name)))
533    ///     .execute(conn);
534    /// # #[cfg(feature = "postgres")]
535    /// assert_eq!(Ok(2), insert_count);
536    ///
537    /// # #[cfg(feature = "postgres")]
538    /// let users_in_db = users.load(conn);
539    /// # #[cfg(feature = "postgres")]
540    /// assert_eq!(Ok(vec![(1, "Sean".to_string()), (2, "Tess".to_string())]), users_in_db);
541    /// # }
542    /// # #[cfg(feature = "mysql")]
543    /// # fn main() {}
544    /// ```
545    ///
546    /// ## Use `.filter()`method to limit the rows actually updated
547    ///
548    /// ```rust
549    /// # include!("on_conflict_docs_setup.rs");
550    /// #
551    /// # #[cfg(feature = "postgres")]
552    /// # fn main() {
553    /// #     use diesel::QueryDsl;
554    /// #     use diesel::query_dsl::methods::FilterDsl;
555    /// use self::users::dsl::*;
556    /// #     let conn = &mut establish_connection();
557    /// #     #[cfg(feature = "postgres")]
558    /// #     diesel::sql_query("TRUNCATE TABLE users").execute(conn).unwrap();
559    /// let user = User { id: 1, name: "Pascal" };
560    /// let user2 = User { id: 1, name: "Sean" };
561    ///
562    /// assert_eq!(Ok(1), diesel::insert_into(users).values(&user).execute(conn));
563    ///
564    /// let insert_count = diesel::insert_into(users)
565    ///     .values(&user2)
566    ///     .on_conflict(id)
567    ///     .do_update()
568    ///     .set(&user2)
569    ///     .filter(id.ge(5))
570    ///     .execute(conn);
571    /// assert_eq!(Ok(0), insert_count);
572    ///
573    /// let users_in_db = users.load(conn);
574    /// assert_eq!(Ok(vec![(1, "Pascal".to_string())]), users_in_db);
575    /// # }
576    /// # #[cfg(any(feature = "sqlite", feature = "mysql"))]
577    /// # fn main() {}
578    /// ```
579    pub fn do_update(self) -> IncompleteDoUpdate<Stmt, Target> {
580        IncompleteDoUpdate {
581            stmt: self.stmt,
582            target: self.target,
583        }
584    }
585}
586
587/// A partially constructed `ON CONFLICT DO UPDATE` clause.
588#[derive(Debug, Clone, Copy)]
589pub struct IncompleteDoUpdate<Stmt, Target> {
590    stmt: Stmt,
591    target: Target,
592}
593
594impl<T: QuerySource, U, Op, Ret, Target>
595    IncompleteDoUpdate<InsertStatement<T, U, Op, Ret>, Target>
596{
597    /// See [`do_update`] for usage examples.
598    ///
599    /// [`do_update`]: IncompleteOnConflict::do_update()
600    pub fn set<Changes>(
601        self,
602        changes: Changes,
603    ) -> InsertStatement<T, OnConflictValues<U, Target, DoUpdate<Changes::Changeset, T>>, Op, Ret>
604    where
605        T: QuerySource,
606        Changes: AsChangeset<Target = T>,
607    {
608        let target = self.target;
609        self.stmt.replace_values(|values| {
610            OnConflictValues::new(
611                values,
612                target,
613                DoUpdate::new(changes.as_changeset()),
614                NoWhereClause,
615            )
616        })
617    }
618}
619
620impl<T, U, Op, Ret, Target, Action, WhereClause, Predicate> FilterDsl<Predicate>
621    for InsertStatement<T, OnConflictValues<U, Target, Action, WhereClause>, Op, Ret>
622where
623    T: QuerySource,
624    WhereClause: WhereAnd<Predicate>,
625{
626    type Output =
627        InsertStatement<T, OnConflictValues<U, Target, Action, WhereClause::Output>, Op, Ret>;
628
629    fn filter(self, predicate: Predicate) -> Self::Output {
630        self.replace_values(|values| {
631            values.replace_where(|where_clause| where_clause.and(predicate))
632        })
633    }
634}
635
636impl<T, U, Op, Ret, Target, Action, WhereClause, Predicate> OrFilterDsl<Predicate>
637    for InsertStatement<T, OnConflictValues<U, Target, Action, WhereClause>, Op, Ret>
638where
639    T: QuerySource,
640    WhereClause: WhereOr<Predicate>,
641{
642    type Output =
643        InsertStatement<T, OnConflictValues<U, Target, Action, WhereClause::Output>, Op, Ret>;
644
645    fn or_filter(self, predicate: Predicate) -> Self::Output {
646        self.replace_values(|values| {
647            values.replace_where(|where_clause| where_clause.or(predicate))
648        })
649    }
650}