Skip to main content

diesel/query_builder/upsert/
on_conflict_target_decorations.rs

1use crate::backend::Backend;
2use crate::expression::Expression;
3use crate::query_builder::upsert::on_conflict_target::{ConflictTarget, NoConflictTarget};
4use crate::query_builder::where_clause::{NoWhereClause, WhereAnd, WhereClause};
5use crate::query_builder::{AstPass, QueryFragment, QueryResult};
6use crate::sql_types::BoolOrNullableBool;
7
8pub trait UndecoratedConflictTarget {}
9
10impl UndecoratedConflictTarget for NoConflictTarget {}
11impl<T> UndecoratedConflictTarget for ConflictTarget<T> {}
12
13/// Adds a `WHERE` predicate to an `ON CONFLICT` target.
14///
15/// This enables the `ON CONFLICT (target) WHERE predicate DO ...` SQL syntax
16/// on PostgreSQL. PostgreSQL uses the predicate to select which unique index
17/// to match against. Any unique index whose `WHERE` clause is implied by
18/// the predicate qualifies.
19///
20/// Calling `.filter_target()` multiple times combines the predicates with `AND`.
21pub trait DecoratableTarget<P> {
22    /// The type returned by [`filter_target`](DecoratableTarget::filter_target).
23    type FilterOutput;
24    /// Adds a `WHERE` predicate to the `ON CONFLICT` target, telling PostgreSQL
25    /// which unique index to check for conflicts (PostgreSQL only).
26    ///
27    /// This generates `ON CONFLICT (target) WHERE predicate DO ...` SQL.
28    /// PostgreSQL selects unique indexes whose `WHERE` clause is implied by
29    /// the predicate; an exact match is not required.
30    ///
31    /// Calling `.filter_target()` multiple times combines predicates with `AND`.
32    ///
33    /// # Example
34    ///
35    /// ```rust
36    /// # include!("../../upsert/on_conflict_docs_setup.rs");
37    /// # #[cfg(feature = "postgres")]
38    /// # fn main() -> diesel::QueryResult<()> {
39    /// #     use self::users::dsl::*;
40    /// #     let conn = &mut establish_connection();
41    /// #     diesel::sql_query("CREATE UNIQUE INDEX users_name_idx ON users (name)")
42    /// #         .execute(conn)?;
43    /// diesel::insert_into(users)
44    ///     .values(name.eq("Sam"))
45    ///     .execute(conn)?;
46    ///
47    /// diesel::insert_into(users)
48    ///     .values(name.eq("Sam"))
49    ///     .on_conflict(name)
50    ///     .filter_target(name.like("S%"))
51    ///     .do_update()
52    ///     .set(name.eq("Updated"))
53    ///     .execute(conn)?;
54    ///
55    /// let count = users.filter(name.eq("Updated")).count().get_result::<i64>(conn)?;
56    /// assert_eq!(count, 1);
57    /// #     Ok(())
58    /// # }
59    /// # #[cfg(not(feature = "postgres"))]
60    /// # fn main() {}
61    /// ```
62    ///
63    /// For more examples including predicate chaining, see [`IncompleteOnConflict`]'s
64    /// implementation of this trait.
65    ///
66    /// [`IncompleteOnConflict`]: crate::upsert::IncompleteOnConflict
67    fn filter_target(self, predicate: P) -> Self::FilterOutput;
68}
69
70#[derive(#[automatically_derived]
impl<T: ::core::fmt::Debug, U: ::core::fmt::Debug> ::core::fmt::Debug for
    DecoratedConflictTarget<T, U> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f,
            "DecoratedConflictTarget", "target", &self.target, "where_clause",
            &&self.where_clause)
    }
}Debug)]
71pub struct DecoratedConflictTarget<T, U> {
72    pub(crate) target: T,
73    pub(crate) where_clause: U,
74}
75
76impl<T, P> DecoratableTarget<P> for T
77where
78    P: Expression,
79    P::SqlType: BoolOrNullableBool,
80    T: UndecoratedConflictTarget,
81{
82    type FilterOutput = DecoratedConflictTarget<T, WhereClause<P>>;
83
84    fn filter_target(self, predicate: P) -> Self::FilterOutput {
85        DecoratedConflictTarget {
86            target: self,
87            where_clause: NoWhereClause.and(predicate),
88        }
89    }
90}
91
92impl<T, U, P> DecoratableTarget<P> for DecoratedConflictTarget<T, U>
93where
94    P: Expression,
95    P::SqlType: BoolOrNullableBool,
96    U: WhereAnd<P>,
97{
98    type FilterOutput = DecoratedConflictTarget<T, <U as WhereAnd<P>>::Output>;
99
100    fn filter_target(self, predicate: P) -> Self::FilterOutput {
101        DecoratedConflictTarget {
102            target: self.target,
103            where_clause: self.where_clause.and(predicate),
104        }
105    }
106}
107
108impl<DB, T, U> QueryFragment<DB> for DecoratedConflictTarget<T, U>
109where
110    DB: Backend,
111    Self: QueryFragment<DB, DB::OnConflictClause>,
112{
113    fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
114        <Self as QueryFragment<DB, DB::OnConflictClause>>::walk_ast(self, pass)
115    }
116}