use spg_engine::{Engine, QueryResult};
use spg_storage::Value;
fn ok(eng: &mut Engine, sql: &str) -> QueryResult {
eng.execute(sql)
.unwrap_or_else(|e| panic!("{sql:?}: {e:?}"))
}
fn select_value(eng: &mut Engine, sql: &str) -> Value {
match ok(eng, sql) {
QueryResult::Rows { rows, .. } => rows
.into_iter()
.next()
.map(|mut r| r.values.remove(0))
.expect("at least one row"),
other => panic!("expected Rows, got {other:?}"),
}
}
fn select_rows(eng: &mut Engine, sql: &str) -> Vec<Vec<Value>> {
match ok(eng, sql) {
QueryResult::Rows { rows, .. } => rows.into_iter().map(|r| r.values).collect(),
other => panic!("expected Rows, got {other:?}"),
}
}
#[test]
fn int_array_create_insert_select_roundtrip() {
let mut eng = Engine::new();
ok(&mut eng, "CREATE TABLE t (xs INT[] NOT NULL)");
ok(&mut eng, "INSERT INTO t VALUES (ARRAY[1, 2, 3])");
let v = select_value(&mut eng, "SELECT xs FROM t");
assert!(matches!(v, Value::IntArray(ref a) if a.as_slice() == [Some(1), Some(2), Some(3)]));
}
#[test]
fn int_array_with_nulls() {
let mut eng = Engine::new();
ok(&mut eng, "CREATE TABLE t (xs INT[] NOT NULL)");
ok(&mut eng, "INSERT INTO t VALUES (ARRAY[1, NULL, 3])");
let v = select_value(&mut eng, "SELECT xs FROM t");
assert!(matches!(v, Value::IntArray(ref a) if a.as_slice() == [Some(1), None, Some(3)]));
}
#[test]
fn int_array_subscript_returns_int() {
let mut eng = Engine::new();
ok(&mut eng, "CREATE TABLE t (xs INT[] NOT NULL)");
ok(&mut eng, "INSERT INTO t VALUES (ARRAY[10, 20, 30])");
let v = select_value(&mut eng, "SELECT xs[2] FROM t");
assert!(matches!(v, Value::Int(20)));
}
#[test]
fn int_array_subscript_out_of_range_returns_null() {
let mut eng = Engine::new();
ok(&mut eng, "CREATE TABLE t (xs INT[] NOT NULL)");
ok(&mut eng, "INSERT INTO t VALUES (ARRAY[10, 20])");
let v = select_value(&mut eng, "SELECT xs[5] FROM t");
assert!(matches!(v, Value::Null));
}
#[test]
fn int_array_any() {
let mut eng = Engine::new();
ok(&mut eng, "CREATE TABLE t (xs INT[] NOT NULL)");
ok(&mut eng, "INSERT INTO t VALUES (ARRAY[1, 2, 3])");
let v = select_value(&mut eng, "SELECT 2 = ANY(xs) FROM t");
assert!(matches!(v, Value::Bool(true)));
}
#[test]
fn int_array_all() {
let mut eng = Engine::new();
ok(&mut eng, "CREATE TABLE t (xs INT[] NOT NULL)");
ok(&mut eng, "INSERT INTO t VALUES (ARRAY[10, 20, 30])");
let v = select_value(&mut eng, "SELECT 5 < ALL(xs) FROM t");
assert!(matches!(v, Value::Bool(true)));
}
#[test]
fn int_array_length() {
let mut eng = Engine::new();
ok(&mut eng, "CREATE TABLE t (xs INT[] NOT NULL)");
ok(&mut eng, "INSERT INTO t VALUES (ARRAY[1, 2, 3, 4, 5])");
let v = select_value(&mut eng, "SELECT array_length(xs, 1) FROM t");
assert!(matches!(v, Value::Int(5)));
}
#[test]
fn int_array_position() {
let mut eng = Engine::new();
ok(&mut eng, "CREATE TABLE t (xs INT[] NOT NULL)");
ok(&mut eng, "INSERT INTO t VALUES (ARRAY[7, 11, 13])");
let v = select_value(&mut eng, "SELECT array_position(xs, 11) FROM t");
assert!(matches!(v, Value::Int(2)));
let v = select_value(&mut eng, "SELECT array_position(xs, 999) FROM t");
assert!(matches!(v, Value::Null));
}
#[test]
fn int_array_unnest_emits_ints() {
let mut eng = Engine::new();
let rows = select_rows(
&mut eng,
"SELECT * FROM unnest(ARRAY[10, 20, 30]) AS u",
);
assert_eq!(rows.len(), 3);
assert!(matches!(rows[0][0], Value::Int(10)));
assert!(matches!(rows[1][0], Value::Int(20)));
assert!(matches!(rows[2][0], Value::Int(30)));
}
#[test]
fn int_array_concat_array_to_array() {
let mut eng = Engine::new();
let v = select_value(
&mut eng,
"SELECT ARRAY[1, 2] || ARRAY[3, 4]",
);
assert!(
matches!(v, Value::IntArray(ref a) if a.as_slice() == [Some(1), Some(2), Some(3), Some(4)])
);
}
#[test]
fn int_array_append_scalar() {
let mut eng = Engine::new();
let v = select_value(&mut eng, "SELECT ARRAY[1, 2] || 99");
assert!(matches!(v, Value::IntArray(ref a) if a.as_slice() == [Some(1), Some(2), Some(99)]));
}
#[test]
fn bigint_array_create_insert_select() {
let mut eng = Engine::new();
ok(&mut eng, "CREATE TABLE t (xs BIGINT[] NOT NULL)");
ok(
&mut eng,
"INSERT INTO t VALUES (ARRAY[9223372036854775807, 1, -1])",
);
let v = select_value(&mut eng, "SELECT xs FROM t");
assert!(matches!(
v,
Value::BigIntArray(ref a)
if a.as_slice() == [Some(9_223_372_036_854_775_807_i64), Some(1), Some(-1)]
));
}
#[test]
fn bigint_array_subscript_returns_bigint() {
let mut eng = Engine::new();
ok(&mut eng, "CREATE TABLE t (xs BIGINT[] NOT NULL)");
ok(&mut eng, "INSERT INTO t VALUES (ARRAY[1000000000000, 2])");
let v = select_value(&mut eng, "SELECT xs[1] FROM t");
assert!(matches!(v, Value::BigInt(1_000_000_000_000_i64)));
}
#[test]
fn int_array_cast_from_text() {
let mut eng = Engine::new();
let v = select_value(&mut eng, "SELECT '{1,2,3}'::INT[]");
assert!(matches!(v, Value::IntArray(ref a) if a.as_slice() == [Some(1), Some(2), Some(3)]));
}
#[test]
fn bigint_array_cast_widening_from_int_array() {
let mut eng = Engine::new();
let v = select_value(&mut eng, "SELECT (ARRAY[1, 2, 3])::BIGINT[]");
assert!(
matches!(v, Value::BigIntArray(ref a) if a.as_slice() == [Some(1_i64), Some(2), Some(3)])
);
}