use rust_ef::db_context::{DbContext, DbContextOptionsBuilder};
use rust_ef::prelude::*;
use rust_ef_sqlite::DbContextOptionsBuilderExt as _;
#[derive(Debug, Clone, EntityType)]
#[table("lb_items")]
struct LbItem {
#[primary_key]
#[auto_increment]
id: i32,
#[required]
name: String,
value: i32,
}
fn make_ctx() -> DbContext {
let mut builder = DbContextOptionsBuilder::new();
builder.use_sqlite_in_memory();
let options = builder.build();
DbContext::from_options(&options).unwrap()
}
async fn seed() -> DbContext {
let mut ctx = make_ctx();
ctx.set::<LbItem>();
ctx.ensure_created().await.unwrap();
for (i, (name, value)) in [("alpha", 10), ("beta", 20), ("gamma", 30)]
.iter()
.enumerate()
{
ctx.set::<LbItem>().add(LbItem {
id: 0,
name: (*name).into(),
value: *value,
});
let _ = i;
}
ctx.save_changes().await.unwrap();
ctx
}
#[tokio::test]
async fn test_untyped_closure_basic_filter() {
let mut ctx = seed().await;
let rows = linq!(ctx.set::<LbItem>(), |b| b.value > 15)
.to_list()
.await
.unwrap();
assert_eq!(rows.len(), 2);
let names: Vec<&str> = rows.iter().map(|r| r.name.as_str()).collect();
assert!(names.contains(&"beta"));
assert!(names.contains(&"gamma"));
}
#[tokio::test]
async fn test_untyped_closure_with_order_by() {
let mut ctx = seed().await;
let rows = linq!(ctx.set::<LbItem>(), |b| b.value > 0; order_by b.value)
.to_list()
.await
.unwrap();
assert_eq!(rows.len(), 3);
assert_eq!(rows[0].value, 10);
assert_eq!(rows[1].value, 20);
assert_eq!(rows[2].value, 30);
}
#[tokio::test]
async fn test_untyped_closure_with_include() {
let mut ctx = seed().await;
let rows = linq!(ctx.set::<LbItem>(), |b| b.value >= 10; order_by b.id)
.to_list()
.await
.unwrap();
assert_eq!(rows.len(), 3);
}
#[tokio::test]
async fn test_untyped_closure_aggregate() {
let mut ctx = seed().await;
let total: f64 = linq!(ctx.set::<LbItem>(), |b| b.value > 0; sum b.value)
.await
.unwrap();
assert_eq!(total, 60.0);
}
#[tokio::test]
async fn test_untyped_closure_count() {
let mut ctx = seed().await;
let count = linq!(ctx.set::<LbItem>(), |b| b.value > 15; count)
.await
.unwrap();
assert_eq!(count, 2);
}
#[tokio::test]
async fn test_typed_closure_still_works() {
let mut ctx = seed().await;
let rows = linq!(ctx.set::<LbItem>(), |b: LbItem| b.value > 15)
.to_list()
.await
.unwrap();
assert_eq!(rows.len(), 2);
}
#[tokio::test]
async fn test_untyped_closure_with_select() {
let mut ctx = seed().await;
let rows: Vec<(i32, String)> =
linq!(ctx.set::<LbItem>(), |b| b.value > 0; select (b.id, b.name))
.to_list_typed_2::<i32, String>()
.await
.unwrap();
assert_eq!(rows.len(), 3);
}
#[tokio::test]
async fn test_reusable_filter_untyped_closure_with_typed_source() {
let mut ctx = seed().await;
let set = ctx.set::<LbItem>();
let expr = linq!(|b: LbItem| b.value > 15);
let rows = set.filter(expr).to_list().await.unwrap();
assert_eq!(rows.len(), 2);
}