#![cfg(feature = "std")]
use graphitesql::{Connection, Value};
use std::process::Command;
fn sqlite3(setup: &[&str], query: &str) -> String {
let mut script = String::new();
for s in setup {
script.push_str(s);
script.push_str(";\n");
}
script.push_str(query);
script.push(';');
let o = Command::new("sqlite3")
.arg(":memory:")
.arg(&script)
.output()
.unwrap();
String::from_utf8_lossy(&o.stdout).trim_end().to_string()
}
fn render(result: &graphitesql::QueryResult) -> String {
result
.rows
.iter()
.map(|row| {
row.iter()
.map(|v| match v {
Value::Null => String::new(),
Value::Integer(i) => i.to_string(),
Value::Text(s) => String::from(s.as_str()),
Value::Real(r) => graphitesql::exec::eval::format_real(*r),
Value::Blob(b) => b.iter().map(|x| format!("{x:02x}")).collect(),
})
.collect::<Vec<_>>()
.join("|")
})
.collect::<Vec<_>>()
.join("\n")
}
fn check(setup: &[&str], queries: &[&str]) {
let mut g = Connection::open_memory().unwrap();
for s in setup {
g.execute(s).unwrap();
}
for q in queries {
let want = sqlite3(setup, q);
let got = render(&g.query(q).unwrap());
assert_eq!(got, want, "bare-aggregate HAVING diverged: {q}");
}
}
#[test]
fn bare_aggregate_having_matches_sqlite3() {
if Command::new("sqlite3").arg("--version").output().is_err() {
eprintln!("sqlite3 not found; skipping");
return;
}
let setup = [
"CREATE TABLE t(a INTEGER, b TEXT)",
"INSERT INTO t VALUES(1,'x'),(2,'y'),(3,'z')",
];
check(
&setup,
&[
"SELECT count(*) FROM t HAVING count(*) > 5", "SELECT count(*) FROM t HAVING count(*) > 2", "SELECT sum(a) FROM t HAVING sum(a) >= 6", "SELECT max(a) FROM t HAVING max(a) > 2", "SELECT count(*), sum(a) FROM t HAVING count(*) >= 3", "SELECT count(*) FROM t HAVING count(*) BETWEEN 1 AND 3", "SELECT count(*) FROM t HAVING sum(a) > 100", "SELECT count(*) FROM t HAVING sum(a) = 6", ],
);
check(
&["CREATE TABLE e(a INTEGER)"],
&[
"SELECT count(*) FROM e HAVING count(*) > 0", "SELECT count(*) FROM e HAVING count(*) = 0", "SELECT sum(a) FROM e HAVING count(*) = 0", ],
);
}