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