aro-fletch 1.0.0

Fletch ORM persistence adapter for the Aro web framework
Documentation
#![cfg(all(
    feature = "query-adapters",
    any(feature = "sqlite", feature = "postgres", feature = "mysql")
))]

mod common;

use aro_core::pagination::PageRequest;
use aro_core::repository::{Paginatable, Queryable, Repository};
use aro_fletch::EntityQuery;
use common::{User, setup};
use fletch_orm::{Filter, Op, Order};

#[tokio::test]
async fn find_by_name_filter() {
    let (_pool, repo) = setup().await;
    repo.create(User {
        id: 1,
        name: "Alice".into(),
    })
    .await
    .unwrap();
    repo.create(User {
        id: 2,
        name: "Bob".into(),
    })
    .await
    .unwrap();
    repo.create(User {
        id: 3,
        name: "Alicia".into(),
    })
    .await
    .unwrap();

    let query = EntityQuery::new()
        .filter(Filter::new("name", Op::Like, "%Ali%"))
        .order_by("id", Order::Asc);
    let results = repo.find_by(query).await.unwrap();

    assert_eq!(results.len(), 2);
    assert_eq!(results[0].name, "Alice");
    assert_eq!(results[1].name, "Alicia");
}

#[tokio::test]
async fn find_by_empty_query_returns_all() {
    let (_pool, repo) = setup().await;
    repo.create(User {
        id: 1,
        name: "Alice".into(),
    })
    .await
    .unwrap();
    repo.create(User {
        id: 2,
        name: "Bob".into(),
    })
    .await
    .unwrap();

    let results = repo.find_by(EntityQuery::new()).await.unwrap();
    assert_eq!(results.len(), 2);
}

#[tokio::test]
async fn find_page_first_page() {
    let (_pool, repo) = setup().await;
    for (id, name) in [(1, "Alice"), (2, "Bob"), (3, "Charlie"), (4, "Diana")] {
        repo.create(User {
            id,
            name: name.into(),
        })
        .await
        .unwrap();
    }

    let page = repo
        .find_page(PageRequest {
            page: 1,
            per_page: 2,
        })
        .await
        .unwrap();

    assert_eq!(page.total, 4);
    assert_eq!(page.page, 1);
    assert_eq!(page.per_page, 2);
    assert_eq!(page.items.len(), 2);
    assert_eq!(page.items[0].id, 1);
    assert_eq!(page.items[1].id, 2);
    assert!(page.has_next_page());
}

#[tokio::test]
async fn find_page_second_page() {
    let (_pool, repo) = setup().await;
    for (id, name) in [(1, "Alice"), (2, "Bob"), (3, "Charlie")] {
        repo.create(User {
            id,
            name: name.into(),
        })
        .await
        .unwrap();
    }

    let page = repo
        .find_page(PageRequest {
            page: 2,
            per_page: 2,
        })
        .await
        .unwrap();

    assert_eq!(page.total, 3);
    assert_eq!(page.items.len(), 1);
    assert_eq!(page.items[0].id, 3);
    assert!(!page.has_next_page());
}

#[tokio::test]
async fn find_page_empty_table() {
    let (_pool, repo) = setup().await;

    let page = repo
        .find_page(PageRequest {
            page: 1,
            per_page: 10,
        })
        .await
        .unwrap();

    assert_eq!(page.total, 0);
    assert!(page.items.is_empty());
    assert!(!page.has_next_page());
}

#[tokio::test]
async fn find_page_by_applies_filter_to_total_and_items() {
    let (_pool, repo) = setup().await;
    for (id, name) in [(1, "Alice"), (2, "Bob"), (3, "Alicia"), (4, "Alix")] {
        repo.create(User {
            id,
            name: name.into(),
        })
        .await
        .unwrap();
    }

    let query = EntityQuery::new()
        .filter(Filter::new("name", Op::Like, "%Ali%"))
        .order_by("id", Order::Asc);
    let page = repo
        .find_page_by(
            query,
            PageRequest {
                page: 1,
                per_page: 2,
            },
        )
        .await
        .unwrap();

    assert_eq!(page.total, 3);
    assert_eq!(page.items.len(), 2);
    assert_eq!(page.items[0].name, "Alice");
    assert_eq!(page.items[1].name, "Alicia");
    assert!(page.has_next_page());
}

#[tokio::test]
async fn find_page_by_second_page_respects_filter() {
    let (_pool, repo) = setup().await;
    for (id, name) in [(1, "Alice"), (2, "Bob"), (3, "Alicia"), (4, "Alix")] {
        repo.create(User {
            id,
            name: name.into(),
        })
        .await
        .unwrap();
    }

    let query = EntityQuery::new()
        .filter(Filter::new("name", Op::Like, "%Ali%"))
        .order_by("id", Order::Asc);
    let page = repo
        .find_page_by(
            query,
            PageRequest {
                page: 2,
                per_page: 2,
            },
        )
        .await
        .unwrap();

    assert_eq!(page.total, 3);
    assert_eq!(page.items.len(), 1);
    assert_eq!(page.items[0].name, "Alix");
    assert!(!page.has_next_page());
}

#[tokio::test]
async fn find_page_by_empty_query_matches_find_page_total() {
    let (_pool, repo) = setup().await;
    for (id, name) in [(1, "Alice"), (2, "Bob"), (3, "Charlie")] {
        repo.create(User {
            id,
            name: name.into(),
        })
        .await
        .unwrap();
    }

    let request = PageRequest {
        page: 1,
        per_page: 10,
    };
    let unfiltered = repo.find_page(request.clone()).await.unwrap();
    let filtered = repo
        .find_page_by(EntityQuery::new(), request)
        .await
        .unwrap();

    assert_eq!(filtered.total, unfiltered.total);
    assert_eq!(filtered.items.len(), unfiltered.items.len());
}

#[tokio::test]
async fn find_page_by_preserves_custom_order() {
    let (_pool, repo) = setup().await;
    for (id, name) in [(1, "Alice"), (2, "Bob"), (3, "Charlie")] {
        repo.create(User {
            id,
            name: name.into(),
        })
        .await
        .unwrap();
    }

    let query = EntityQuery::new().order_by("name", Order::Desc);
    let page = repo
        .find_page_by(
            query,
            PageRequest {
                page: 1,
                per_page: 10,
            },
        )
        .await
        .unwrap();

    assert_eq!(page.items.len(), 3);
    assert_eq!(page.items[0].name, "Charlie");
    assert_eq!(page.items[1].name, "Bob");
    assert_eq!(page.items[2].name, "Alice");
}