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