use crate::prelude::*;
use toasty_core::driver::{Operation, operation::Transaction};
#[driver_test(id(ID), requires(sql), scenario(crate::scenarios::user_unique_email))]
pub async fn batch_two_creates_rolls_back_on_second_failure(t: &mut Test) -> Result<()> {
let mut db = setup(t).await;
User::create()
.email("taken@example.com")
.exec(&mut db)
.await?;
t.log().clear();
assert_err!(
toasty::batch((
User::create().email("new@example.com"),
User::create().email("taken@example.com"),
))
.exec(&mut db)
.await
);
assert_struct!(
t.log().pop_op(),
Operation::Transaction(Transaction::Start {
isolation: None,
read_only: false
})
);
assert_struct!(t.log().pop_op(), Operation::QuerySql(_)); assert_struct!(
t.log().pop_op(),
Operation::Transaction(Transaction::Rollback)
);
assert!(t.log().is_empty());
let users: Vec<User> = User::all().exec(&mut db).await?;
assert_eq!(1, users.len());
assert_eq!(users[0].email, "taken@example.com");
Ok(())
}
#[driver_test(id(ID), requires(sql), scenario(crate::scenarios::user_unique_email))]
pub async fn batch_create_and_update_rolls_back_on_update_failure(t: &mut Test) -> Result<()> {
let mut db = setup(t).await;
User::create()
.email("alice@example.com")
.exec(&mut db)
.await?;
User::create()
.email("taken@example.com")
.exec(&mut db)
.await?;
t.log().clear();
assert_err!(
toasty::batch((
User::create().email("bob@example.com"),
User::filter_by_email("alice@example.com")
.update()
.email("taken@example.com"), ))
.exec(&mut db)
.await
);
assert_struct!(
t.log().pop_op(),
Operation::Transaction(Transaction::Start {
isolation: None,
read_only: false
})
);
assert_struct!(t.log().pop_op(), Operation::QuerySql(_)); assert_struct!(
t.log().pop_op(),
Operation::Transaction(Transaction::Rollback)
);
assert!(t.log().is_empty());
let all: Vec<User> = User::all().exec(&mut db).await?;
assert_eq!(2, all.len());
let emails: hashbrown::HashSet<_> = all.iter().map(|u| u.email.as_str()).collect();
assert!(emails.contains("alice@example.com"));
assert!(emails.contains("taken@example.com"));
Ok(())
}
#[driver_test(id(ID), requires(sql), scenario(crate::scenarios::user_unique_email))]
pub async fn batch_update_and_create_rolls_back_on_create_failure(t: &mut Test) -> Result<()> {
let mut db = setup(t).await;
User::create()
.email("alice@example.com")
.exec(&mut db)
.await?;
User::create()
.email("taken@example.com")
.exec(&mut db)
.await?;
t.log().clear();
assert_err!(
toasty::batch((
User::filter_by_email("alice@example.com")
.update()
.email("alice2@example.com"),
User::create().email("taken@example.com"), ))
.exec(&mut db)
.await
);
assert_struct!(
t.log().pop_op(),
Operation::Transaction(Transaction::Start {
isolation: None,
read_only: false
})
);
assert_struct!(t.log().pop_op(), Operation::QuerySql(_)); assert_struct!(
t.log().pop_op(),
Operation::Transaction(Transaction::Rollback)
);
assert!(t.log().is_empty());
let alice: Vec<User> = User::filter_by_email("alice@example.com")
.exec(&mut db)
.await?;
assert_eq!(1, alice.len());
let alice2: Vec<User> = User::filter_by_email("alice2@example.com")
.exec(&mut db)
.await?;
assert!(alice2.is_empty());
Ok(())
}
#[driver_test(id(ID), requires(sql), scenario(crate::scenarios::user_unique_email))]
pub async fn batch_array_creates_rolls_back_on_failure(t: &mut Test) -> Result<()> {
let mut db = setup(t).await;
User::create()
.email("taken@example.com")
.exec(&mut db)
.await?;
t.log().clear();
assert_err!(
toasty::batch([
User::create().email("first@example.com"),
User::create().email("second@example.com"),
User::create().email("taken@example.com"), ])
.exec(&mut db)
.await
);
assert_struct!(
t.log().pop_op(),
Operation::Transaction(Transaction::Start {
isolation: None,
read_only: false
})
);
assert_struct!(t.log().pop_op(), Operation::QuerySql(_)); assert_struct!(t.log().pop_op(), Operation::QuerySql(_)); assert_struct!(
t.log().pop_op(),
Operation::Transaction(Transaction::Rollback)
);
assert!(t.log().is_empty());
let users: Vec<User> = User::all().exec(&mut db).await?;
assert_eq!(1, users.len());
assert_eq!(users[0].email, "taken@example.com");
Ok(())
}
#[driver_test(id(ID), requires(sql))]
pub async fn batch_different_models_rolls_back_on_failure(t: &mut Test) -> Result<()> {
#[derive(Debug, toasty::Model)]
struct User {
#[key]
#[auto]
id: ID,
name: String,
}
#[derive(Debug, toasty::Model)]
struct Post {
#[key]
#[auto]
id: ID,
#[unique]
title: String,
}
let mut db = t.setup_db(models!(User, Post)).await;
Post::create().title("taken").exec(&mut db).await?;
t.log().clear();
assert_err!(
toasty::batch((
User::create().name("alice"),
Post::create().title("taken"), ))
.exec(&mut db)
.await
);
assert_struct!(
t.log().pop_op(),
Operation::Transaction(Transaction::Start {
isolation: None,
read_only: false
})
);
assert_struct!(t.log().pop_op(), Operation::QuerySql(_)); assert_struct!(
t.log().pop_op(),
Operation::Transaction(Transaction::Rollback)
);
assert!(t.log().is_empty());
let users: Vec<User> = User::all().exec(&mut db).await?;
assert!(users.is_empty());
let posts: Vec<Post> = Post::all().exec(&mut db).await?;
assert_eq!(1, posts.len());
Ok(())
}