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