use spg_engine::{Engine, QueryResult};
use spg_storage::Value;
fn one_row(r: QueryResult) -> Vec<Value> {
match r {
QueryResult::Rows { rows, .. } => {
assert_eq!(rows.len(), 1);
rows.into_iter().next().unwrap().values
}
_ => panic!(),
}
}
fn f(v: &Value) -> f64 {
match v {
Value::Float(x) => *x,
other => panic!("expected Float, got {other:?}"),
}
}
#[test]
fn random_returns_value_in_zero_to_one() {
let mut e = Engine::new();
let row = one_row(e.execute("SELECT random()").unwrap());
let v = f(&row[0]);
assert!((0.0..1.0).contains(&v), "got {v}");
}
#[test]
fn random_returns_float_type() {
let mut e = Engine::new();
let r = e.execute("SELECT random()").unwrap();
let QueryResult::Rows { columns, .. } = r else {
panic!()
};
assert_eq!(columns[0].ty, spg_storage::DataType::Float);
}
#[test]
fn random_takes_no_args() {
let mut e = Engine::new();
assert!(e.execute("SELECT random(1)").is_err());
}
#[test]
fn random_many_calls_distribute_widely() {
let mut e = Engine::new();
let mut min = 1.0_f64;
let mut max = 0.0_f64;
for _ in 0..50 {
let row = one_row(e.execute("SELECT random()").unwrap());
let v = f(&row[0]);
if v < min {
min = v;
}
if v > max {
max = v;
}
}
assert!(min < 0.5, "min={min} should fall below 0.5 in 50 samples");
assert!(max > 0.5, "max={max} should rise above 0.5 in 50 samples");
}
#[test]
fn random_in_where_clause() {
let mut e = Engine::new();
e.execute("CREATE TABLE u (id INT NOT NULL)").unwrap();
for i in 1..=100 {
e.execute(&format!("INSERT INTO u VALUES ({i})")).unwrap();
}
let r = e
.execute("SELECT count(*) FROM u WHERE random() < 0.5")
.unwrap();
let QueryResult::Rows { rows, .. } = r else {
panic!()
};
let count = match &rows[0].values[0] {
Value::BigInt(n) => *n,
Value::Int(n) => i64::from(*n),
other => panic!("got {other:?}"),
};
assert!((10..=90).contains(&count), "expected ~50, got {count}");
}
#[test]
fn random_inside_order_by_for_sampling() {
let mut e = Engine::new();
e.execute("CREATE TABLE u (id INT NOT NULL)").unwrap();
for i in 1..=10 {
e.execute(&format!("INSERT INTO u VALUES ({i})")).unwrap();
}
let r = e
.execute("SELECT id FROM u ORDER BY random() LIMIT 1")
.unwrap();
let QueryResult::Rows { rows, .. } = r else {
panic!()
};
assert_eq!(rows.len(), 1);
let id = match &rows[0].values[0] {
Value::Int(n) => *n,
other => panic!("got {other:?}"),
};
assert!((1..=10).contains(&id));
}