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