1use crate::{
2 DatabaseConnection, DatabaseConnectionType, DbBackend, EntityTrait, ExecResult,
3 ExecResultHolder, Iden, IdenStatic, Iterable, MockDatabaseConnection, MockDatabaseTrait,
4 ModelTrait, QueryResult, QueryResultRow, SelectA, SelectB, Statement, error::*,
5};
6use sea_query::{Value, ValueType, Values};
7use std::{collections::BTreeMap, sync::Arc};
8use tracing::instrument;
9
10#[derive(Debug)]
12pub struct MockDatabase {
13 db_backend: DbBackend,
14 transaction: Option<OpenTransaction>,
15 transaction_log: Vec<Transaction>,
16 exec_results: Vec<Result<MockExecResult, DbErr>>,
17 query_results: Vec<Result<Vec<MockRow>, DbErr>>,
18}
19
20#[derive(Clone, Debug, Default)]
22pub struct MockExecResult {
23 pub last_insert_id: u64,
25 pub rows_affected: u64,
27}
28
29#[derive(Clone, Debug)]
32pub struct MockRow {
33 pub(crate) values: BTreeMap<String, Value>,
35}
36
37pub trait IntoMockRow {
39 fn into_mock_row(self) -> MockRow;
41}
42
43#[derive(Debug)]
45pub struct OpenTransaction {
46 stmts: Vec<Statement>,
47 transaction_depth: usize,
48}
49
50#[derive(Debug, Clone, PartialEq)]
52pub struct Transaction {
53 stmts: Vec<Statement>,
54}
55
56impl MockDatabase {
57 pub fn new(db_backend: DbBackend) -> Self {
60 Self {
61 db_backend,
62 transaction: None,
63 transaction_log: Vec::new(),
64 exec_results: Vec::new(),
65 query_results: Vec::new(),
66 }
67 }
68
69 pub fn into_connection(self) -> DatabaseConnection {
71 DatabaseConnectionType::MockDatabaseConnection(Arc::new(MockDatabaseConnection::new(self)))
72 .into()
73 }
74
75 pub fn append_exec_results<I>(mut self, vec: I) -> Self
77 where
78 I: IntoIterator<Item = MockExecResult>,
79 {
80 self.exec_results.extend(vec.into_iter().map(Result::Ok));
81 self
82 }
83
84 pub fn append_query_results<T, I, II>(mut self, vec: II) -> Self
86 where
87 T: IntoMockRow,
88 I: IntoIterator<Item = T>,
89 II: IntoIterator<Item = I>,
90 {
91 for row in vec.into_iter() {
92 let row = row.into_iter().map(|vec| Ok(vec.into_mock_row())).collect();
93 self.query_results.push(row);
94 }
95 self
96 }
97
98 pub fn append_exec_errors<I>(mut self, vec: I) -> Self
100 where
101 I: IntoIterator<Item = DbErr>,
102 {
103 self.exec_results.extend(vec.into_iter().map(Result::Err));
104 self
105 }
106
107 pub fn append_query_errors<I>(mut self, vec: I) -> Self
109 where
110 I: IntoIterator<Item = DbErr>,
111 {
112 self.query_results.extend(vec.into_iter().map(Result::Err));
113 self
114 }
115}
116
117impl MockDatabaseTrait for MockDatabase {
118 #[instrument(level = "trace")]
119 fn execute(&mut self, counter: usize, statement: Statement) -> Result<ExecResult, DbErr> {
120 if let Some(transaction) = &mut self.transaction {
121 transaction.push(statement);
122 } else {
123 self.transaction_log.push(Transaction::one(statement));
124 }
125 if counter < self.exec_results.len() {
126 match std::mem::replace(
127 &mut self.exec_results[counter],
128 Err(exec_err("this value has been consumed already")),
129 ) {
130 Ok(result) => Ok(ExecResult {
131 result: ExecResultHolder::Mock(result),
132 }),
133 Err(err) => Err(err),
134 }
135 } else {
136 Err(exec_err("`exec_results` buffer is empty"))
137 }
138 }
139
140 #[instrument(level = "trace")]
141 fn query(&mut self, counter: usize, statement: Statement) -> Result<Vec<QueryResult>, DbErr> {
142 if let Some(transaction) = &mut self.transaction {
143 transaction.push(statement);
144 } else {
145 self.transaction_log.push(Transaction::one(statement));
146 }
147 if counter < self.query_results.len() {
148 match std::mem::replace(
149 &mut self.query_results[counter],
150 Err(query_err("this value has been consumed already")),
151 ) {
152 Ok(result) => Ok(result
153 .into_iter()
154 .map(|row| QueryResult {
155 row: QueryResultRow::Mock(row),
156 })
157 .collect()),
158 Err(err) => Err(err),
159 }
160 } else {
161 Err(query_err("`query_results` buffer is empty."))
162 }
163 }
164
165 #[instrument(level = "trace")]
166 fn begin(&mut self) {
167 match self.transaction.as_mut() {
168 Some(transaction) => transaction.begin_nested(self.db_backend),
169 None => self.transaction = Some(OpenTransaction::init()),
170 }
171 }
172
173 #[instrument(level = "trace")]
174 fn commit(&mut self) {
175 match self.transaction.as_mut() {
176 Some(transaction) => {
177 if transaction.commit(self.db_backend) {
178 if let Some(transaction) = self.transaction.take() {
179 self.transaction_log.push(transaction.into_transaction());
180 }
181 }
182 }
183 None => panic!("There is no open transaction to commit"),
184 }
185 }
186
187 #[instrument(level = "trace")]
188 fn rollback(&mut self) {
189 match self.transaction.as_mut() {
190 Some(transaction) => {
191 if transaction.rollback(self.db_backend) {
192 if let Some(transaction) = self.transaction.take() {
193 self.transaction_log.push(transaction.into_transaction());
194 }
195 }
196 }
197 None => panic!("There is no open transaction to rollback"),
198 }
199 }
200
201 fn drain_transaction_log(&mut self) -> Vec<Transaction> {
202 std::mem::take(&mut self.transaction_log)
203 }
204
205 fn get_database_backend(&self) -> DbBackend {
206 self.db_backend
207 }
208
209 fn ping(&self) -> Result<(), DbErr> {
210 Ok(())
211 }
212}
213
214impl MockRow {
215 pub fn try_get<T, I: crate::ColIdx>(&self, index: I) -> Result<T, DbErr>
217 where
218 T: ValueType,
219 {
220 if let Some(index) = index.as_str() {
221 T::try_from(
222 self.values
223 .get(index)
224 .ok_or_else(|| query_err(format!("No column for ColIdx {index:?}")))?
225 .clone(),
226 )
227 .map_err(type_err)
228 } else if let Some(index) = index.as_usize() {
229 let (_, value) = self
230 .values
231 .iter()
232 .nth(*index)
233 .ok_or_else(|| query_err(format!("Column at index {index} not found")))?;
234 T::try_from(value.clone()).map_err(type_err)
235 } else {
236 unreachable!("Missing ColIdx implementation for MockRow");
237 }
238 }
239
240 pub fn into_column_value_tuples(self) -> impl Iterator<Item = (String, Value)> {
242 self.values.into_iter()
243 }
244}
245
246impl IntoMockRow for MockRow {
247 fn into_mock_row(self) -> MockRow {
248 self
249 }
250}
251
252impl<M> IntoMockRow for M
253where
254 M: ModelTrait,
255{
256 fn into_mock_row(self) -> MockRow {
257 let mut values = BTreeMap::new();
258 for col in <<M::Entity as EntityTrait>::Column>::iter() {
259 values.insert(col.to_string(), self.get(col));
260 }
261 MockRow { values }
262 }
263}
264
265impl<M, N> IntoMockRow for (M, N)
266where
267 M: ModelTrait,
268 N: ModelTrait,
269{
270 fn into_mock_row(self) -> MockRow {
271 let mut mapped_join = BTreeMap::new();
272
273 for column in <<M as ModelTrait>::Entity as EntityTrait>::Column::iter() {
274 mapped_join.insert(
275 format!("{}{}", SelectA.as_str(), column.as_str()),
276 self.0.get(column),
277 );
278 }
279 for column in <<N as ModelTrait>::Entity as EntityTrait>::Column::iter() {
280 mapped_join.insert(
281 format!("{}{}", SelectB.as_str(), column.as_str()),
282 self.1.get(column),
283 );
284 }
285
286 mapped_join.into_mock_row()
287 }
288}
289
290impl<M, N> IntoMockRow for (M, Option<N>)
291where
292 M: ModelTrait,
293 N: ModelTrait,
294{
295 fn into_mock_row(self) -> MockRow {
296 let mut mapped_join = BTreeMap::new();
297
298 for column in <<M as ModelTrait>::Entity as EntityTrait>::Column::iter() {
299 mapped_join.insert(
300 format!("{}{}", SelectA.as_str(), column.as_str()),
301 self.0.get(column),
302 );
303 }
304 if let Some(b_entity) = self.1 {
305 for column in <<N as ModelTrait>::Entity as EntityTrait>::Column::iter() {
306 mapped_join.insert(
307 format!("{}{}", SelectB.as_str(), column.as_str()),
308 b_entity.get(column),
309 );
310 }
311 }
312
313 mapped_join.into_mock_row()
314 }
315}
316
317impl<T> IntoMockRow for BTreeMap<T, Value>
318where
319 T: Into<String>,
320{
321 fn into_mock_row(self) -> MockRow {
322 MockRow {
323 values: self.into_iter().map(|(k, v)| (k.into(), v)).collect(),
324 }
325 }
326}
327
328impl Transaction {
329 pub fn from_sql_and_values<I, T>(db_backend: DbBackend, sql: T, values: I) -> Self
331 where
332 I: IntoIterator<Item = Value>,
333 T: Into<String>,
334 {
335 Self::one(Statement::from_string_values_tuple(
336 db_backend,
337 (sql, Values(values.into_iter().collect())),
338 ))
339 }
340
341 pub fn one(stmt: Statement) -> Self {
343 Self { stmts: vec![stmt] }
344 }
345
346 pub fn many<I>(stmts: I) -> Self
348 where
349 I: IntoIterator<Item = Statement>,
350 {
351 Self {
352 stmts: stmts.into_iter().collect(),
353 }
354 }
355
356 pub fn wrap<I>(stmts: I) -> Vec<Self>
358 where
359 I: IntoIterator<Item = Statement>,
360 {
361 stmts.into_iter().map(Self::one).collect()
362 }
363
364 pub fn statements(&self) -> &[Statement] {
366 &self.stmts
367 }
368}
369
370impl OpenTransaction {
371 fn init() -> Self {
372 Self {
373 stmts: vec![Statement::from_string(DbBackend::Postgres, "BEGIN")],
374 transaction_depth: 0,
375 }
376 }
377
378 fn begin_nested(&mut self, db_backend: DbBackend) {
379 self.transaction_depth += 1;
380 self.push(Statement::from_string(
381 db_backend,
382 format!("SAVEPOINT savepoint_{}", self.transaction_depth),
383 ));
384 }
385
386 fn commit(&mut self, db_backend: DbBackend) -> bool {
387 if self.transaction_depth == 0 {
388 self.push(Statement::from_string(db_backend, "COMMIT"));
389 true
390 } else {
391 self.push(Statement::from_string(
392 db_backend,
393 format!("RELEASE SAVEPOINT savepoint_{}", self.transaction_depth),
394 ));
395 self.transaction_depth -= 1;
396 false
397 }
398 }
399
400 fn rollback(&mut self, db_backend: DbBackend) -> bool {
401 if self.transaction_depth == 0 {
402 self.push(Statement::from_string(db_backend, "ROLLBACK"));
403 true
404 } else {
405 self.push(Statement::from_string(
406 db_backend,
407 format!("ROLLBACK TO SAVEPOINT savepoint_{}", self.transaction_depth),
408 ));
409 self.transaction_depth -= 1;
410 false
411 }
412 }
413
414 fn push(&mut self, stmt: Statement) {
415 self.stmts.push(stmt);
416 }
417
418 fn into_transaction(self) -> Transaction {
419 match self.transaction_depth {
420 0 => Transaction { stmts: self.stmts },
421 _ => panic!("There is uncommitted nested transaction"),
422 }
423 }
424}
425
426#[cfg(test)]
427#[cfg(feature = "mock")]
428mod tests {
429 #[cfg(feature = "sync")]
430 use crate::util::StreamShim;
431 use crate::{
432 DbBackend, DbErr, IntoMockRow, MockDatabase, Statement, Transaction, TransactionError,
433 TransactionTrait, entity::*, error::*, tests_cfg::*,
434 };
435 use pretty_assertions::assert_eq;
436
437 #[derive(Debug, PartialEq, Eq)]
438 pub struct MyErr(String);
439
440 impl std::error::Error for MyErr {}
441
442 impl std::fmt::Display for MyErr {
443 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
444 write!(f, "{}", self.0.as_str())
445 }
446 }
447
448 #[test]
449 fn test_transaction_1() {
450 let db = MockDatabase::new(DbBackend::Postgres).into_connection();
451
452 db.transaction::<_, (), DbErr>(|txn| {
453 let _1 = cake::Entity::find().one(txn);
454 let _2 = fruit::Entity::find().all(txn);
455
456 Ok(())
457 })
458 .unwrap();
459
460 let _ = cake::Entity::find().all(&db);
461
462 assert_eq!(
463 db.into_transaction_log(),
464 [
465 Transaction::many([
466 Statement::from_string(DbBackend::Postgres, "BEGIN"),
467 Statement::from_sql_and_values(
468 DbBackend::Postgres,
469 r#"SELECT "cake"."id", "cake"."name" FROM "cake" LIMIT $1"#,
470 [1u64.into()]
471 ),
472 Statement::from_sql_and_values(
473 DbBackend::Postgres,
474 r#"SELECT "fruit"."id", "fruit"."name", "fruit"."cake_id" FROM "fruit""#,
475 []
476 ),
477 Statement::from_string(DbBackend::Postgres, "COMMIT"),
478 ]),
479 Transaction::from_sql_and_values(
480 DbBackend::Postgres,
481 r#"SELECT "cake"."id", "cake"."name" FROM "cake""#,
482 []
483 ),
484 ]
485 );
486 }
487
488 #[test]
489 fn test_transaction_2() {
490 let db = MockDatabase::new(DbBackend::Postgres).into_connection();
491
492 let result = db.transaction::<_, (), MyErr>(|txn| {
493 let _ = cake::Entity::find().one(txn);
494 Err(MyErr("test".to_owned()))
495 });
496
497 match result {
498 Err(TransactionError::Transaction(err)) => {
499 assert_eq!(err, MyErr("test".to_owned()))
500 }
501 _ => unreachable!(),
502 }
503
504 assert_eq!(
505 db.into_transaction_log(),
506 [Transaction::many([
507 Statement::from_string(DbBackend::Postgres, "BEGIN"),
508 Statement::from_sql_and_values(
509 DbBackend::Postgres,
510 r#"SELECT "cake"."id", "cake"."name" FROM "cake" LIMIT $1"#,
511 [1u64.into()]
512 ),
513 Statement::from_string(DbBackend::Postgres, "ROLLBACK"),
514 ])]
515 );
516 }
517
518 #[test]
519 fn test_nested_transaction_1() {
520 let db = MockDatabase::new(DbBackend::Postgres).into_connection();
521
522 db.transaction::<_, (), DbErr>(|txn| {
523 let _ = cake::Entity::find().one(txn);
524
525 txn.transaction::<_, (), DbErr>(|txn| {
526 let _ = fruit::Entity::find().all(txn);
527
528 Ok(())
529 })
530 .unwrap();
531
532 Ok(())
533 })
534 .unwrap();
535
536 assert_eq!(
537 db.into_transaction_log(),
538 [Transaction::many([
539 Statement::from_string(DbBackend::Postgres, "BEGIN"),
540 Statement::from_sql_and_values(
541 DbBackend::Postgres,
542 r#"SELECT "cake"."id", "cake"."name" FROM "cake" LIMIT $1"#,
543 [1u64.into()]
544 ),
545 Statement::from_string(DbBackend::Postgres, "SAVEPOINT savepoint_1"),
546 Statement::from_sql_and_values(
547 DbBackend::Postgres,
548 r#"SELECT "fruit"."id", "fruit"."name", "fruit"."cake_id" FROM "fruit""#,
549 []
550 ),
551 Statement::from_string(DbBackend::Postgres, "RELEASE SAVEPOINT savepoint_1"),
552 Statement::from_string(DbBackend::Postgres, "COMMIT"),
553 ]),]
554 );
555 }
556
557 #[test]
558 fn test_nested_transaction_2() {
559 let db = MockDatabase::new(DbBackend::Postgres).into_connection();
560
561 db.transaction::<_, (), DbErr>(|txn| {
562 let _ = cake::Entity::find().one(txn);
563
564 txn.transaction::<_, (), DbErr>(|txn| {
565 let _ = fruit::Entity::find().all(txn);
566
567 txn.transaction::<_, (), DbErr>(|txn| {
568 let _ = cake::Entity::find().all(txn);
569
570 Ok(())
571 })
572 .unwrap();
573
574 Ok(())
575 })
576 .unwrap();
577
578 Ok(())
579 })
580 .unwrap();
581
582 assert_eq!(
583 db.into_transaction_log(),
584 [Transaction::many([
585 Statement::from_string(DbBackend::Postgres, "BEGIN"),
586 Statement::from_sql_and_values(
587 DbBackend::Postgres,
588 r#"SELECT "cake"."id", "cake"."name" FROM "cake" LIMIT $1"#,
589 [1u64.into()]
590 ),
591 Statement::from_string(DbBackend::Postgres, "SAVEPOINT savepoint_1"),
592 Statement::from_sql_and_values(
593 DbBackend::Postgres,
594 r#"SELECT "fruit"."id", "fruit"."name", "fruit"."cake_id" FROM "fruit""#,
595 []
596 ),
597 Statement::from_string(DbBackend::Postgres, "SAVEPOINT savepoint_2"),
598 Statement::from_sql_and_values(
599 DbBackend::Postgres,
600 r#"SELECT "cake"."id", "cake"."name" FROM "cake""#,
601 []
602 ),
603 Statement::from_string(DbBackend::Postgres, "RELEASE SAVEPOINT savepoint_2"),
604 Statement::from_string(DbBackend::Postgres, "RELEASE SAVEPOINT savepoint_1"),
605 Statement::from_string(DbBackend::Postgres, "COMMIT"),
606 ]),]
607 );
608 }
609
610 #[test]
611 fn test_stream_1() -> Result<(), DbErr> {
612 let apple = fruit::Model {
613 id: 1,
614 name: "Apple".to_owned(),
615 cake_id: Some(1),
616 };
617
618 let orange = fruit::Model {
619 id: 2,
620 name: "orange".to_owned(),
621 cake_id: None,
622 };
623
624 let db = MockDatabase::new(DbBackend::Postgres)
625 .append_query_results([[apple.clone(), orange.clone()]])
626 .into_connection();
627
628 let mut stream = fruit::Entity::find().stream(&db)?;
629
630 assert_eq!(stream.try_next()?, Some(apple));
631
632 assert_eq!(stream.try_next()?, Some(orange));
633
634 assert_eq!(stream.try_next()?, None);
635
636 Ok(())
637 }
638
639 #[test]
640 fn test_stream_2() -> Result<(), DbErr> {
641 use fruit::Entity as Fruit;
642 let db = MockDatabase::new(DbBackend::Postgres)
643 .append_query_results([Vec::<fruit::Model>::new()])
644 .into_connection();
645
646 let mut stream = Fruit::find().stream(&db)?;
647
648 while let Some(item) = stream.try_next()? {
649 let _item: fruit::ActiveModel = item.into();
650 }
651
652 Ok(())
653 }
654
655 #[test]
656 fn test_stream_in_transaction() -> Result<(), DbErr> {
657 let apple = fruit::Model {
658 id: 1,
659 name: "Apple".to_owned(),
660 cake_id: Some(1),
661 };
662
663 let orange = fruit::Model {
664 id: 2,
665 name: "orange".to_owned(),
666 cake_id: None,
667 };
668
669 let db = MockDatabase::new(DbBackend::Postgres)
670 .append_query_results([[apple.clone(), orange.clone()]])
671 .into_connection();
672
673 let txn = db.begin()?;
674
675 if let Ok(mut stream) = fruit::Entity::find().stream(&txn) {
676 assert_eq!(stream.try_next()?, Some(apple));
677
678 assert_eq!(stream.try_next()?, Some(orange));
679
680 assert_eq!(stream.try_next()?, None);
681
682 }
684
685 txn.commit()?;
686
687 Ok(())
688 }
689
690 #[test]
691 fn test_mocked_join() {
692 let row = (
693 cake::Model {
694 id: 1,
695 name: "Apple Cake".to_owned(),
696 },
697 fruit::Model {
698 id: 2,
699 name: "Apple".to_owned(),
700 cake_id: Some(1),
701 },
702 );
703 let mocked_row = row.into_mock_row();
704
705 let a_id = mocked_row.try_get::<i32, _>("A_id");
706 assert!(a_id.is_ok());
707 assert_eq!(1, a_id.unwrap());
708 let b_id = mocked_row.try_get::<i32, _>("B_id");
709 assert!(b_id.is_ok());
710 assert_eq!(2, b_id.unwrap());
711 }
712
713 #[test]
714 fn test_find_also_related_1() -> Result<(), DbErr> {
715 let db = MockDatabase::new(DbBackend::Postgres)
716 .append_query_results([[(
717 cake::Model {
718 id: 1,
719 name: "Apple Cake".to_owned(),
720 },
721 fruit::Model {
722 id: 2,
723 name: "Apple".to_owned(),
724 cake_id: Some(1),
725 },
726 )]])
727 .into_connection();
728
729 assert_eq!(
730 cake::Entity::find()
731 .find_also_related(fruit::Entity)
732 .all(&db)?,
733 [(
734 cake::Model {
735 id: 1,
736 name: "Apple Cake".to_owned(),
737 },
738 Some(fruit::Model {
739 id: 2,
740 name: "Apple".to_owned(),
741 cake_id: Some(1),
742 })
743 )]
744 );
745
746 assert_eq!(
747 db.into_transaction_log(),
748 [Transaction::from_sql_and_values(
749 DbBackend::Postgres,
750 r#"SELECT "cake"."id" AS "A_id", "cake"."name" AS "A_name", "fruit"."id" AS "B_id", "fruit"."name" AS "B_name", "fruit"."cake_id" AS "B_cake_id" FROM "cake" LEFT JOIN "fruit" ON "cake"."id" = "fruit"."cake_id""#,
751 []
752 ),]
753 );
754
755 Ok(())
756 }
757
758 #[cfg(feature = "postgres-array")]
759 #[test]
760 fn test_postgres_array_1() -> Result<(), DbErr> {
761 mod collection {
762 use crate as sea_orm;
763 use crate::entity::prelude::*;
764
765 #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
766 #[sea_orm(table_name = "collection")]
767 pub struct Model {
768 #[sea_orm(primary_key)]
769 pub id: i32,
770 pub integers: Vec<i32>,
771 pub integers_opt: Option<Vec<i32>>,
772 }
773
774 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
775 pub enum Relation {}
776
777 impl ActiveModelBehavior for ActiveModel {}
778 }
779
780 let db = MockDatabase::new(DbBackend::Postgres)
781 .append_query_results([[
782 collection::Model {
783 id: 1,
784 integers: vec![1, 2, 3],
785 integers_opt: Some(vec![1, 2, 3]),
786 },
787 collection::Model {
788 id: 2,
789 integers: vec![],
790 integers_opt: Some(vec![]),
791 },
792 collection::Model {
793 id: 3,
794 integers: vec![3, 1, 4],
795 integers_opt: None,
796 },
797 ]])
798 .into_connection();
799
800 assert_eq!(
801 collection::Entity::find().all(&db)?,
802 [
803 collection::Model {
804 id: 1,
805 integers: vec![1, 2, 3],
806 integers_opt: Some(vec![1, 2, 3]),
807 },
808 collection::Model {
809 id: 2,
810 integers: vec![],
811 integers_opt: Some(vec![]),
812 },
813 collection::Model {
814 id: 3,
815 integers: vec![3, 1, 4],
816 integers_opt: None,
817 },
818 ]
819 );
820
821 assert_eq!(
822 db.into_transaction_log(),
823 [Transaction::from_sql_and_values(
824 DbBackend::Postgres,
825 r#"SELECT "collection"."id", "collection"."integers", "collection"."integers_opt" FROM "collection""#,
826 []
827 ),]
828 );
829
830 Ok(())
831 }
832
833 #[test]
834 fn test_query_err() {
835 let db = MockDatabase::new(DbBackend::MySql)
836 .append_query_errors([query_err("this is a mock query error")])
837 .into_connection();
838
839 assert_eq!(
840 cake::Entity::find().all(&db),
841 Err(query_err("this is a mock query error"))
842 );
843 }
844
845 #[test]
846 fn test_exec_err() {
847 let db = MockDatabase::new(DbBackend::MySql)
848 .append_exec_errors([exec_err("this is a mock exec error")])
849 .into_connection();
850
851 let model = cake::ActiveModel::new();
852
853 assert_eq!(model.save(&db), Err(exec_err("this is a mock exec error")));
854 }
855}