use nodedb_client::NodeDb;
use crate::common::origin::OriginServer;
use crate::common::sql::{OriginPgwire, open_lite};
const CREATE_LITE: &str = "CREATE COLLECTION col_parity (
id BIGINT NOT NULL PRIMARY KEY,
ts TIMESTAMP NOT NULL,
value FLOAT64
) WITH storage = 'columnar'";
const CREATE_ORIGIN: &str = "CREATE COLLECTION col_parity (
id BIGINT NOT NULL,
ts TIMESTAMP NOT NULL,
value FLOAT64
) WITH (engine='columnar')";
#[tokio::test]
async fn columnar_create_and_drop() {
let Some(_origin) = OriginServer::try_spawn_with_pgwire() else {
eprintln!("SKIP: Origin binary unavailable (set NODEDB_BIN or run via `cargo nextest`)");
return;
};
let pg = OriginPgwire::connect().await;
let db = open_lite().await;
pg.execute(CREATE_ORIGIN).await;
db.execute_sql(CREATE_LITE, &[])
.await
.expect("Lite CREATE columnar col_parity");
pg.execute("DROP COLLECTION col_parity").await;
db.execute_sql("DROP COLLECTION col_parity", &[])
.await
.expect("Lite DROP columnar col_parity");
}
#[tokio::test]
async fn columnar_insert_acknowledged() {
let Some(_origin) = OriginServer::try_spawn_with_pgwire() else {
eprintln!("SKIP: Origin binary unavailable (set NODEDB_BIN or run via `cargo nextest`)");
return;
};
let pg = OriginPgwire::connect().await;
let db = open_lite().await;
pg.execute(CREATE_ORIGIN).await;
db.execute_sql(CREATE_LITE, &[]).await.expect("Lite CREATE");
pg.execute("INSERT INTO col_parity (id, ts, value) VALUES (1, '2024-01-01 00:00:00', 3.14)")
.await;
let r = db
.execute_sql(
"INSERT INTO col_parity (id, ts, value) VALUES (1, '2024-01-01 00:00:00', 3.14)",
&[],
)
.await
.expect("Lite columnar INSERT");
assert!(
r.rows_affected >= 1,
"Lite columnar INSERT must acknowledge >= 1 affected row, got {}",
r.rows_affected
);
}
#[tokio::test]
async fn columnar_select_all_rows() {
let Some(_origin) = OriginServer::try_spawn_with_pgwire() else {
eprintln!("SKIP: Origin binary unavailable (set NODEDB_BIN or run via `cargo nextest`)");
return;
};
let pg = OriginPgwire::connect().await;
let db = open_lite().await;
pg.execute(CREATE_ORIGIN).await;
db.execute_sql(CREATE_LITE, &[]).await.expect("Lite CREATE");
for (id, val) in [(1i64, 1.11f64), (2, 2.22), (3, 3.33)] {
let sql = format!(
"INSERT INTO col_parity (id, ts, value) VALUES ({id}, '2024-01-01 00:00:00', {val})"
);
pg.execute(&sql).await;
db.execute_sql(&sql, &[]).await.expect("Lite INSERT");
}
let origin_rows = pg.query("SELECT id, value FROM col_parity").await;
let lite_result = db
.execute_sql("SELECT * FROM col_parity", &[])
.await
.expect("Lite SELECT *");
assert_eq!(origin_rows.len(), 3, "Origin must return 3 columnar rows");
assert_eq!(
lite_result.rows.len(),
3,
"Lite columnar SELECT must return 3 rows after insert, got {}",
lite_result.rows.len()
);
assert!(
lite_result.columns.contains(&"id".to_string()),
"Lite SELECT must include 'id' column, got: {:?}",
lite_result.columns
);
assert!(
lite_result.columns.contains(&"value".to_string()),
"Lite SELECT must include 'value' column"
);
let id_idx = lite_result
.columns
.iter()
.position(|c| c == "id")
.expect("'id' column present");
let mut lite_ids: Vec<i64> = lite_result
.rows
.iter()
.filter_map(|r| {
if let nodedb_types::value::Value::Integer(i) = r[id_idx] {
Some(i)
} else {
None
}
})
.collect();
lite_ids.sort_unstable();
assert_eq!(
lite_ids,
vec![1, 2, 3],
"Lite columnar rows must contain id values 1, 2, 3"
);
}