#![allow(dead_code)]
use rust_ef::db_context::{DbContext, DbContextOptionsBuilder};
use rust_ef::entity::IEntityType;
use rust_ef::error::EFResult;
use rust_ef::migration::{MigrationDialect, MigrationEngine};
use rust_ef::provider::IDatabaseProvider;
use std::sync::Arc;
use super::test_item::TestItem;
#[allow(clippy::type_complexity)]
pub fn db_context_with_provider(provider: Arc<dyn IDatabaseProvider>) -> DbContext {
let p = provider.clone();
let factory: Arc<dyn Fn(&str) -> EFResult<Arc<dyn IDatabaseProvider>> + Send + Sync> =
Arc::new(move |_| Ok(p.clone()));
let mut builder = DbContextOptionsBuilder::new();
builder.connection_string("integration-test");
builder.set_provider_factory("integration", "integration-test", factory);
DbContext::from_options(&builder.build()).expect("DbContext")
}
pub async fn reset_schema(
provider: &dyn IDatabaseProvider,
dialect: MigrationDialect,
) -> EFResult<()> {
let meta = TestItem::entity_meta();
let engine = MigrationEngine::new(dialect);
let _ = engine
.ensure_deleted(provider, std::slice::from_ref(&meta))
.await;
engine.ensure_created(provider, &[meta]).await
}
pub async fn run_crud_lifecycle(
provider: Arc<dyn IDatabaseProvider>,
dialect: MigrationDialect,
) -> EFResult<()> {
reset_schema(&*provider, dialect).await?;
let mut ctx = db_context_with_provider(provider);
ctx.set::<TestItem>().add(TestItem {
id: 0,
name: "Alpha".into(),
value: 1.0,
});
ctx.set::<TestItem>().add(TestItem {
id: 0,
name: "Beta".into(),
value: 2.0,
});
let saved = ctx.save_changes().await?;
assert_eq!(saved.added, 2);
let items = ctx.set::<TestItem>().query().to_list().await?;
assert_eq!(items.len(), 2);
let one = items
.into_iter()
.find(|i| i.name == "Alpha")
.expect("Alpha row");
ctx.set::<TestItem>().clear_entries();
ctx.set::<TestItem>().attach(one);
ctx.set::<TestItem>()
.tracked_entries_mut()
.next()
.unwrap()
.name = "AlphaUpdated".into();
ctx.set::<TestItem>().detect_changes();
let updated = ctx.save_changes().await?;
assert_eq!(updated.updated, 1);
let after_update = ctx.set::<TestItem>().query().to_list().await?;
assert!(after_update.iter().any(|i| i.name == "AlphaUpdated"));
ctx.set::<TestItem>().clear_entries();
ctx.set::<TestItem>().attach(
after_update
.into_iter()
.find(|i| i.name == "Beta")
.expect("Beta row"),
);
ctx.set::<TestItem>().remove_at(0).unwrap();
let deleted = ctx.save_changes().await?;
assert_eq!(deleted.deleted, 1);
assert_eq!(ctx.set::<TestItem>().query().count().await?, 1);
Ok(())
}
pub async fn run_filter_with_in_operator(
provider: Arc<dyn IDatabaseProvider>,
dialect: MigrationDialect,
) -> EFResult<()> {
use rust_ef::linq;
reset_schema(&*provider, dialect).await?;
let mut ctx = db_context_with_provider(provider);
ctx.set::<TestItem>().add(TestItem {
id: 0,
name: "A".into(),
value: 1.0,
});
ctx.set::<TestItem>().add(TestItem {
id: 0,
name: "B".into(),
value: 2.0,
});
ctx.set::<TestItem>().add(TestItem {
id: 0,
name: "C".into(),
value: 3.0,
});
ctx.save_changes().await?;
let items = ctx
.set::<TestItem>()
.filter(linq!(TestItem, |t| t.value > 1.5))
.to_list()
.await?;
assert_eq!(items.len(), 2);
let items_null = ctx
.set::<TestItem>()
.filter(linq!(TestItem, |t| t.value.is_null()))
.to_list()
.await?;
assert_eq!(items_null.len(), 0);
let items_not_null = ctx
.set::<TestItem>()
.filter(linq!(TestItem, |t| t.name.is_not_null()))
.to_list()
.await?;
assert_eq!(items_not_null.len(), 3);
Ok(())
}
pub async fn run_limit_and_offset(
provider: Arc<dyn IDatabaseProvider>,
dialect: MigrationDialect,
) -> EFResult<()> {
reset_schema(&*provider, dialect).await?;
let mut ctx = db_context_with_provider(provider);
for i in 0..10 {
ctx.set::<TestItem>().add(TestItem {
id: 0,
name: format!("Item{}", i),
value: i as f64,
});
}
ctx.save_changes().await?;
let items = ctx.set::<TestItem>().query().take(3).to_list().await?;
assert_eq!(items.len(), 3);
let items = ctx
.set::<TestItem>()
.query()
.skip(8)
.take(5)
.to_list()
.await?;
assert_eq!(items.len(), 2);
Ok(())
}
pub async fn run_count_and_any(
provider: Arc<dyn IDatabaseProvider>,
dialect: MigrationDialect,
) -> EFResult<()> {
use rust_ef::linq;
reset_schema(&*provider, dialect).await?;
let mut ctx = db_context_with_provider(provider);
for i in 0..5 {
ctx.set::<TestItem>().add(TestItem {
id: 0,
name: "X".into(),
value: i as f64,
});
}
ctx.save_changes().await?;
let count = ctx.set::<TestItem>().query().count().await?;
assert_eq!(count, 5);
let any = ctx
.set::<TestItem>()
.filter(linq!(TestItem, |t| t.value == 3))
.any()
.await?;
assert!(any);
let any_none = ctx
.set::<TestItem>()
.filter(linq!(TestItem, |t| t.value == 99))
.any()
.await?;
assert!(!any_none);
Ok(())
}
pub async fn run_aggregation_queries(
provider: Arc<dyn IDatabaseProvider>,
dialect: MigrationDialect,
) -> EFResult<()> {
use rust_ef::linq;
reset_schema(&*provider, dialect).await?;
let mut ctx = db_context_with_provider(provider);
for i in 1..=5 {
ctx.set::<TestItem>().add(TestItem {
id: 0,
name: "Agg".into(),
value: i as f64,
});
}
ctx.save_changes().await?;
let sum = linq!(ctx.set::<TestItem>().query(), |b: TestItem| true; sum b.value).await?;
assert!((sum - 15.0).abs() < 0.01, "sum should be 15.0, got {}", sum);
let avg = linq!(ctx.set::<TestItem>().query(), |b: TestItem| true; avg b.value).await?;
assert!((avg - 3.0).abs() < 0.01, "avg should be 3.0, got {}", avg);
Ok(())
}
pub async fn run_empty_result_handling(
provider: Arc<dyn IDatabaseProvider>,
dialect: MigrationDialect,
) -> EFResult<()> {
reset_schema(&*provider, dialect).await?;
let mut ctx = db_context_with_provider(provider);
let items = ctx.set::<TestItem>().query().to_list().await?;
assert!(items.is_empty());
let count = ctx.set::<TestItem>().query().count().await?;
assert_eq!(count, 0);
let any = ctx.set::<TestItem>().query().any().await?;
assert!(!any);
let first = ctx.set::<TestItem>().query().first_or_default().await?;
assert!(first.is_none());
Ok(())
}
pub async fn run_ensure_created_and_deleted(
provider: Arc<dyn IDatabaseProvider>,
dialect: MigrationDialect,
) -> EFResult<()> {
let meta = TestItem::entity_meta();
let engine = MigrationEngine::new(dialect);
let _ = engine
.ensure_deleted(&*provider, std::slice::from_ref(&meta))
.await;
let mut ctx = db_context_with_provider(provider);
ctx.set::<TestItem>();
ctx.ensure_created().await?;
ctx.set::<TestItem>().add(TestItem {
id: 0,
name: "Created".into(),
value: 1.0,
});
let result = ctx.save_changes().await?;
assert_eq!(result.added, 1);
let items = ctx.set::<TestItem>().query().to_list().await?;
assert_eq!(items.len(), 1);
ctx.ensure_deleted().await?;
ctx.ensure_created().await?;
let items = ctx.set::<TestItem>().query().to_list().await?;
assert!(items.is_empty());
Ok(())
}
pub async fn run_has_data_seed(
provider: Arc<dyn IDatabaseProvider>,
dialect: MigrationDialect,
) -> EFResult<()> {
let meta = TestItem::entity_meta();
let engine = MigrationEngine::new(dialect);
let _ = engine
.ensure_deleted(&*provider, std::slice::from_ref(&meta))
.await;
let mut ctx = db_context_with_provider(provider);
ctx.model().entity::<TestItem>().has_data(&[TestItem {
id: 1,
name: "Seed".into(),
value: 9.0,
}]);
ctx.set::<TestItem>();
ctx.ensure_created().await?;
let items = ctx.set::<TestItem>().query().to_list().await?;
assert_eq!(items.len(), 1);
assert_eq!(items[0].name, "Seed");
assert!((items[0].value - 9.0).abs() < f64::EPSILON);
Ok(())
}