#![cfg(feature = "std")]
use graphitesql::{Connection, Value};
fn rows(c: &Connection, sql: &str) -> Vec<Vec<Value>> {
c.query(sql).unwrap().rows
}
#[test]
fn group_by_position_resolves_to_column() {
let mut c = Connection::open_memory().unwrap();
c.execute("CREATE TABLE t(a)").unwrap();
c.execute("INSERT INTO t VALUES(1),(1),(2),(3),(4)")
.unwrap();
assert_eq!(
rows(&c, "SELECT a, count(*) FROM t GROUP BY 1 ORDER BY 1"),
vec![
vec![Value::Integer(1), Value::Integer(2)],
vec![Value::Integer(2), Value::Integer(1)],
vec![Value::Integer(3), Value::Integer(1)],
vec![Value::Integer(4), Value::Integer(1)],
]
);
assert_eq!(
rows(&c, "SELECT a%2 p, count(*) FROM t GROUP BY 1 ORDER BY 1"),
vec![
vec![Value::Integer(0), Value::Integer(2)],
vec![Value::Integer(1), Value::Integer(3)],
]
);
assert_eq!(
rows(&c, "SELECT a, count(*) FROM t GROUP BY 1 ORDER BY 1"),
rows(&c, "SELECT a, count(*) FROM t GROUP BY a ORDER BY a")
);
}
#[test]
fn positional_term_out_of_range_message_matches_sqlite() {
let c = Connection::open_memory().unwrap();
let err = |sql: &str| {
c.query(sql)
.unwrap_err()
.to_string()
.trim_start_matches("error: ")
.to_string()
};
assert_eq!(
err("SELECT 1 ORDER BY 2"),
"1st ORDER BY term out of range - should be between 1 and 1"
);
assert_eq!(
err("SELECT 1,2,3 ORDER BY 5"),
"1st ORDER BY term out of range - should be between 1 and 3"
);
assert_eq!(
err("SELECT 1 AS a ORDER BY a, 5"),
"2nd ORDER BY term out of range - should be between 1 and 1"
);
assert_eq!(
err("SELECT 1 ORDER BY 1, 1, 4"),
"3rd ORDER BY term out of range - should be between 1 and 1"
);
assert_eq!(
err("SELECT 1,2 GROUP BY 3"),
"1st GROUP BY term out of range - should be between 1 and 2"
);
assert_eq!(
err("SELECT 1,2 GROUP BY 1, 3"),
"2nd GROUP BY term out of range - should be between 1 and 2"
);
assert_eq!(
err("SELECT 1 a, 2 b GROUP BY 9 ORDER BY 8"),
"1st ORDER BY term out of range - should be between 1 and 2"
);
assert_eq!(
err("SELECT 1 a, 2 b GROUP BY 9 ORDER BY 1"),
"1st GROUP BY term out of range - should be between 1 and 2"
);
assert_eq!(
err("SELECT 1 ORDER BY +2"),
"1st ORDER BY term out of range - should be between 1 and 1"
);
let many = |n: usize| core::iter::repeat_n("1", n).collect::<Vec<_>>().join(",");
assert_eq!(
err(&format!("SELECT {} ORDER BY {},99", many(12), many(12))),
"13th ORDER BY term out of range - should be between 1 and 12"
);
assert_eq!(
err(&format!("SELECT {} ORDER BY {},99", many(21), many(20))),
"21st ORDER BY term out of range - should be between 1 and 21"
);
assert!(c.query("SELECT 1 ORDER BY 1.0").is_ok());
assert!(c.query("SELECT 1 ORDER BY '2'").is_ok());
}
#[test]
fn signed_positional_order_by_resolves_to_column() {
let mut c = Connection::open_memory().unwrap();
c.execute("CREATE TABLE t(a, b)").unwrap();
c.execute("INSERT INTO t VALUES(30, 11), (10, 22), (20, 33)")
.unwrap();
let sorted_by_a = vec![
vec![Value::Integer(10), Value::Integer(22)],
vec![Value::Integer(20), Value::Integer(33)],
vec![Value::Integer(30), Value::Integer(11)],
];
for q in [
"SELECT a, b FROM t ORDER BY +1",
"SELECT a, b FROM t ORDER BY (1)",
"SELECT a, b FROM t ORDER BY 1 COLLATE BINARY",
"SELECT a, b FROM t ORDER BY 1",
"SELECT a, b FROM t ORDER BY a",
] {
assert_eq!(rows(&c, q), sorted_by_a, "{q}");
}
assert_eq!(
rows(&c, "SELECT a, b FROM t ORDER BY +2 DESC"),
vec![
vec![Value::Integer(20), Value::Integer(33)],
vec![Value::Integer(10), Value::Integer(22)],
vec![Value::Integer(30), Value::Integer(11)],
]
);
assert_eq!(
rows(
&c,
"SELECT a, b FROM t UNION SELECT a, b FROM t ORDER BY +2"
),
rows(&c, "SELECT a, b FROM t UNION SELECT a, b FROM t ORDER BY 2")
);
}
#[test]
fn signed_positional_group_by_resolves_to_column() {
let mut c = Connection::open_memory().unwrap();
c.execute("CREATE TABLE t(a, b)").unwrap();
c.execute("INSERT INTO t VALUES(1, 5), (1, 6), (2, 7), (3, 8)")
.unwrap();
let grouped = vec![
vec![Value::Integer(1), Value::Integer(2)],
vec![Value::Integer(2), Value::Integer(1)],
vec![Value::Integer(3), Value::Integer(1)],
];
for q in [
"SELECT a, count(*) FROM t GROUP BY +1 ORDER BY +1",
"SELECT a, count(*) FROM t GROUP BY (1) ORDER BY 1",
"SELECT a, count(*) FROM t GROUP BY 1 ORDER BY 1",
"SELECT a, count(*) FROM t GROUP BY a ORDER BY a",
] {
assert_eq!(rows(&c, q), grouped, "{q}");
}
}
#[test]
fn positional_group_by_to_aggregate_is_rejected() {
let mut c = Connection::open_memory().unwrap();
c.execute("CREATE TABLE t(a, b)").unwrap();
c.execute("INSERT INTO t VALUES(1, 2), (3, 4)").unwrap();
let err = |sql: &str| {
c.query(sql)
.unwrap_err()
.to_string()
.trim_start_matches("error: ")
.to_string()
};
let msg = "aggregate functions are not allowed in the GROUP BY clause";
for q in [
"SELECT a, count(*) FROM t GROUP BY 2",
"SELECT a, count(*) FROM t GROUP BY +2",
"SELECT a, count(*) FROM t GROUP BY (2)",
"SELECT a, a + sum(b) FROM t GROUP BY 2",
"SELECT a, count(*) FROM t GROUP BY count(*)",
] {
assert_eq!(err(q), msg, "{q}");
}
assert!(c.query("SELECT a, count(*) FROM t GROUP BY 1").is_ok());
}
#[test]
fn generate_series_zero_step_is_one() {
let c = Connection::open_memory().unwrap();
assert_eq!(
rows(&c, "SELECT count(*) FROM generate_series(0,5,0)")[0][0],
Value::Integer(6)
);
assert_eq!(
rows(
&c,
"SELECT value FROM generate_series(0,3,0) ORDER BY value"
),
vec![
vec![Value::Integer(0)],
vec![Value::Integer(1)],
vec![Value::Integer(2)],
vec![Value::Integer(3)],
]
);
assert_eq!(
rows(&c, "SELECT count(*) FROM generate_series(10,1,0)")[0][0],
Value::Integer(0)
);
}