use nodedb_client::NodeDb;
use crate::common::origin::OriginServer;
use crate::common::sql::{OriginPgwire, open_lite};
const CREATE_LITE: &str = "CREATE COLLECTION strict_parity (
id BIGINT NOT NULL PRIMARY KEY,
name TEXT NOT NULL,
score FLOAT64
) WITH storage = 'strict'";
const CREATE_ORIGIN: &str = "CREATE COLLECTION strict_parity (
id BIGINT NOT NULL,
name TEXT NOT NULL,
score FLOAT64
) WITH (engine='document_strict')";
#[tokio::test]
async fn strict_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 strict_parity");
pg.execute("DROP COLLECTION strict_parity").await;
db.execute_sql("DROP COLLECTION strict_parity", &[])
.await
.expect("Lite DROP strict_parity");
}
#[tokio::test]
async fn strict_insert_returns_affected() {
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 strict_parity (id, name, score) VALUES (1, 'Alice', 9.5)")
.await;
pg.execute("INSERT INTO strict_parity (id, name, score) VALUES (2, 'Bob', 8.0)")
.await;
let r1 = db
.execute_sql(
"INSERT INTO strict_parity (id, name, score) VALUES (1, 'Alice', 9.5)",
&[],
)
.await
.expect("Lite INSERT 1");
let r2 = db
.execute_sql(
"INSERT INTO strict_parity (id, name, score) VALUES (2, 'Bob', 8.0)",
&[],
)
.await
.expect("Lite INSERT 2");
assert!(
r1.rows_affected >= 1,
"Lite INSERT 1 must affect >= 1 row, got {}",
r1.rows_affected
);
assert!(
r2.rows_affected >= 1,
"Lite INSERT 2 must affect >= 1 row, got {}",
r2.rows_affected
);
}
#[tokio::test]
async fn strict_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, name, score) in [(1i64, "Alice", 9.5f64), (2, "Bob", 8.0), (3, "Carol", 7.5)] {
let sql =
format!("INSERT INTO strict_parity (id, name, score) VALUES ({id}, '{name}', {score})");
pg.execute(&sql).await;
db.execute_sql(&sql, &[]).await.expect("Lite INSERT");
}
let origin_rows = pg.query("SELECT id, name, score FROM strict_parity").await;
let lite_result = db
.execute_sql("SELECT id, name, score FROM strict_parity", &[])
.await
.expect("Lite SELECT *");
assert_eq!(origin_rows.len(), 3, "Origin must return 3 rows");
assert_eq!(
lite_result.rows.len(),
3,
"Lite strict SELECT must return 3 rows after insert"
);
assert!(
lite_result.columns.contains(&"id".to_string()),
"Lite SELECT must include 'id' column, got: {:?}",
lite_result.columns
);
assert!(
lite_result.columns.contains(&"name".to_string()),
"Lite SELECT must include 'name' column"
);
assert!(
lite_result.columns.contains(&"score".to_string()),
"Lite SELECT must include 'score' column"
);
let mut lite_ids: Vec<String> = lite_result
.rows
.iter()
.map(|r| {
crate::common::sql::normalise_lite_row(&lite_result, 0)
.get("id")
.cloned()
.unwrap_or_default();
let id_idx = lite_result
.columns
.iter()
.position(|c| c == "id")
.unwrap_or(0);
format!("{:?}", r[id_idx])
})
.collect();
lite_ids.sort();
assert_eq!(
lite_ids,
vec!["Integer(1)", "Integer(2)", "Integer(3)"],
"Lite rows must contain id values 1, 2, 3"
);
}
#[tokio::test]
async fn strict_update_returns_affected() {
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 strict_parity (id, name, score) VALUES (1, 'Alice', 9.5)")
.await;
db.execute_sql(
"INSERT INTO strict_parity (id, name, score) VALUES (1, 'Alice', 9.5)",
&[],
)
.await
.expect("Lite INSERT");
pg.execute("UPDATE strict_parity SET score = 8.0 WHERE id = 1")
.await;
let r = db
.execute_sql("UPDATE strict_parity SET score = 8.0 WHERE id = 1", &[])
.await
.expect("Lite UPDATE strict_parity");
assert!(
r.rows_affected >= 1,
"Lite UPDATE must affect >= 1 row, got {}",
r.rows_affected
);
}
#[tokio::test]
async fn strict_delete_returns_affected() {
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 strict_parity (id, name, score) VALUES (1, 'Alice', 9.5)")
.await;
db.execute_sql(
"INSERT INTO strict_parity (id, name, score) VALUES (1, 'Alice', 9.5)",
&[],
)
.await
.expect("Lite INSERT");
pg.execute("DELETE FROM strict_parity WHERE id = 1").await;
let r = db
.execute_sql("DELETE FROM strict_parity WHERE id = 1", &[])
.await
.expect("Lite DELETE strict_parity");
assert!(
r.rows_affected >= 1,
"Lite DELETE must affect >= 1 row, got {}",
r.rows_affected
);
}
#[tokio::test]
async fn strict_point_get_by_primary_key() {
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 strict_parity (id, name, score) VALUES (42, 'Eve', 7.0)")
.await;
db.execute_sql(
"INSERT INTO strict_parity (id, name, score) VALUES (42, 'Eve', 7.0)",
&[],
)
.await
.expect("Lite INSERT");
let origin_rows = pg
.query("SELECT id, name, score FROM strict_parity WHERE id = 42")
.await;
assert_eq!(origin_rows.len(), 1, "Origin PointGet must return 1 row");
let lite_result = db
.execute_sql(
"SELECT id, name, score FROM strict_parity WHERE id = 42",
&[],
)
.await
.expect("Lite PointGet strict_parity must not error");
assert_eq!(
lite_result.rows.len(),
1,
"Lite PointGet must return 1 row, got {}",
lite_result.rows.len()
);
let row = crate::common::sql::normalise_lite_row(&lite_result, 0);
assert_eq!(
row.get("id").map(|s| s.as_str()),
Some("42"),
"Lite PointGet id must be 42, got row: {row:?}"
);
assert_eq!(
row.get("name").map(|s| s.as_str()),
Some("Eve"),
"Lite PointGet name must be 'Eve', got row: {row:?}"
);
}