use vantage_expressions::{ExprDataSource, Expression, ExpressiveEnum};
use vantage_sql::sqlite::{AnySqliteType, SqliteDB};
use vantage_sql::sqlite_expr;
use vantage_types::Record;
fn records(result: AnySqliteType) -> Vec<Record<AnySqliteType>> {
Vec::<Record<AnySqliteType>>::try_from(result).unwrap()
}
async fn setup() -> (SqliteDB, SqliteDB) {
let config_db = SqliteDB::connect("sqlite::memory:").await.unwrap();
let shop_db = SqliteDB::connect("sqlite::memory:").await.unwrap();
sqlx::query("CREATE TABLE config (key TEXT PRIMARY KEY, value INTEGER NOT NULL)")
.execute(config_db.pool())
.await
.unwrap();
sqlx::query("INSERT INTO config VALUES ('min_price', 150)")
.execute(config_db.pool())
.await
.unwrap();
sqlx::query(
"CREATE TABLE product (id TEXT PRIMARY KEY, name TEXT NOT NULL, price INTEGER NOT NULL)",
)
.execute(shop_db.pool())
.await
.unwrap();
let insert = sqlite_expr!(
"INSERT INTO product VALUES ({}, {}, {}), ({}, {}, {}), ({}, {}, {})",
"a",
"Cheap Thing",
50i64,
"b",
"Mid Thing",
150i64,
"c",
"Expensive Thing",
300i64
);
shop_db.execute(&insert).await.unwrap();
(config_db, shop_db)
}
#[tokio::test]
async fn test_cross_database_deferred() {
let (config_db, shop_db) = setup().await;
let threshold_query = sqlite_expr!("SELECT value FROM config WHERE key = {}", "min_price");
let deferred_threshold = config_db.defer(threshold_query);
let shop_query = Expression::<AnySqliteType>::new(
"SELECT name FROM product WHERE price >= {} ORDER BY price",
vec![ExpressiveEnum::Deferred(deferred_threshold)],
);
let result = records(shop_db.execute(&shop_query).await.unwrap());
assert_eq!(result.len(), 2);
assert_eq!(
result[0]["name"].try_get::<String>(),
Some("Mid Thing".to_string())
);
assert_eq!(
result[1]["name"].try_get::<String>(),
Some("Expensive Thing".to_string())
);
}
#[tokio::test]
async fn test_deferred_mixed_with_scalars() {
let (config_db, shop_db) = setup().await;
let threshold_query = sqlite_expr!("SELECT value FROM config WHERE key = {}", "min_price");
let deferred_threshold = config_db.defer(threshold_query);
let shop_query = Expression::<AnySqliteType>::new(
"SELECT name FROM product WHERE price >= {} AND name != {} ORDER BY price",
vec![
ExpressiveEnum::Deferred(deferred_threshold),
ExpressiveEnum::Scalar(AnySqliteType::new("Mid Thing".to_string())),
],
);
let result = records(shop_db.execute(&shop_query).await.unwrap());
assert_eq!(result.len(), 1);
assert_eq!(
result[0]["name"].try_get::<String>(),
Some("Expensive Thing".to_string())
);
}
#[tokio::test]
async fn test_nested_deferred() {
let (config_db, shop_db) = setup().await;
let threshold_query = sqlite_expr!("SELECT value FROM config WHERE key = {}", "min_price");
let deferred_threshold = config_db.defer(threshold_query);
let inner = Expression::<AnySqliteType>::new(
"price >= {}",
vec![ExpressiveEnum::Deferred(deferred_threshold)],
);
let shop_query = sqlite_expr!("SELECT name FROM product WHERE {} ORDER BY price", (inner));
let result = records(shop_db.execute(&shop_query).await.unwrap());
assert_eq!(result.len(), 2);
assert_eq!(
result[0]["name"].try_get::<String>(),
Some("Mid Thing".to_string())
);
assert_eq!(
result[1]["name"].try_get::<String>(),
Some("Expensive Thing".to_string())
);
}