benzin 0.4.0

An async extension for Diesel the safe, extensible ORM and Query Builder
use std::fmt::Debug;

use benzin::{RunQueryDsl, SaveChangesDsl, *};
use diesel::{QueryResult, prelude::*};

use crate::{User, UserForm, users};

type TestConnection = AsyncMysqlConnection;

diesel::define_sql_function!(fn pg_sleep(interval: diesel::sql_types::Double));

async fn setup(connection: &mut TestConnection) {
    diesel::sql_query(
        "CREATE TEMPORARY TABLE users (
                id INTEGER PRIMARY KEY AUTO_INCREMENT,
                name TEXT NOT NULL
            ) CHARACTER SET utf8mb4",
    )
    .execute(connection)
    .await
    .unwrap();
}

async fn connection() -> TestConnection {
    let db_url = std::env::var("MYSQL_DATABASE_URL").expect("MYSQL_DATABASE_URL");
    let mut conn = TestConnection::establish(&db_url).await.unwrap();
    setup(&mut conn).await;
    conn
}

#[tokio::test]
async fn test_basic_insert_and_load() -> QueryResult<()> {
    let conn = &mut connection().await;
    let res = diesel::insert_into(users::table)
        .values([users::name.eq("John Doe"), users::name.eq("Jane Doe")])
        .execute(conn)
        .await;
    assert_eq!(res, Ok(2), "User count does not match");
    let users = users::table
        .order_by(users::name)
        .load::<User>(conn)
        .await?;
    assert_eq!(&users[0].name, "Jane Doe");
    assert_eq!(&users[1].name, "John Doe");

    Ok(())
}

#[tokio::test]
async fn test_save_changes() -> QueryResult<()> {
    let conn = &mut connection().await;
    let res = diesel::insert_into(users::table)
        .values([users::name.eq("John Doe"), users::name.eq("Jane Doe")])
        .execute(conn)
        .await;
    assert_eq!(res, Ok(2), "User count does not match");
    let user = UserForm {
        id: 1,
        name: "Jack Doe",
    };
    let changed_user: User = user.save_changes(conn).await?;
    let expected_user = User {
        id: 1,
        name: String::from("Jack Doe"),
    };
    assert_eq!(changed_user, expected_user);

    Ok(())
}

#[tokio::test]
async fn test_first() -> QueryResult<()> {
    let conn = &mut connection().await;
    let res = diesel::insert_into(users::table)
        .values([users::name.eq("John Doe"), users::name.eq("Jane Doe")])
        .execute(conn)
        .await;
    assert_eq!(res, Ok(2), "User count does not match");
    let user = users::table
        .order_by(users::name)
        .first::<User>(conn)
        .await?;
    assert_eq!(&user.name, "Jane Doe");

    Ok(())
}

#[tokio::test]
async fn test_update() -> QueryResult<()> {
    let conn = &mut connection().await;
    let res = diesel::insert_into(users::table)
        .values([users::name.eq("John Doe"), users::name.eq("Jane Doe")])
        .execute(conn)
        .await;
    assert_eq!(res, Ok(2), "User count does not match");
    diesel::update(users::table)
        .filter(users::name.eq("John Doe"))
        .set(users::name.eq("Jack Doe"))
        .execute(conn)
        .await?;
    let users = users::table
        .order_by(users::name)
        .load::<User>(conn)
        .await?;
    assert_eq!(&users[0].name, "Jack Doe");
    assert_eq!(&users[1].name, "Jane Doe");

    Ok(())
}

#[tokio::test]
async fn test_transaction() -> QueryResult<()> {
    let mut conn = connection().await;
    let res = conn
        .transaction(|transaction| {
            Box::pin(async move {
                let res = diesel::insert_into(users::table)
                    .values([users::name.eq("John Doe"), users::name.eq("Jane Doe")])
                    .execute(transaction)
                    .await;
                assert_eq!(res, Ok(2), "User count does not match");
                let users = users::table
                    .order_by(users::name)
                    .load::<User>(transaction)
                    .await?;
                assert_eq!(&users[0].name, "Jane Doe");
                assert_eq!(&users[1].name, "John Doe");
                Err::<(), _>(diesel::result::Error::RollbackTransaction)
            })
        })
        .await;
    assert_eq!(
        res,
        Err(diesel::result::Error::RollbackTransaction),
        "Failed to rollback transaction"
    );
    Ok(())
}