use hyperdb_api::{Catalog, Date, Inserter, SqlType, TableDefinition};
mod common;
use common::TestConnection;
#[test]
fn test_inserter_null_in_non_null_column() {
let test = TestConnection::new().expect("Failed to create test connection");
let table_def = TableDefinition::new("foo").add_required_column("a", SqlType::int());
Catalog::new(&test.connection)
.create_table(&table_def)
.expect("Failed to create table");
let mut inserter =
Inserter::new(&test.connection, &table_def).expect("Failed to create inserter");
let result = inserter.add_row(&[&None::<i32>]);
assert!(
result.is_err(),
"add_row should fail for NULL in NOT NULL column"
);
}
#[test]
fn test_inserter_type_match() {
let test = TestConnection::new().expect("Failed to create test connection");
let table_def = TableDefinition::new("foo").add_nullable_column("a", SqlType::int());
Catalog::new(&test.connection)
.create_table(&table_def)
.expect("Failed to create table");
let mut inserter =
Inserter::new(&test.connection, &table_def).expect("Failed to create inserter");
inserter.add_row(&[&42i32]).expect("add_row should succeed");
inserter.execute().expect("execute should succeed");
let mut result = test
.connection
.execute_query("SELECT a FROM foo")
.expect("Failed to query");
let chunk = result
.next_chunk()
.expect("Failed to get chunk")
.expect("Expected chunk");
let value = chunk
.first()
.expect("Expected row")
.get_i32(0)
.expect("NULL value");
assert_eq!(value, 42);
}
#[test]
fn test_inserter_missing_table() {
let test = TestConnection::new().expect("Failed to create test connection");
let table_def = TableDefinition::new("nonexistent").add_nullable_column("a", SqlType::int());
let mut inserter =
Inserter::new(&test.connection, &table_def).expect("Inserter creation should succeed");
inserter.add_row(&[&42i32]).expect("add_row should succeed");
assert!(
inserter.execute().is_err(),
"execute should fail for non-existent table"
);
}
#[test]
#[expect(
clippy::approx_constant,
reason = "test literal 3.14 chosen for readability; not intended as an approximation of PI"
)]
fn test_inserter_all_types() {
let test = TestConnection::new().expect("Failed to create test connection");
let table_def = TableDefinition::new("all_types_test")
.add_nullable_column("col_bool", SqlType::bool())
.add_nullable_column("col_int", SqlType::int())
.add_nullable_column("col_bigint", SqlType::big_int())
.add_nullable_column("col_text", SqlType::text())
.add_nullable_column("col_double", SqlType::double())
.add_nullable_column("col_date", SqlType::date());
Catalog::new(&test.connection)
.create_table(&table_def)
.expect("Failed to create table");
let mut inserter =
Inserter::new(&test.connection, &table_def).expect("Failed to create inserter");
let date = Date::new(2024, 1, 15);
inserter
.add_row(&[
&true,
&42i32,
&1234567890123i64,
&"hello",
&3.14159f64,
&date,
])
.expect("Failed to add row");
inserter.execute().expect("Failed to execute inserter");
let mut result = test
.connection
.execute_query("SELECT * FROM all_types_test")
.expect("Failed to query");
let chunk = result
.next_chunk()
.expect("Failed to get chunk")
.expect("Expected chunk");
let row = chunk.first().expect("Expected row");
let bool_val = row.get::<bool>(0).expect("NULL bool");
let int_val = row.get_i32(1).expect("NULL int");
let bigint_val = row.get_i64(2).expect("NULL bigint");
let text_val = row.get::<String>(3).expect("NULL text");
let double_val = row.get_f64(4).expect("NULL double");
assert!(bool_val);
assert_eq!(int_val, 42);
assert_eq!(bigint_val, 1234567890123i64);
assert_eq!(text_val, "hello");
assert!((double_val - 3.14159).abs() < 0.0001);
}
#[test]
fn test_inserter_bulk_insert() {
let test = TestConnection::new().expect("Failed to create test connection");
let table_def = TableDefinition::new("numbers")
.add_required_column("id", SqlType::int())
.add_nullable_column("value", SqlType::double());
Catalog::new(&test.connection)
.create_table(&table_def)
.expect("Failed to create table");
let mut inserter =
Inserter::new(&test.connection, &table_def).expect("Failed to create inserter");
for i in 0..1000 {
inserter
.add_row(&[&i, &(f64::from(i) * 1.5)])
.expect("Failed to add row");
}
inserter.execute().expect("Failed to execute inserter");
let count = test
.count_tuples("numbers")
.expect("Failed to count tuples");
assert_eq!(count, 1000);
}
#[test]
fn test_inserter_nullable_columns() {
let test = TestConnection::new().expect("Failed to create test connection");
let table_def = TableDefinition::new("nullable_test")
.add_required_column("id", SqlType::int())
.add_nullable_column("name", SqlType::text());
Catalog::new(&test.connection)
.create_table(&table_def)
.expect("Failed to create table");
let mut inserter =
Inserter::new(&test.connection, &table_def).expect("Failed to create inserter");
inserter
.add_row(&[&1i32, &Some("Alice")])
.expect("Failed to add row with value");
inserter
.add_row(&[&2i32, &None::<&str>])
.expect("Failed to add row with NULL");
inserter.execute().expect("Failed to execute inserter");
let mut result = test
.connection
.execute_query("SELECT id, name FROM nullable_test ORDER BY id")
.expect("Failed to query table");
let mut rows: Vec<(i32, Option<String>)> = Vec::new();
while let Some(chunk) = result.next_chunk().expect("Failed to get chunk") {
for row in &chunk {
let id = row.get_i32(0).expect("NULL id");
let name = row.get::<String>(1);
rows.push((id, name));
}
}
assert_eq!(rows.len(), 2);
assert_eq!(rows[0], (1, Some("Alice".to_string())));
assert_eq!(rows[1], (2, None));
}
#[test]
fn test_inserter_from_table() {
let test = TestConnection::new().expect("Failed to create test connection");
test.execute_command(
"CREATE TABLE products (id INT NOT NULL, name TEXT, price DOUBLE PRECISION)",
)
.expect("Failed to create table");
let catalog = Catalog::new(&test.connection);
let table_def = catalog
.get_table_definition("products")
.expect("Failed to get table definition");
let mut inserter =
Inserter::new(&test.connection, &table_def).expect("Failed to create inserter");
inserter
.add_row(&[&1i32, &"Widget", &9.99f64])
.expect("Failed to add row");
inserter
.add_row(&[&2i32, &"Gadget", &19.99f64])
.expect("Failed to add row");
inserter.execute().expect("Failed to execute inserter");
let count = test.count_tuples("products").expect("Failed to count");
assert_eq!(count, 2);
}