1use super::ReturningSelector;
2use crate::{
3 ActiveModelTrait, ColumnTrait, ConnectionTrait, DbBackend, EntityTrait, Insert, InsertMany,
4 IntoActiveModel, Iterable, PrimaryKeyToColumn, PrimaryKeyTrait, SelectModel, TryFromU64,
5 TryInsert, error::*,
6};
7use sea_query::{FromValueTuple, Iden, InsertStatement, Query, ReturningClause, ValueTuple};
8use std::marker::PhantomData;
9
10type PrimaryKey<A> = <<A as ActiveModelTrait>::Entity as EntityTrait>::PrimaryKey;
11
12#[derive(Debug)]
18pub struct Inserter<A>
19where
20 A: ActiveModelTrait,
21{
22 primary_key: Option<ValueTuple>,
23 query: InsertStatement,
24 model: PhantomData<A>,
25}
26
27#[derive(Debug)]
30#[non_exhaustive]
31pub struct InsertResult<A>
32where
33 A: ActiveModelTrait,
34{
35 pub last_insert_id: <PrimaryKey<A> as PrimaryKeyTrait>::ValueType,
37}
38
39#[derive(Debug)]
42#[non_exhaustive]
43pub struct InsertManyResult<A>
44where
45 A: ActiveModelTrait,
46{
47 pub last_insert_id: Option<<PrimaryKey<A> as PrimaryKeyTrait>::ValueType>,
49}
50
51#[derive(Debug)]
56pub enum TryInsertResult<T> {
57 Empty,
61 Conflicted,
72 Inserted(T),
74}
75
76impl<A> TryInsertResult<InsertResult<A>>
77where
78 A: ActiveModelTrait,
79{
80 pub fn last_insert_id(
86 self,
87 ) -> Result<Option<<PrimaryKey<A> as PrimaryKeyTrait>::ValueType>, DbErr> {
88 match self {
89 Self::Empty => Ok(None),
90 Self::Inserted(v) => Ok(Some(v.last_insert_id)),
91 Self::Conflicted => Err(DbErr::RecordNotInserted),
92 }
93 }
94}
95
96impl<A> TryInsert<A>
97where
98 A: ActiveModelTrait,
99{
100 pub fn exec<C>(self, db: &C) -> Result<TryInsertResult<InsertResult<A>>, DbErr>
102 where
103 C: ConnectionTrait,
104 {
105 if self.empty {
106 return Ok(TryInsertResult::Empty);
107 }
108 let res = self.insert_struct.exec(db);
109 match res {
110 Ok(res) => Ok(TryInsertResult::Inserted(res)),
111 Err(DbErr::RecordNotInserted) => Ok(TryInsertResult::Conflicted),
112 Err(err) => Err(err),
113 }
114 }
115
116 pub fn exec_without_returning<C>(self, db: &C) -> Result<TryInsertResult<u64>, DbErr>
119 where
120 C: ConnectionTrait,
121 {
122 if self.empty {
123 return Ok(TryInsertResult::Empty);
124 }
125 let res = self.insert_struct.exec_without_returning(db);
126 match res {
127 Ok(res) => Ok(TryInsertResult::Inserted(res)),
128 Err(DbErr::RecordNotInserted) => Ok(TryInsertResult::Conflicted),
129 Err(err) => Err(err),
130 }
131 }
132
133 pub fn exec_with_returning<C>(
135 self,
136 db: &C,
137 ) -> Result<TryInsertResult<<A::Entity as EntityTrait>::Model>, DbErr>
138 where
139 <A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
140 C: ConnectionTrait,
141 {
142 if self.empty {
143 return Ok(TryInsertResult::Empty);
144 }
145 let res = self.insert_struct.exec_with_returning(db);
146 match res {
147 Ok(res) => Ok(TryInsertResult::Inserted(res)),
148 Err(DbErr::RecordNotInserted) => Ok(TryInsertResult::Conflicted),
149 Err(err) => Err(err),
150 }
151 }
152
153 pub fn exec_with_returning_keys<C>(
155 self,
156 db: &C,
157 ) -> Result<TryInsertResult<Vec<<PrimaryKey<A> as PrimaryKeyTrait>::ValueType>>, DbErr>
158 where
159 <A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
160 C: ConnectionTrait,
161 {
162 if self.empty {
163 return Ok(TryInsertResult::Empty);
164 }
165
166 let res = self.insert_struct.exec_with_returning_keys(db);
167 match res {
168 Ok(res) => Ok(TryInsertResult::Inserted(res)),
169 Err(DbErr::RecordNotInserted) => Ok(TryInsertResult::Conflicted),
170 Err(err) => Err(err),
171 }
172 }
173
174 pub fn exec_with_returning_many<C>(
176 self,
177 db: &C,
178 ) -> Result<TryInsertResult<Vec<<A::Entity as EntityTrait>::Model>>, DbErr>
179 where
180 <A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
181 C: ConnectionTrait,
182 {
183 if self.empty {
184 return Ok(TryInsertResult::Empty);
185 }
186
187 let res = self.insert_struct.exec_with_returning_many(db);
188 match res {
189 Ok(res) => Ok(TryInsertResult::Inserted(res)),
190 Err(DbErr::RecordNotInserted) => Ok(TryInsertResult::Conflicted),
191 Err(err) => Err(err),
192 }
193 }
194}
195
196impl<A> Insert<A>
197where
198 A: ActiveModelTrait,
199{
200 pub fn exec<'a, C>(self, db: &'a C) -> Result<InsertResult<A>, DbErr>
202 where
203 C: ConnectionTrait,
204 A: 'a,
205 {
206 let mut query = self.query;
208 if db.support_returning() {
209 query.returning(returning_pk::<A>(db.get_database_backend()));
210 }
211 Inserter::<A>::new(self.primary_key, query).exec(db)
212 }
213
214 pub fn exec_without_returning<'a, C>(self, db: &'a C) -> Result<u64, DbErr>
217 where
218 C: ConnectionTrait,
219 A: 'a,
220 {
221 Inserter::<A>::new(self.primary_key, self.query).exec_without_returning(db)
222 }
223
224 pub fn exec_with_returning<'a, C>(
230 self,
231 db: &'a C,
232 ) -> Result<<A::Entity as EntityTrait>::Model, DbErr>
233 where
234 <A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
235 C: ConnectionTrait,
236 A: 'a,
237 {
238 Inserter::<A>::new(self.primary_key, self.query).exec_with_returning(db)
239 }
240
241 pub fn exec_with_returning_keys<'a, C>(
243 self,
244 db: &'a C,
245 ) -> Result<Vec<<PrimaryKey<A> as PrimaryKeyTrait>::ValueType>, DbErr>
246 where
247 <A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
248 C: ConnectionTrait,
249 A: 'a,
250 {
251 Inserter::<A>::new(self.primary_key, self.query).exec_with_returning_keys(db)
252 }
253
254 pub fn exec_with_returning_many<'a, C>(
256 self,
257 db: &'a C,
258 ) -> Result<Vec<<A::Entity as EntityTrait>::Model>, DbErr>
259 where
260 <A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
261 C: ConnectionTrait,
262 A: 'a,
263 {
264 Inserter::<A>::new(self.primary_key, self.query).exec_with_returning_many(db)
265 }
266}
267
268impl<A> InsertMany<A>
269where
270 A: ActiveModelTrait,
271{
272 pub fn exec<C>(self, db: &C) -> Result<InsertManyResult<A>, DbErr>
274 where
275 C: ConnectionTrait,
276 {
277 if self.empty {
278 return Ok(InsertManyResult {
279 last_insert_id: None,
280 });
281 }
282 let res = self.into_one().exec(db);
283 match res {
284 Ok(r) => Ok(InsertManyResult {
285 last_insert_id: Some(r.last_insert_id),
286 }),
287 Err(err) => Err(err),
288 }
289 }
290
291 pub fn exec_without_returning<C>(self, db: &C) -> Result<u64, DbErr>
294 where
295 C: ConnectionTrait,
296 {
297 if self.empty {
298 return Ok(0);
299 }
300 self.into_one().exec_without_returning(db)
301 }
302
303 pub fn exec_with_returning<C>(
305 self,
306 db: &C,
307 ) -> Result<Vec<<A::Entity as EntityTrait>::Model>, DbErr>
308 where
309 <A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
310 C: ConnectionTrait,
311 {
312 if self.empty {
313 return Ok(Vec::new());
314 }
315
316 self.into_one().exec_with_returning_many(db)
317 }
318
319 #[deprecated(
321 since = "2.0.0",
322 note = "Please use [`InsertMany::exec_with_returning`]"
323 )]
324 pub fn exec_with_returning_many<C>(
325 self,
326 db: &C,
327 ) -> Result<Vec<<A::Entity as EntityTrait>::Model>, DbErr>
328 where
329 <A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
330 C: ConnectionTrait,
331 {
332 if self.empty {
333 return Ok(Vec::new());
334 }
335
336 self.into_one().exec_with_returning_many(db)
337 }
338
339 pub fn exec_with_returning_keys<C>(
341 self,
342 db: &C,
343 ) -> Result<Vec<<PrimaryKey<A> as PrimaryKeyTrait>::ValueType>, DbErr>
344 where
345 <A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
346 C: ConnectionTrait,
347 {
348 if self.empty {
349 return Ok(Vec::new());
350 }
351
352 self.into_one().exec_with_returning_keys(db)
353 }
354}
355
356impl<A> Inserter<A>
357where
358 A: ActiveModelTrait,
359{
360 pub fn new(primary_key: Option<ValueTuple>, query: InsertStatement) -> Self {
362 Self {
363 primary_key,
364 query,
365 model: PhantomData,
366 }
367 }
368
369 pub fn exec<'a, C>(self, db: &'a C) -> Result<InsertResult<A>, DbErr>
371 where
372 C: ConnectionTrait,
373 A: 'a,
374 {
375 exec_insert(self.primary_key, self.query, db)
376 }
377
378 pub fn exec_without_returning<'a, C>(self, db: &'a C) -> Result<u64, DbErr>
380 where
381 C: ConnectionTrait,
382 A: 'a,
383 {
384 exec_insert_without_returning(self.query, db)
385 }
386
387 pub fn exec_with_returning<'a, C>(
389 self,
390 db: &'a C,
391 ) -> Result<<A::Entity as EntityTrait>::Model, DbErr>
392 where
393 <A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
394 C: ConnectionTrait,
395 A: 'a,
396 {
397 exec_insert_with_returning::<A, _>(self.primary_key, self.query, db)
398 }
399
400 pub fn exec_with_returning_keys<'a, C>(
402 self,
403 db: &'a C,
404 ) -> Result<Vec<<PrimaryKey<A> as PrimaryKeyTrait>::ValueType>, DbErr>
405 where
406 <A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
407 C: ConnectionTrait,
408 A: 'a,
409 {
410 exec_insert_with_returning_keys::<A, _>(self.query, db)
411 }
412
413 pub fn exec_with_returning_many<'a, C>(
415 self,
416 db: &'a C,
417 ) -> Result<Vec<<A::Entity as EntityTrait>::Model>, DbErr>
418 where
419 <A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
420 C: ConnectionTrait,
421 A: 'a,
422 {
423 exec_insert_with_returning_many::<A, _>(self.query, db)
424 }
425}
426
427fn exec_insert<A, C>(
428 primary_key: Option<ValueTuple>,
429 statement: InsertStatement,
430 db: &C,
431) -> Result<InsertResult<A>, DbErr>
432where
433 C: ConnectionTrait,
434 A: ActiveModelTrait,
435{
436 type ValueTypeOf<A> = <PrimaryKey<A> as PrimaryKeyTrait>::ValueType;
437
438 let db_backend = db.get_database_backend();
439
440 let last_insert_id = match (primary_key, db.support_returning()) {
441 (_, true) => {
442 let mut rows = db.query_all(&statement)?;
443 let row = match rows.pop() {
444 Some(row) => row,
445 None => return Err(DbErr::RecordNotInserted),
446 };
447 let cols = PrimaryKey::<A>::iter()
448 .map(|col| col.to_string())
449 .collect::<Vec<_>>();
450 row.try_get_many("", cols.as_ref())
451 .map_err(|_| DbErr::UnpackInsertId)?
452 }
453 (Some(value_tuple), false) => {
454 let res = db.execute(&statement)?;
455 if res.rows_affected() == 0 {
456 return Err(DbErr::RecordNotInserted);
457 }
458 FromValueTuple::from_value_tuple(value_tuple)
459 }
460 (None, false) => {
461 let res = db.execute(&statement)?;
462 if res.rows_affected() == 0 {
463 return Err(DbErr::RecordNotInserted);
464 }
465 let last_insert_id = res.last_insert_id();
466 if db_backend == DbBackend::MySql && last_insert_id == 0 {
472 return Err(DbErr::RecordNotInserted);
473 }
474 ValueTypeOf::<A>::try_from_u64(last_insert_id).map_err(|_| DbErr::UnpackInsertId)?
475 }
476 };
477
478 Ok(InsertResult { last_insert_id })
479}
480
481fn exec_insert_without_returning<C>(insert_statement: InsertStatement, db: &C) -> Result<u64, DbErr>
482where
483 C: ConnectionTrait,
484{
485 let exec_result = db.execute(&insert_statement)?;
486 Ok(exec_result.rows_affected())
487}
488
489fn exec_insert_with_returning<A, C>(
490 primary_key: Option<ValueTuple>,
491 mut insert_statement: InsertStatement,
492 db: &C,
493) -> Result<<A::Entity as EntityTrait>::Model, DbErr>
494where
495 <A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
496 C: ConnectionTrait,
497 A: ActiveModelTrait,
498{
499 let db_backend = db.get_database_backend();
500 let found = match db.support_returning() {
501 true => {
502 let returning = Query::returning().exprs(
503 <A::Entity as EntityTrait>::Column::iter()
504 .map(|c| c.select_as(c.into_returning_expr(db_backend))),
505 );
506 insert_statement.returning(returning);
507 ReturningSelector::<SelectModel<<A::Entity as EntityTrait>::Model>, _>::from_query(
508 insert_statement,
509 )
510 .one(db)?
511 }
512 false => {
513 let insert_res = exec_insert::<A, _>(primary_key, insert_statement, db)?;
514 <A::Entity as EntityTrait>::find_by_id(insert_res.last_insert_id).one(db)?
515 }
516 };
517 match found {
518 Some(model) => Ok(model),
519 None => Err(DbErr::RecordNotFound(
520 "Failed to find inserted item".to_owned(),
521 )),
522 }
523}
524
525fn exec_insert_with_returning_keys<A, C>(
526 mut insert_statement: InsertStatement,
527 db: &C,
528) -> Result<Vec<<PrimaryKey<A> as PrimaryKeyTrait>::ValueType>, DbErr>
529where
530 <A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
531 C: ConnectionTrait,
532 A: ActiveModelTrait,
533{
534 let db_backend = db.get_database_backend();
535 match db.support_returning() {
536 true => {
537 insert_statement.returning(returning_pk::<A>(db_backend));
538 let rows = db.query_all(&insert_statement)?;
539 let cols = PrimaryKey::<A>::iter()
540 .map(|col| col.to_string())
541 .collect::<Vec<_>>();
542 let mut keys = Vec::new();
543 for row in rows {
544 keys.push(
545 row.try_get_many("", cols.as_ref())
546 .map_err(|_| DbErr::UnpackInsertId)?,
547 );
548 }
549 Ok(keys)
550 }
551 false => Err(DbErr::BackendNotSupported {
552 db: db_backend.as_str(),
553 ctx: "INSERT RETURNING",
554 }),
555 }
556}
557
558fn exec_insert_with_returning_many<A, C>(
559 mut insert_statement: InsertStatement,
560 db: &C,
561) -> Result<Vec<<A::Entity as EntityTrait>::Model>, DbErr>
562where
563 <A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
564 C: ConnectionTrait,
565 A: ActiveModelTrait,
566{
567 let db_backend = db.get_database_backend();
568 match db.support_returning() {
569 true => {
570 let returning = Query::returning().exprs(
571 <A::Entity as EntityTrait>::Column::iter()
572 .map(|c| c.select_as(c.into_returning_expr(db_backend))),
573 );
574 insert_statement.returning(returning);
575 ReturningSelector::<SelectModel<<A::Entity as EntityTrait>::Model>, _>::from_query(
576 insert_statement,
577 )
578 .all(db)
579 }
580 false => Err(DbErr::BackendNotSupported {
581 db: db_backend.as_str(),
582 ctx: "INSERT RETURNING",
583 }),
584 }
585}
586
587fn returning_pk<A>(db_backend: DbBackend) -> ReturningClause
588where
589 A: ActiveModelTrait,
590{
591 Query::returning().exprs(<A::Entity as EntityTrait>::PrimaryKey::iter().map(|c| {
592 c.into_column()
593 .select_as(c.into_column().into_returning_expr(db_backend))
594 }))
595}