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