ormer 0.2.8

A minimalist ORM framework that supports SQLite, PostgreSQL, MySQL, and SqlServer
#![cfg(feature = "sqlite")]

use ormer::{Database, DbType};

#[derive(Debug, Clone, ormer::Model)]
#[table = "batch_query_users"]
struct BatchUser {
    #[primary]
    id: i32,
    name: String,
    age: i32,
    #[has_many(BatchOrder.user_id)]
    orders: Vec<BatchOrder>,
}

#[derive(Debug, Clone, ormer::Model)]
#[table = "batch_query_orders"]
struct BatchOrder {
    #[primary]
    id: i32,
    #[foreign(BatchUser.id)]
    user_id: i32,
    total: i32,
}

async fn setup_db() -> ormer::Result<Database> {
    let db = Database::connect(DbType::Sqlite, ":memory:").await?;
    db.create_table::<BatchUser>().execute().await?;
    db.create_table::<BatchOrder>().execute().await?;

    db.insert(&[
        BatchUser {
            id: 1,
            name: "Alice".to_string(),
            age: 20,
            orders: Vec::new(),
        },
        BatchUser {
            id: 2,
            name: "Bob".to_string(),
            age: 25,
            orders: Vec::new(),
        },
    ])
    .execute()
    .await?;

    db.insert(&[
        BatchOrder {
            id: 1,
            user_id: 1,
            total: 100,
        },
        BatchOrder {
            id: 2,
            user_id: 1,
            total: 120,
        },
        BatchOrder {
            id: 3,
            user_id: 2,
            total: 80,
        },
    ])
    .execute()
    .await?;

    Ok(db)
}

#[tokio::test]
async fn sqlite_batch_returns_tuple_results() -> ormer::Result<()> {
    let db = setup_db().await?;

    let (users, orders, order_count): (Vec<BatchUser>, Vec<BatchOrder>, usize) = db
        .batch((
            db.select::<BatchUser>()
                .order_by(|u| u.id)
                .include(|u| u.orders),
            db.select::<BatchOrder>()
                .filter(|o| o.user_id.eq(1))
                .order_by(|o| o.id),
            db.select::<BatchOrder>().count(|o| o.id),
        ))
        .await?;

    assert_eq!(users.len(), 2);
    assert_eq!(users[0].name, "Alice");
    assert_eq!(users[0].orders.len(), 2);
    assert_eq!(users[1].orders.len(), 1);
    assert_eq!(
        orders.iter().map(|order| order.total).collect::<Vec<_>>(),
        vec![100, 120]
    );
    assert_eq!(order_count, 3);

    Ok(())
}

#[tokio::test]
async fn sqlite_batch_many_returns_vec_results() -> ormer::Result<()> {
    let db = setup_db().await?;
    let order_queries = vec![
        db.select::<BatchOrder>()
            .filter(|o| o.user_id.eq(1))
            .order_by(|o| o.id),
        db.select::<BatchOrder>()
            .filter(|o| o.user_id.eq(2))
            .order_by(|o| o.id),
    ];

    let orders: Vec<Vec<BatchOrder>> = db.batch_many(order_queries).await?;

    assert_eq!(orders.len(), 2);
    assert_eq!(orders[0].len(), 2);
    assert_eq!(orders[1].len(), 1);
    assert_eq!(orders[1][0].total, 80);

    Ok(())
}

#[tokio::test]
async fn sqlite_transaction_batch_uses_transaction_executor() -> ormer::Result<()> {
    let db = setup_db().await?;

    let (users, orders): (Vec<BatchUser>, Vec<BatchOrder>) = db
        .transaction(|tx| {
            Box::pin(async move {
                tx.batch((
                    tx.select::<BatchUser>().order_by(|u| u.id),
                    tx.select::<BatchOrder>()
                        .filter(|o| o.user_id.eq(1))
                        .order_by(|o| o.id),
                ))
                .await
            })
        })
        .await?;

    assert_eq!(
        users.iter().map(|user| user.age).collect::<Vec<_>>(),
        vec![20, 25]
    );
    assert_eq!(
        orders.iter().map(|order| order.id).collect::<Vec<_>>(),
        vec![1, 2]
    );

    Ok(())
}