drizzle_postgres/builder/insert.rs
1//! `INSERT` builder states and clause methods.
2//!
3//! [`InsertBuilder`] is the builder returned by `QueryBuilder::insert`. Its
4//! state parameter only allows steps in SQL order: rows (`VALUES` or a
5//! `SELECT`), then `ON CONFLICT`, then `RETURNING`.
6
7use crate::traits::PostgresTable;
8use crate::values::PostgresValue;
9use core::marker::PhantomData;
10use drizzle_core::builder::{
11 OnConflictBuilder as CoreOnConflictBuilder, OnConflictOutput, PostgresConflictTarget,
12};
13use drizzle_core::{
14 ConflictTarget, InsertSelectCompatible, InsertSelectTable, InsertTargetColumns,
15 NamedConstraint, PartialInsertSelectCompatible, SQL, ToSQL, Token,
16};
17
18use super::select::{CompletedSelect, IntoSelectQuery};
19
20//------------------------------------------------------------------------------
21// Type State Markers
22//------------------------------------------------------------------------------
23
24pub use drizzle_core::builder::{
25 InsertColumnsSet, InsertDoUpdateSet, InsertInitial, InsertOnConflictSet, InsertReturningSet,
26 InsertValuesSet,
27};
28
29//------------------------------------------------------------------------------
30// OnConflictBuilder
31//------------------------------------------------------------------------------
32
33/// The `ON CONFLICT` target of an `INSERT`, waiting for its action.
34///
35/// Created by [`InsertBuilder::on_conflict()`] or
36/// [`InsertBuilder::on_conflict_on_constraint()`].
37/// Call [`do_nothing()`](Self::do_nothing) or [`do_update()`](Self::do_update)
38/// to complete the clause.
39pub type OnConflictBuilder<'a, S, T> = CoreOnConflictBuilder<
40 'a,
41 PostgresValue<'a>,
42 S,
43 T,
44 PostgresConflictTarget<'a, PostgresValue<'a>>,
45 PostgresOnConflictOutput,
46>;
47
48#[doc(hidden)]
49#[derive(Debug, Clone, Copy, Default)]
50pub struct PostgresOnConflictOutput;
51
52impl<'a, S, T> OnConflictOutput<'a, PostgresValue<'a>, S, T> for PostgresOnConflictOutput {
53 type OnConflictSet = InsertBuilder<'a, S, InsertOnConflictSet, T>;
54 type DoUpdateSet = InsertBuilder<'a, S, InsertDoUpdateSet, T>;
55
56 fn on_conflict(sql: SQL<'a, PostgresValue<'a>>) -> Self::OnConflictSet {
57 InsertBuilder {
58 sql,
59 schema: PhantomData,
60 state: PhantomData,
61 table: PhantomData,
62 marker: PhantomData,
63 row: PhantomData,
64 grouped: PhantomData,
65 }
66 }
67
68 fn do_update(sql: SQL<'a, PostgresValue<'a>>) -> Self::DoUpdateSet {
69 InsertBuilder {
70 sql,
71 schema: PhantomData,
72 state: PhantomData,
73 table: PhantomData,
74 marker: PhantomData,
75 row: PhantomData,
76 grouped: PhantomData,
77 }
78 }
79}
80
81//------------------------------------------------------------------------------
82// InsertBuilder Definition
83//------------------------------------------------------------------------------
84
85/// A `PostgreSQL` `INSERT` being built: a [`QueryBuilder`](super::QueryBuilder)
86/// in one of the `Insert*` states.
87///
88/// Rows come from `.values(...)` (the table's generated `Insert*` model) or
89/// from `.select(...)`. Then add `ON CONFLICT` handling and `RETURNING` as
90/// needed. `State` allows only these steps, in this order.
91///
92/// # Examples
93///
94/// ```rust
95/// # extern crate self as drizzle;
96/// # mod _drizzle {
97/// # pub mod core { pub use drizzle_core::*; }
98/// # pub mod error { pub use drizzle_core::error::*; }
99/// # pub mod types { pub use drizzle_types::*; }
100/// # pub mod migrations { pub use drizzle_migrations::*; }
101/// # pub use drizzle_types::Dialect;
102/// # pub use drizzle_types as ddl;
103/// # pub mod postgres {
104/// # pub mod values { pub use drizzle_postgres::values::*; }
105/// # pub mod traits { pub use drizzle_postgres::traits::*; }
106/// # pub mod common { pub use drizzle_postgres::common::*; }
107/// # pub mod attrs { pub use drizzle_postgres::attrs::*; }
108/// # pub mod builder { pub use drizzle_postgres::builder::*; }
109/// # pub mod helpers { pub use drizzle_postgres::helpers::*; }
110/// # pub mod expr { pub use drizzle_postgres::expr::*; }
111/// # pub mod types { pub use drizzle_postgres::types::*; }
112/// # #[cfg(feature = "aws-data-api")]
113/// # pub mod aws_data_api { pub use drizzle_postgres::aws_data_api::*; }
114/// # pub struct Row;
115/// # impl Row {
116/// # pub fn get<'a, I, T>(&'a self, _: I) -> T { unimplemented!() }
117/// # pub fn try_get<'a, I, T>(&'a self, _: I) -> Result<T, Box<dyn std::error::Error + Sync + Send>> { unimplemented!() }
118/// # }
119/// # pub mod prelude {
120/// # pub use drizzle_macros::{PostgresTable, PostgresSchema, PostgresIndex};
121/// # pub use drizzle_postgres::attrs::*;
122/// # pub use drizzle_postgres::common::PostgresSchemaType;
123/// # pub use drizzle_postgres::traits::{PostgresColumn, PostgresTable};
124/// # pub use drizzle_postgres::values::{PostgresInsertValue, PostgresUpdateValue, PostgresValue};
125/// # pub use drizzle_core::*;
126/// # }
127/// # }
128/// # }
129/// # pub use _drizzle::*;
130/// # pub use const_format;
131/// # fn main() {
132/// # use drizzle::postgres::prelude::*;
133/// # use drizzle::postgres::builder::QueryBuilder;
134/// # #[PostgresTable(name = "users")]
135/// # struct User {
136/// # #[column(serial, primary)]
137/// # id: i32,
138/// # name: String,
139/// # email: Option<String>,
140/// # }
141/// # #[PostgresTable(name = "posts")]
142/// # struct Post {
143/// # #[column(serial, primary)]
144/// # id: i32,
145/// # #[column(references = User::id)]
146/// # author_id: i32,
147/// # title: String,
148/// # }
149/// # #[derive(PostgresSchema)]
150/// # struct Schema {
151/// # user: User,
152/// # post: Post,
153/// # }
154/// # let db = QueryBuilder::new::<Schema>();
155/// # let Schema { user, post } = Schema::new();
156/// let query = db
157/// .insert(user)
158/// .values([InsertUser::new("Alice"), InsertUser::new("Bob")])
159/// .on_conflict_do_nothing()
160/// .returning(user.id);
161/// assert_eq!(
162/// query.to_sql().sql(),
163/// r#"INSERT INTO "users" ("name") VALUES ($1), ($2) ON CONFLICT DO NOTHING RETURNING "users"."id""#
164/// );
165/// # }
166/// ```
167pub type InsertBuilder<'a, Schema, State, Table, Marker = (), Row = ()> =
168 super::QueryBuilder<'a, Schema, State, Table, Marker, Row>;
169
170type ReturningMarker<Table, Columns> = drizzle_core::Scoped<
171 <Columns as drizzle_core::IntoSelectTarget>::Marker,
172 drizzle_core::Cons<Table, drizzle_core::Nil>,
173>;
174
175type ReturningRow<Table, Columns> =
176 <<Columns as drizzle_core::IntoSelectTarget>::Marker as drizzle_core::ResolveRow<Table>>::Row;
177
178type ReturningBuilder<'a, S, T, Columns> = InsertBuilder<
179 'a,
180 S,
181 InsertReturningSet,
182 T,
183 ReturningMarker<T, Columns>,
184 ReturningRow<T, Columns>,
185>;
186
187//------------------------------------------------------------------------------
188// Initial State Implementation
189//------------------------------------------------------------------------------
190
191impl<'a, Schema, Table> InsertBuilder<'a, Schema, InsertInitial, Table>
192where
193 Table: PostgresTable<'a>,
194{
195 /// Inserts one row. Shorthand for `.values([row])`.
196 ///
197 /// # Examples
198 ///
199 /// ```rust
200 /// # extern crate self as drizzle;
201 /// # mod _drizzle {
202 /// # pub mod core { pub use drizzle_core::*; }
203 /// # pub mod error { pub use drizzle_core::error::*; }
204 /// # pub mod types { pub use drizzle_types::*; }
205 /// # pub mod migrations { pub use drizzle_migrations::*; }
206 /// # pub use drizzle_types::Dialect;
207 /// # pub use drizzle_types as ddl;
208 /// # pub mod postgres {
209 /// # pub mod values { pub use drizzle_postgres::values::*; }
210 /// # pub mod traits { pub use drizzle_postgres::traits::*; }
211 /// # pub mod common { pub use drizzle_postgres::common::*; }
212 /// # pub mod attrs { pub use drizzle_postgres::attrs::*; }
213 /// # pub mod builder { pub use drizzle_postgres::builder::*; }
214 /// # pub mod helpers { pub use drizzle_postgres::helpers::*; }
215 /// # pub mod expr { pub use drizzle_postgres::expr::*; }
216 /// # pub mod types { pub use drizzle_postgres::types::*; }
217 /// # #[cfg(feature = "aws-data-api")]
218 /// # pub mod aws_data_api { pub use drizzle_postgres::aws_data_api::*; }
219 /// # pub struct Row;
220 /// # impl Row {
221 /// # pub fn get<'a, I, T>(&'a self, _: I) -> T { unimplemented!() }
222 /// # pub fn try_get<'a, I, T>(&'a self, _: I) -> Result<T, Box<dyn std::error::Error + Sync + Send>> { unimplemented!() }
223 /// # }
224 /// # pub mod prelude {
225 /// # pub use drizzle_macros::{PostgresTable, PostgresSchema, PostgresIndex};
226 /// # pub use drizzle_postgres::attrs::*;
227 /// # pub use drizzle_postgres::common::PostgresSchemaType;
228 /// # pub use drizzle_postgres::traits::{PostgresColumn, PostgresTable};
229 /// # pub use drizzle_postgres::values::{PostgresInsertValue, PostgresUpdateValue, PostgresValue};
230 /// # pub use drizzle_core::*;
231 /// # }
232 /// # }
233 /// # }
234 /// # pub use _drizzle::*;
235 /// # pub use const_format;
236 /// # fn main() {
237 /// # use drizzle::postgres::prelude::*;
238 /// # use drizzle::postgres::builder::QueryBuilder;
239 /// # #[PostgresTable(name = "users")]
240 /// # struct User {
241 /// # #[column(serial, primary)]
242 /// # id: i32,
243 /// # name: String,
244 /// # email: Option<String>,
245 /// # }
246 /// # #[PostgresTable(name = "posts")]
247 /// # struct Post {
248 /// # #[column(serial, primary)]
249 /// # id: i32,
250 /// # #[column(references = User::id)]
251 /// # author_id: i32,
252 /// # title: String,
253 /// # }
254 /// # #[derive(PostgresSchema)]
255 /// # struct Schema {
256 /// # user: User,
257 /// # post: Post,
258 /// # }
259 /// # let db = QueryBuilder::new::<Schema>();
260 /// # let Schema { user, post } = Schema::new();
261 /// let query = db.insert(user).value(InsertUser::new("Alice"));
262 /// assert_eq!(query.to_sql().sql(), r#"INSERT INTO "users" ("name") VALUES ($1)"#);
263 /// # }
264 /// ```
265 #[inline]
266 pub fn value<T>(
267 self,
268 value: Table::Insert<T>,
269 ) -> InsertBuilder<'a, Schema, InsertValuesSet, Table> {
270 self.values([value])
271 }
272
273 /// Inserts the given rows, built with the table's `Insert*` model.
274 ///
275 /// Every row has the same model type. A column a row leaves unset gets
276 /// its database default; when rows set different columns, every row lists
277 /// the union of the columns, with `DEFAULT` where it sets none.
278 ///
279 /// # Examples
280 ///
281 /// ```rust
282 /// # extern crate self as drizzle;
283 /// # mod _drizzle {
284 /// # pub mod core { pub use drizzle_core::*; }
285 /// # pub mod error { pub use drizzle_core::error::*; }
286 /// # pub mod types { pub use drizzle_types::*; }
287 /// # pub mod migrations { pub use drizzle_migrations::*; }
288 /// # pub use drizzle_types::Dialect;
289 /// # pub use drizzle_types as ddl;
290 /// # pub mod postgres {
291 /// # pub mod values { pub use drizzle_postgres::values::*; }
292 /// # pub mod traits { pub use drizzle_postgres::traits::*; }
293 /// # pub mod common { pub use drizzle_postgres::common::*; }
294 /// # pub mod attrs { pub use drizzle_postgres::attrs::*; }
295 /// # pub mod builder { pub use drizzle_postgres::builder::*; }
296 /// # pub mod helpers { pub use drizzle_postgres::helpers::*; }
297 /// # pub mod expr { pub use drizzle_postgres::expr::*; }
298 /// # pub mod types { pub use drizzle_postgres::types::*; }
299 /// # #[cfg(feature = "aws-data-api")]
300 /// # pub mod aws_data_api { pub use drizzle_postgres::aws_data_api::*; }
301 /// # pub struct Row;
302 /// # impl Row {
303 /// # pub fn get<'a, I, T>(&'a self, _: I) -> T { unimplemented!() }
304 /// # pub fn try_get<'a, I, T>(&'a self, _: I) -> Result<T, Box<dyn std::error::Error + Sync + Send>> { unimplemented!() }
305 /// # }
306 /// # pub mod prelude {
307 /// # pub use drizzle_macros::{PostgresTable, PostgresSchema, PostgresIndex};
308 /// # pub use drizzle_postgres::attrs::*;
309 /// # pub use drizzle_postgres::common::PostgresSchemaType;
310 /// # pub use drizzle_postgres::traits::{PostgresColumn, PostgresTable};
311 /// # pub use drizzle_postgres::values::{PostgresInsertValue, PostgresUpdateValue, PostgresValue};
312 /// # pub use drizzle_core::*;
313 /// # }
314 /// # }
315 /// # }
316 /// # pub use _drizzle::*;
317 /// # pub use const_format;
318 /// # fn main() {
319 /// # use drizzle::postgres::prelude::*;
320 /// # use drizzle::postgres::builder::QueryBuilder;
321 /// # #[PostgresTable(name = "users")]
322 /// # struct User {
323 /// # #[column(serial, primary)]
324 /// # id: i32,
325 /// # name: String,
326 /// # email: Option<String>,
327 /// # }
328 /// # #[PostgresTable(name = "posts")]
329 /// # struct Post {
330 /// # #[column(serial, primary)]
331 /// # id: i32,
332 /// # #[column(references = User::id)]
333 /// # author_id: i32,
334 /// # title: String,
335 /// # }
336 /// # #[derive(PostgresSchema)]
337 /// # struct Schema {
338 /// # user: User,
339 /// # post: Post,
340 /// # }
341 /// # let db = QueryBuilder::new::<Schema>();
342 /// # let Schema { user, post } = Schema::new();
343 /// let query = db
344 /// .insert(user)
345 /// .values([InsertUser::new("Alice"), InsertUser::new("Bob")]);
346 /// assert_eq!(
347 /// query.to_sql().sql(),
348 /// r#"INSERT INTO "users" ("name") VALUES ($1), ($2)"#
349 /// );
350 /// # }
351 /// ```
352 #[inline]
353 pub fn values<I, T>(self, values: I) -> InsertBuilder<'a, Schema, InsertValuesSet, Table>
354 where
355 I: IntoIterator<Item = Table::Insert<T>>,
356 {
357 let sql = crate::helpers::values::<'a, Table, T>(values);
358 InsertBuilder {
359 sql: self.sql.append(sql),
360 schema: PhantomData,
361 state: PhantomData,
362 table: PhantomData,
363 marker: PhantomData,
364 row: PhantomData,
365 grouped: PhantomData,
366 }
367 }
368
369 /// Sets the target columns, in order, for `INSERT ... SELECT`.
370 ///
371 /// The list must include every required column (non-null without a
372 /// default). Continue with [`select`](Self::select), whose columns must
373 /// match these in number, order and type.
374 ///
375 /// # Examples
376 ///
377 /// ```rust
378 /// # extern crate self as drizzle;
379 /// # mod _drizzle {
380 /// # pub mod core { pub use drizzle_core::*; }
381 /// # pub mod error { pub use drizzle_core::error::*; }
382 /// # pub mod types { pub use drizzle_types::*; }
383 /// # pub mod migrations { pub use drizzle_migrations::*; }
384 /// # pub use drizzle_types::Dialect;
385 /// # pub use drizzle_types as ddl;
386 /// # pub mod postgres {
387 /// # pub mod values { pub use drizzle_postgres::values::*; }
388 /// # pub mod traits { pub use drizzle_postgres::traits::*; }
389 /// # pub mod common { pub use drizzle_postgres::common::*; }
390 /// # pub mod attrs { pub use drizzle_postgres::attrs::*; }
391 /// # pub mod builder { pub use drizzle_postgres::builder::*; }
392 /// # pub mod helpers { pub use drizzle_postgres::helpers::*; }
393 /// # pub mod expr { pub use drizzle_postgres::expr::*; }
394 /// # pub mod types { pub use drizzle_postgres::types::*; }
395 /// # #[cfg(feature = "aws-data-api")]
396 /// # pub mod aws_data_api { pub use drizzle_postgres::aws_data_api::*; }
397 /// # pub struct Row;
398 /// # impl Row {
399 /// # pub fn get<'a, I, T>(&'a self, _: I) -> T { unimplemented!() }
400 /// # pub fn try_get<'a, I, T>(&'a self, _: I) -> Result<T, Box<dyn std::error::Error + Sync + Send>> { unimplemented!() }
401 /// # }
402 /// # pub mod prelude {
403 /// # pub use drizzle_macros::{PostgresTable, PostgresSchema, PostgresIndex};
404 /// # pub use drizzle_postgres::attrs::*;
405 /// # pub use drizzle_postgres::common::PostgresSchemaType;
406 /// # pub use drizzle_postgres::traits::{PostgresColumn, PostgresTable};
407 /// # pub use drizzle_postgres::values::{PostgresInsertValue, PostgresUpdateValue, PostgresValue};
408 /// # pub use drizzle_core::*;
409 /// # }
410 /// # }
411 /// # }
412 /// # pub use _drizzle::*;
413 /// # pub use const_format;
414 /// # fn main() {
415 /// # use drizzle::postgres::prelude::*;
416 /// # use drizzle::postgres::builder::QueryBuilder;
417 /// # #[PostgresTable(name = "users")]
418 /// # struct User {
419 /// # #[column(serial, primary)]
420 /// # id: i32,
421 /// # name: String,
422 /// # email: Option<String>,
423 /// # }
424 /// # #[PostgresTable(name = "posts")]
425 /// # struct Post {
426 /// # #[column(serial, primary)]
427 /// # id: i32,
428 /// # #[column(references = User::id)]
429 /// # author_id: i32,
430 /// # title: String,
431 /// # }
432 /// # #[derive(PostgresSchema)]
433 /// # struct Schema {
434 /// # user: User,
435 /// # post: Post,
436 /// # }
437 /// # let db = QueryBuilder::new::<Schema>();
438 /// # let Schema { user, post } = Schema::new();
439 /// let query = db
440 /// .insert(post)
441 /// .columns((post.author_id, post.title))
442 /// .select(db.select((user.id, user.name)).from(user));
443 /// assert_eq!(
444 /// query.to_sql().sql(),
445 /// r#"INSERT INTO "posts" ("author_id", "title") SELECT "users"."id", "users"."name" FROM "users""#
446 /// );
447 /// # }
448 /// ```
449 #[inline]
450 pub fn columns<Columns>(
451 self,
452 columns: Columns,
453 ) -> InsertBuilder<'a, Schema, InsertColumnsSet<Columns::Columns>, Table>
454 where
455 Columns: InsertTargetColumns<'a, PostgresValue<'a>, Table>,
456 {
457 InsertBuilder {
458 sql: self.sql.append(columns.into_target_columns_sql()),
459 schema: PhantomData,
460 state: PhantomData,
461 table: PhantomData,
462 marker: PhantomData,
463 row: PhantomData,
464 grouped: PhantomData,
465 }
466 }
467
468 /// Inserts the rows of a `SELECT` into every insertable column of the table.
469 ///
470 /// The query's columns must match the table's insertable columns in
471 /// number, order, type and nullability, and the query must pass the
472 /// usual scope and `GROUP BY` checks; all of this is checked at compile
473 /// time. To fill only some columns, call [`columns`](Self::columns) first.
474 #[inline]
475 pub fn select<Q, R, ScopeProof, AggProof>(
476 self,
477 query: Q,
478 ) -> InsertBuilder<'a, Schema, InsertValuesSet, Table>
479 where
480 Table: InsertSelectTable,
481 Q: IntoSelectQuery<'a, Schema, R>,
482 Q::Marker: InsertSelectCompatible<'a, PostgresValue<'a>, Table, R>
483 + drizzle_core::MarkerScopeValidFor<ScopeProof>
484 + drizzle_core::MarkerAggValidFor<Q::Grouped, AggProof>,
485 {
486 let select = query.into_select_query().into_select_sql();
487 InsertBuilder {
488 sql: self
489 .sql
490 .append(Table::insert_columns_sql::<PostgresValue<'a>>())
491 .append(select),
492 schema: PhantomData,
493 state: PhantomData,
494 table: PhantomData,
495 marker: PhantomData,
496 row: PhantomData,
497 grouped: PhantomData,
498 }
499 }
500
501 /// Inserts the rows of a raw `SELECT`, with no target column list.
502 ///
503 /// Nothing about the query is checked: not its column count, types,
504 /// nullability, sources or aggregates. Prefer [`select`](Self::select).
505 #[inline]
506 pub fn select_raw<Q>(self, query: Q) -> InsertBuilder<'a, Schema, InsertValuesSet, Table>
507 where
508 Q: ToSQL<'a, PostgresValue<'a>>,
509 {
510 InsertBuilder {
511 sql: self.sql.append(query.into_sql()),
512 schema: PhantomData,
513 state: PhantomData,
514 table: PhantomData,
515 marker: PhantomData,
516 row: PhantomData,
517 grouped: PhantomData,
518 }
519 }
520}
521
522impl<'a, Schema, Table, Targets> InsertBuilder<'a, Schema, InsertColumnsSet<Targets>, Table>
523where
524 Table: PostgresTable<'a> + InsertSelectTable,
525{
526 /// Inserts the rows of a `SELECT` into the columns chosen with `.columns(...)`.
527 ///
528 /// The query's columns must match the target columns in number, order,
529 /// type and nullability, and the query must pass the usual scope and
530 /// `GROUP BY` checks; all of this is checked at compile time.
531 #[inline]
532 pub fn select<Q, R, RequiredProof, ScopeProof, AggProof>(
533 self,
534 query: Q,
535 ) -> InsertBuilder<'a, Schema, InsertValuesSet, Table>
536 where
537 Targets: drizzle_core::IncludesRequired<Table::RequiredColumns, RequiredProof>,
538 Q: IntoSelectQuery<'a, Schema, R>,
539 Q::Marker: PartialInsertSelectCompatible<'a, PostgresValue<'a>, Targets>
540 + drizzle_core::MarkerScopeValidFor<ScopeProof>
541 + drizzle_core::MarkerAggValidFor<Q::Grouped, AggProof>,
542 {
543 let select = query.into_select_query().into_select_sql();
544 InsertBuilder {
545 sql: self.sql.append(select),
546 schema: PhantomData,
547 state: PhantomData,
548 table: PhantomData,
549 marker: PhantomData,
550 row: PhantomData,
551 grouped: PhantomData,
552 }
553 }
554
555 /// Inserts the rows of a raw `SELECT` into the chosen target columns.
556 ///
557 /// Only the target list is checked (it must include every required
558 /// column); the query itself is not. Prefer [`select`](Self::select).
559 #[inline]
560 pub fn select_raw<Q, RequiredProof>(
561 self,
562 query: Q,
563 ) -> InsertBuilder<'a, Schema, InsertValuesSet, Table>
564 where
565 Targets: drizzle_core::IncludesRequired<Table::RequiredColumns, RequiredProof>,
566 Q: ToSQL<'a, PostgresValue<'a>>,
567 {
568 InsertBuilder {
569 sql: self.sql.append(query.into_sql()),
570 schema: PhantomData,
571 state: PhantomData,
572 table: PhantomData,
573 marker: PhantomData,
574 row: PhantomData,
575 grouped: PhantomData,
576 }
577 }
578}
579
580//------------------------------------------------------------------------------
581// Post-VALUES Implementation
582//------------------------------------------------------------------------------
583
584impl<'a, S, T> InsertBuilder<'a, S, InsertValuesSet, T> {
585 /// Starts `ON CONFLICT (columns)`, handling rows that would violate a
586 /// unique constraint on the target.
587 ///
588 /// The target is a primary-key column, a unique column, or a unique
589 /// index (anything implementing `ConflictTarget<T>`, which the macros
590 /// generate). Finish with `.do_nothing()` or `.do_update(update_model)`.
591 ///
592 /// # Examples
593 ///
594 /// ```rust
595 /// # extern crate self as drizzle;
596 /// # mod _drizzle {
597 /// # pub mod core { pub use drizzle_core::*; }
598 /// # pub mod error { pub use drizzle_core::error::*; }
599 /// # pub mod types { pub use drizzle_types::*; }
600 /// # pub mod migrations { pub use drizzle_migrations::*; }
601 /// # pub use drizzle_types::Dialect;
602 /// # pub use drizzle_types as ddl;
603 /// # pub mod postgres {
604 /// # pub mod values { pub use drizzle_postgres::values::*; }
605 /// # pub mod traits { pub use drizzle_postgres::traits::*; }
606 /// # pub mod common { pub use drizzle_postgres::common::*; }
607 /// # pub mod attrs { pub use drizzle_postgres::attrs::*; }
608 /// # pub mod builder { pub use drizzle_postgres::builder::*; }
609 /// # pub mod helpers { pub use drizzle_postgres::helpers::*; }
610 /// # pub mod expr { pub use drizzle_postgres::expr::*; }
611 /// # pub mod types { pub use drizzle_postgres::types::*; }
612 /// # #[cfg(feature = "aws-data-api")]
613 /// # pub mod aws_data_api { pub use drizzle_postgres::aws_data_api::*; }
614 /// # pub struct Row;
615 /// # impl Row {
616 /// # pub fn get<'a, I, T>(&'a self, _: I) -> T { unimplemented!() }
617 /// # pub fn try_get<'a, I, T>(&'a self, _: I) -> Result<T, Box<dyn std::error::Error + Sync + Send>> { unimplemented!() }
618 /// # }
619 /// # pub mod prelude {
620 /// # pub use drizzle_macros::{PostgresTable, PostgresSchema, PostgresIndex};
621 /// # pub use drizzle_postgres::attrs::*;
622 /// # pub use drizzle_postgres::common::PostgresSchemaType;
623 /// # pub use drizzle_postgres::traits::{PostgresColumn, PostgresTable};
624 /// # pub use drizzle_postgres::values::{PostgresInsertValue, PostgresUpdateValue, PostgresValue};
625 /// # pub use drizzle_core::*;
626 /// # }
627 /// # }
628 /// # }
629 /// # pub use _drizzle::*;
630 /// # pub use const_format;
631 /// fn main() {
632 /// use drizzle::postgres::prelude::*;
633 /// use drizzle::postgres::builder::QueryBuilder;
634 ///
635 /// #[PostgresTable(name = "users")]
636 /// struct User {
637 /// #[column(serial, primary)]
638 /// id: i32,
639 /// name: String,
640 /// #[column(unique)]
641 /// email: Option<String>,
642 /// }
643 ///
644 /// #[PostgresIndex(unique)]
645 /// struct UserEmailIdx(User::email);
646 ///
647 /// #[derive(PostgresSchema)]
648 /// struct Schema {
649 /// user: User,
650 /// user_email_idx: UserEmailIdx,
651 /// }
652 ///
653 /// let builder = QueryBuilder::new::<Schema>();
654 /// let schema = Schema::new();
655 /// let user = schema.user;
656 ///
657 /// // Target a specific column
658 /// builder.insert(user).values([InsertUser::new("Alice")])
659 /// .on_conflict(user.id).do_nothing();
660 ///
661 /// // DO UPDATE with new values
662 /// let query = builder.insert(user).values([InsertUser::new("Alice")])
663 /// .on_conflict(user.email).do_update(UpdateUser::default().with_name("updated"));
664 /// assert_eq!(
665 /// query.to_sql().sql(),
666 /// r#"INSERT INTO "users" ("name") VALUES ($1) ON CONFLICT ("email") DO UPDATE SET "name" = $2"#
667 /// );
668 ///
669 /// // Target a unique index
670 /// builder.insert(user).values([InsertUser::new("Alice")])
671 /// .on_conflict(schema.user_email_idx).do_nothing();
672 /// }
673 /// ```
674 pub fn on_conflict<C: ConflictTarget<T>>(self, target: C) -> OnConflictBuilder<'a, S, T> {
675 let columns = target.conflict_columns();
676 let target_where = target.conflict_where_clause().map(SQL::raw);
677 let target_sql = SQL::join(columns.iter().map(|c| SQL::ident(*c)), Token::COMMA);
678 OnConflictBuilder::new(self.sql, PostgresConflictTarget::columns(target_sql))
679 .with_target_where_sql(target_where)
680 }
681
682 /// Starts `ON CONFLICT ON CONSTRAINT name`, naming the unique constraint
683 /// to handle.
684 ///
685 /// The target is a unique column or a named unique constraint (anything
686 /// implementing `NamedConstraint<T>`, which the macros generate). A
687 /// standalone unique index is not a constraint, so `PostgreSQL` rejects it
688 /// here; use [`on_conflict`](Self::on_conflict) for indexes. Finish with
689 /// `.do_nothing()` or `.do_update(update_model)`.
690 ///
691 /// # Examples
692 ///
693 /// ```rust
694 /// # extern crate self as drizzle;
695 /// # mod _drizzle {
696 /// # pub mod core { pub use drizzle_core::*; }
697 /// # pub mod error { pub use drizzle_core::error::*; }
698 /// # pub mod types { pub use drizzle_types::*; }
699 /// # pub mod migrations { pub use drizzle_migrations::*; }
700 /// # pub use drizzle_types::Dialect;
701 /// # pub use drizzle_types as ddl;
702 /// # pub mod postgres {
703 /// # pub mod values { pub use drizzle_postgres::values::*; }
704 /// # pub mod traits { pub use drizzle_postgres::traits::*; }
705 /// # pub mod common { pub use drizzle_postgres::common::*; }
706 /// # pub mod attrs { pub use drizzle_postgres::attrs::*; }
707 /// # pub mod builder { pub use drizzle_postgres::builder::*; }
708 /// # pub mod helpers { pub use drizzle_postgres::helpers::*; }
709 /// # pub mod expr { pub use drizzle_postgres::expr::*; }
710 /// # pub mod types { pub use drizzle_postgres::types::*; }
711 /// # #[cfg(feature = "aws-data-api")]
712 /// # pub mod aws_data_api { pub use drizzle_postgres::aws_data_api::*; }
713 /// # pub struct Row;
714 /// # impl Row {
715 /// # pub fn get<'a, I, T>(&'a self, _: I) -> T { unimplemented!() }
716 /// # pub fn try_get<'a, I, T>(&'a self, _: I) -> Result<T, Box<dyn std::error::Error + Sync + Send>> { unimplemented!() }
717 /// # }
718 /// # pub mod prelude {
719 /// # pub use drizzle_macros::{PostgresTable, PostgresSchema, PostgresIndex};
720 /// # pub use drizzle_postgres::attrs::*;
721 /// # pub use drizzle_postgres::common::PostgresSchemaType;
722 /// # pub use drizzle_postgres::traits::{PostgresColumn, PostgresTable};
723 /// # pub use drizzle_postgres::values::{PostgresInsertValue, PostgresUpdateValue, PostgresValue};
724 /// # pub use drizzle_core::*;
725 /// # }
726 /// # }
727 /// # }
728 /// # pub use _drizzle::*;
729 /// # pub use const_format;
730 /// fn main() {
731 /// use drizzle::postgres::prelude::*;
732 /// use drizzle::postgres::builder::QueryBuilder;
733 ///
734 /// #[PostgresTable(name = "users")]
735 /// struct User {
736 /// #[column(serial, primary)]
737 /// id: i32,
738 /// name: String,
739 /// #[column(unique)]
740 /// email: Option<String>,
741 /// }
742 ///
743 /// #[derive(PostgresSchema)]
744 /// struct Schema {
745 /// user: User,
746 /// }
747 ///
748 /// let builder = QueryBuilder::new::<Schema>();
749 /// let schema = Schema::new();
750 ///
751 /// let user = schema.user;
752 /// builder.insert(user).values([InsertUser::new("Alice")])
753 /// .on_conflict_on_constraint(user.email).do_nothing();
754 /// }
755 /// ```
756 pub fn on_conflict_on_constraint<C: NamedConstraint<T>>(
757 self,
758 target: C,
759 ) -> OnConflictBuilder<'a, S, T> {
760 OnConflictBuilder::new(
761 self.sql,
762 PostgresConflictTarget::constraint(target.constraint_name()),
763 )
764 }
765
766 /// Adds `ON CONFLICT DO NOTHING` with no target: rows that violate any
767 /// unique or exclusion constraint are skipped.
768 #[must_use]
769 pub fn on_conflict_do_nothing(self) -> InsertBuilder<'a, S, InsertOnConflictSet, T> {
770 let conflict_sql = SQL::from_iter([Token::ON, Token::CONFLICT, Token::DO, Token::NOTHING]);
771 InsertBuilder {
772 sql: self.sql.append(conflict_sql),
773 schema: PhantomData,
774 state: PhantomData,
775 table: PhantomData,
776 marker: PhantomData,
777 row: PhantomData,
778 grouped: PhantomData,
779 }
780 }
781
782 /// Adds `RETURNING columns`, so the statement returns the inserted rows.
783 ///
784 /// Pass a column, a tuple of columns, or `()` for all columns. Only
785 /// columns of the target table are allowed.
786 ///
787 /// # Examples
788 ///
789 /// ```rust
790 /// # extern crate self as drizzle;
791 /// # mod _drizzle {
792 /// # pub mod core { pub use drizzle_core::*; }
793 /// # pub mod error { pub use drizzle_core::error::*; }
794 /// # pub mod types { pub use drizzle_types::*; }
795 /// # pub mod migrations { pub use drizzle_migrations::*; }
796 /// # pub use drizzle_types::Dialect;
797 /// # pub use drizzle_types as ddl;
798 /// # pub mod postgres {
799 /// # pub mod values { pub use drizzle_postgres::values::*; }
800 /// # pub mod traits { pub use drizzle_postgres::traits::*; }
801 /// # pub mod common { pub use drizzle_postgres::common::*; }
802 /// # pub mod attrs { pub use drizzle_postgres::attrs::*; }
803 /// # pub mod builder { pub use drizzle_postgres::builder::*; }
804 /// # pub mod helpers { pub use drizzle_postgres::helpers::*; }
805 /// # pub mod expr { pub use drizzle_postgres::expr::*; }
806 /// # pub mod types { pub use drizzle_postgres::types::*; }
807 /// # #[cfg(feature = "aws-data-api")]
808 /// # pub mod aws_data_api { pub use drizzle_postgres::aws_data_api::*; }
809 /// # pub struct Row;
810 /// # impl Row {
811 /// # pub fn get<'a, I, T>(&'a self, _: I) -> T { unimplemented!() }
812 /// # pub fn try_get<'a, I, T>(&'a self, _: I) -> Result<T, Box<dyn std::error::Error + Sync + Send>> { unimplemented!() }
813 /// # }
814 /// # pub mod prelude {
815 /// # pub use drizzle_macros::{PostgresTable, PostgresSchema, PostgresIndex};
816 /// # pub use drizzle_postgres::attrs::*;
817 /// # pub use drizzle_postgres::common::PostgresSchemaType;
818 /// # pub use drizzle_postgres::traits::{PostgresColumn, PostgresTable};
819 /// # pub use drizzle_postgres::values::{PostgresInsertValue, PostgresUpdateValue, PostgresValue};
820 /// # pub use drizzle_core::*;
821 /// # }
822 /// # }
823 /// # }
824 /// # pub use _drizzle::*;
825 /// # pub use const_format;
826 /// # fn main() {
827 /// # use drizzle::postgres::prelude::*;
828 /// # use drizzle::postgres::builder::QueryBuilder;
829 /// # #[PostgresTable(name = "users")]
830 /// # struct User {
831 /// # #[column(serial, primary)]
832 /// # id: i32,
833 /// # name: String,
834 /// # email: Option<String>,
835 /// # }
836 /// # #[PostgresTable(name = "posts")]
837 /// # struct Post {
838 /// # #[column(serial, primary)]
839 /// # id: i32,
840 /// # #[column(references = User::id)]
841 /// # author_id: i32,
842 /// # title: String,
843 /// # }
844 /// # #[derive(PostgresSchema)]
845 /// # struct Schema {
846 /// # user: User,
847 /// # post: Post,
848 /// # }
849 /// # let db = QueryBuilder::new::<Schema>();
850 /// # let Schema { user, post } = Schema::new();
851 /// let query = db
852 /// .insert(user)
853 /// .values([InsertUser::new("Alice")])
854 /// .returning((user.id, user.name));
855 /// assert_eq!(
856 /// query.to_sql().sql(),
857 /// r#"INSERT INTO "users" ("name") VALUES ($1) RETURNING "users"."id", "users"."name""#
858 /// );
859 /// # }
860 /// ```
861 #[inline]
862 pub fn returning<Columns, ScopeProof>(
863 self,
864 columns: Columns,
865 ) -> ReturningBuilder<'a, S, T, Columns>
866 where
867 Columns: drizzle_core::expr::ExprSources,
868 Columns::Sources:
869 drizzle_core::scope::SourcesIn<drizzle_core::Cons<T, drizzle_core::Nil>, ScopeProof>,
870 Columns: ToSQL<'a, PostgresValue<'a>> + drizzle_core::IntoSelectTarget,
871 Columns::Marker: drizzle_core::ResolveRow<T>,
872 {
873 let returning_sql = crate::helpers::returning(columns);
874 InsertBuilder {
875 sql: self.sql.append(returning_sql),
876 schema: PhantomData,
877 state: PhantomData,
878 table: PhantomData,
879 marker: PhantomData,
880 row: PhantomData,
881 grouped: PhantomData,
882 }
883 }
884}
885
886//------------------------------------------------------------------------------
887// Post-ON CONFLICT Implementation
888//------------------------------------------------------------------------------
889
890impl<'a, S, T> InsertBuilder<'a, S, InsertOnConflictSet, T> {
891 /// Adds `RETURNING columns` after the `ON CONFLICT` clause.
892 ///
893 /// Rows skipped by `DO NOTHING` are not returned.
894 #[inline]
895 pub fn returning<Columns, ScopeProof>(
896 self,
897 columns: Columns,
898 ) -> ReturningBuilder<'a, S, T, Columns>
899 where
900 Columns: drizzle_core::expr::ExprSources,
901 Columns::Sources:
902 drizzle_core::scope::SourcesIn<drizzle_core::Cons<T, drizzle_core::Nil>, ScopeProof>,
903 Columns: ToSQL<'a, PostgresValue<'a>> + drizzle_core::IntoSelectTarget,
904 Columns::Marker: drizzle_core::ResolveRow<T>,
905 {
906 let returning_sql = crate::helpers::returning(columns);
907 InsertBuilder {
908 sql: self.sql.append(returning_sql),
909 schema: PhantomData,
910 state: PhantomData,
911 table: PhantomData,
912 marker: PhantomData,
913 row: PhantomData,
914 grouped: PhantomData,
915 }
916 }
917}
918
919//------------------------------------------------------------------------------
920// Post-DO UPDATE SET Implementation
921//------------------------------------------------------------------------------
922
923impl<'a, S, T> InsertBuilder<'a, S, InsertDoUpdateSet, T> {
924 /// Adds a `WHERE` condition to `DO UPDATE`: conflicting rows are updated
925 /// only when it holds.
926 ///
927 /// Renders `ON CONFLICT (...) DO UPDATE SET ... WHERE condition`. The
928 /// condition may only use columns of the target table.
929 pub fn r#where<E, ScopeProof>(
930 self,
931 condition: E,
932 ) -> InsertBuilder<'a, S, InsertOnConflictSet, T>
933 where
934 E: drizzle_core::expr::ExprSources,
935 E::Sources:
936 drizzle_core::scope::SourcesIn<drizzle_core::Cons<T, drizzle_core::Nil>, ScopeProof>,
937 E: drizzle_core::expr::Expr<'a, PostgresValue<'a>>,
938 E::SQLType: drizzle_core::types::BooleanLike,
939 {
940 let sql = self
941 .sql
942 .push(Token::WHERE)
943 .append(condition.into_expr_sql());
944 InsertBuilder {
945 sql,
946 schema: PhantomData,
947 state: PhantomData,
948 table: PhantomData,
949 marker: PhantomData,
950 row: PhantomData,
951 grouped: PhantomData,
952 }
953 }
954
955 /// Adds `RETURNING columns` after `DO UPDATE SET`.
956 #[inline]
957 pub fn returning<Columns, ScopeProof>(
958 self,
959 columns: Columns,
960 ) -> ReturningBuilder<'a, S, T, Columns>
961 where
962 Columns: drizzle_core::expr::ExprSources,
963 Columns::Sources:
964 drizzle_core::scope::SourcesIn<drizzle_core::Cons<T, drizzle_core::Nil>, ScopeProof>,
965 Columns: ToSQL<'a, PostgresValue<'a>> + drizzle_core::IntoSelectTarget,
966 Columns::Marker: drizzle_core::ResolveRow<T>,
967 {
968 let returning_sql = crate::helpers::returning(columns);
969 InsertBuilder {
970 sql: self.sql.append(returning_sql),
971 schema: PhantomData,
972 state: PhantomData,
973 table: PhantomData,
974 marker: PhantomData,
975 row: PhantomData,
976 grouped: PhantomData,
977 }
978 }
979}
980
981#[cfg(test)]
982mod tests {
983 use super::*;
984 use drizzle_core::{SQL, ToSQL};
985
986 #[test]
987 fn test_insert_builder_creation() {
988 let builder = InsertBuilder::<(), InsertInitial, ()> {
989 sql: SQL::raw("INSERT INTO test"),
990 schema: PhantomData,
991 state: PhantomData,
992 table: PhantomData,
993 marker: PhantomData,
994 row: PhantomData,
995 grouped: PhantomData,
996 };
997
998 assert_eq!(builder.to_sql().sql(), "INSERT INTO test");
999 }
1000}