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