diesel/pg/upsert/
on_conflict_target.rs

1use expression::SqlLiteral;
2use pg::Pg;
3use query_builder::*;
4use query_source::Column;
5use result::QueryResult;
6
7/// Used to specify the constraint name for an upsert statement in the form `ON
8/// CONFLICT ON CONSTRAINT`. Note that `constraint_name` must be the name of a
9/// unique constraint, not the name of an index.
10///
11/// # Example
12///
13/// ```rust
14/// # #[macro_use] extern crate diesel;
15/// # include!("on_conflict_docs_setup.rs");
16/// #
17/// # fn main() {
18/// #     use users::dsl::*;
19/// use diesel::pg::upsert::*;
20///
21/// #     let conn = establish_connection();
22/// #     conn.execute("TRUNCATE TABLE users").unwrap();
23/// conn.execute("ALTER TABLE users ADD CONSTRAINT users_name UNIQUE (name)").unwrap();
24/// let user = User { id: 1, name: "Sean", };
25/// let same_name_different_id = User { id: 2, name: "Sean" };
26/// let same_id_different_name = User { id: 1, name: "Pascal" };
27///
28/// assert_eq!(Ok(1), diesel::insert_into(users).values(&user).execute(&conn));
29///
30/// let inserted_row_count = diesel::insert_into(users)
31///     .values(&same_name_different_id)
32///     .on_conflict(on_constraint("users_name"))
33///     .do_nothing()
34///     .execute(&conn);
35/// assert_eq!(Ok(0), inserted_row_count);
36///
37/// let pk_conflict_result = diesel::insert_into(users)
38///     .values(&same_id_different_name)
39///     .on_conflict(on_constraint("users_name"))
40///     .do_nothing()
41///     .execute(&conn);
42/// assert!(pk_conflict_result.is_err());
43/// # }
44/// ```
45pub fn on_constraint(constraint_name: &str) -> OnConstraint {
46    OnConstraint {
47        constraint_name: constraint_name,
48    }
49}
50
51#[doc(hidden)]
52#[derive(Debug, Clone, Copy)]
53pub struct OnConstraint<'a> {
54    constraint_name: &'a str,
55}
56
57pub trait OnConflictTarget<Table>: QueryFragment<Pg> {}
58
59#[doc(hidden)]
60#[derive(Debug, Clone, Copy)]
61pub struct NoConflictTarget;
62
63impl QueryFragment<Pg> for NoConflictTarget {
64    fn walk_ast(&self, _: AstPass<Pg>) -> QueryResult<()> {
65        Ok(())
66    }
67}
68
69impl<Table> OnConflictTarget<Table> for NoConflictTarget {}
70
71#[doc(hidden)]
72#[derive(Debug, Clone, Copy)]
73pub struct ConflictTarget<T>(pub T);
74
75impl<T: Column> QueryFragment<Pg> for ConflictTarget<T> {
76    fn walk_ast(&self, mut out: AstPass<Pg>) -> QueryResult<()> {
77        out.push_sql(" (");
78        out.push_identifier(T::NAME)?;
79        out.push_sql(")");
80        Ok(())
81    }
82}
83
84impl<T: Column> OnConflictTarget<T::Table> for ConflictTarget<T> {}
85
86impl<ST> QueryFragment<Pg> for ConflictTarget<SqlLiteral<ST>>
87where
88    SqlLiteral<ST>: QueryFragment<Pg>,
89{
90    fn walk_ast(&self, mut out: AstPass<Pg>) -> QueryResult<()> {
91        out.push_sql(" ");
92        self.0.walk_ast(out.reborrow())?;
93        Ok(())
94    }
95}
96
97impl<Tab, ST> OnConflictTarget<Tab> for ConflictTarget<SqlLiteral<ST>> where
98    ConflictTarget<SqlLiteral<ST>>: QueryFragment<Pg>
99{
100}
101
102impl<'a> QueryFragment<Pg> for ConflictTarget<OnConstraint<'a>> {
103    fn walk_ast(&self, mut out: AstPass<Pg>) -> QueryResult<()> {
104        out.push_sql(" ON CONSTRAINT ");
105        out.push_identifier(self.0.constraint_name)?;
106        Ok(())
107    }
108}
109
110impl<'a, Table> OnConflictTarget<Table> for ConflictTarget<OnConstraint<'a>> {}
111
112macro_rules! on_conflict_tuples {
113    ($($col:ident),+) => {
114        impl<T, $($col),+> QueryFragment<Pg> for ConflictTarget<(T, $($col),+)> where
115            T: Column,
116            $($col: Column<Table=T::Table>,)+
117        {
118            fn walk_ast(&self, mut out: AstPass<Pg>) -> QueryResult<()> {
119                out.push_sql(" (");
120                out.push_identifier(T::NAME)?;
121                $(
122                    out.push_sql(", ");
123                    out.push_identifier($col::NAME)?;
124                )+
125                out.push_sql(")");
126                Ok(())
127            }
128        }
129
130        impl<T, $($col),+> OnConflictTarget<T::Table> for ConflictTarget<(T, $($col),+)> where
131            T: Column,
132            $($col: Column<Table=T::Table>,)+
133        {
134        }
135    }
136}
137
138on_conflict_tuples!(U);
139on_conflict_tuples!(U, V);
140on_conflict_tuples!(U, V, W);
141on_conflict_tuples!(U, V, W, X);
142on_conflict_tuples!(U, V, W, X, Y);
143on_conflict_tuples!(U, V, W, X, Y, Z);