use spg_engine::{Engine, QueryResult};
use spg_storage::Value;
fn rows_of(r: QueryResult) -> Vec<Vec<Value>> {
match r {
QueryResult::Rows { rows, .. } => rows.into_iter().map(|r| r.values).collect(),
other => panic!("expected Rows, got {other:?}"),
}
}
#[test]
fn as_of_segment_returns_only_frozen_rows() {
let mut e = Engine::new();
e.execute("CREATE TABLE t (id INT NOT NULL, name TEXT NOT NULL)")
.unwrap();
e.execute("CREATE INDEX by_id ON t (id)").unwrap();
for id in 0..6i64 {
e.execute(&format!("INSERT INTO t VALUES ({id}, 'r-{id}')"))
.unwrap();
}
e.freeze_oldest_to_cold("t", "by_id", 3).unwrap();
let rows = rows_of(e.execute("SELECT id FROM t AS OF SEGMENT '0'").unwrap());
assert_eq!(rows.len(), 3);
let mut ids: Vec<i64> = rows
.into_iter()
.map(|r| match r.into_iter().next().unwrap() {
Value::Int(n) => n as i64,
other => panic!("expected Int, got {other:?}"),
})
.collect();
ids.sort();
assert_eq!(ids, vec![0, 1, 2]);
}
#[test]
fn as_of_segment_supports_where_filter() {
let mut e = Engine::new();
e.execute("CREATE TABLE t (id INT NOT NULL, name TEXT NOT NULL)")
.unwrap();
e.execute("CREATE INDEX by_id ON t (id)").unwrap();
for id in 0..6i64 {
e.execute(&format!("INSERT INTO t VALUES ({id}, 'r-{id}')"))
.unwrap();
}
e.freeze_oldest_to_cold("t", "by_id", 3).unwrap();
let rows = rows_of(
e.execute("SELECT id FROM t AS OF SEGMENT '0' WHERE id = 1")
.unwrap(),
);
assert_eq!(rows.len(), 1);
match &rows[0][0] {
Value::Int(1) => {}
other => panic!("expected Int(1), got {other:?}"),
}
}
#[test]
fn as_of_segment_supports_limit() {
let mut e = Engine::new();
e.execute("CREATE TABLE t (id INT NOT NULL, name TEXT NOT NULL)")
.unwrap();
e.execute("CREATE INDEX by_id ON t (id)").unwrap();
for id in 0..6i64 {
e.execute(&format!("INSERT INTO t VALUES ({id}, 'r-{id}')"))
.unwrap();
}
e.freeze_oldest_to_cold("t", "by_id", 5).unwrap();
let rows = rows_of(
e.execute("SELECT id FROM t AS OF SEGMENT '0' LIMIT 2")
.unwrap(),
);
assert_eq!(rows.len(), 2);
}
#[test]
fn as_of_segment_with_unknown_id_errors() {
let mut e = Engine::new();
e.execute("CREATE TABLE t (id INT NOT NULL)").unwrap();
let r = e.execute("SELECT id FROM t AS OF SEGMENT '42'");
assert!(r.is_err(), "unknown segment id must error");
}
#[test]
fn as_of_segment_rejects_join() {
let mut e = Engine::new();
e.execute("CREATE TABLE t (id INT NOT NULL)").unwrap();
e.execute("CREATE TABLE u (id INT NOT NULL)").unwrap();
e.execute("CREATE INDEX by_id ON t (id)").unwrap();
e.execute("INSERT INTO t VALUES (1)").unwrap();
e.freeze_oldest_to_cold("t", "by_id", 1).unwrap();
let r = e.execute("SELECT t.id FROM t AS OF SEGMENT '0' JOIN u ON t.id = u.id");
assert!(
r.is_err(),
"AS OF SEGMENT + JOIN must surface STABILITY carve-out error"
);
}
#[test]
fn as_of_segment_parses_and_display_round_trips() {
use spg_sql::ast::Statement;
use spg_sql::parser::parse_statement;
let sql = "SELECT id FROM t AS OF SEGMENT '5' WHERE id = 1";
let stmt = parse_statement(sql).unwrap();
let Statement::Select(ref s) = stmt else {
panic!("expected Select");
};
assert_eq!(s.from.as_ref().unwrap().primary.as_of_segment, Some(5));
}