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}