mod common;
use common::TestEngine;
use hyperdb_mcp::export::{export_to_file, ExportOptions};
use hyperdb_mcp::ingest::{ingest_csv, ingest_json, IngestOptions};
#[test]
fn full_pipeline_json_to_query() {
let te = TestEngine::new_ephemeral();
let orders = r#"[
{"order_id": 1, "customer_id": 1, "amount": 100.50},
{"order_id": 2, "customer_id": 2, "amount": 200.00},
{"order_id": 3, "customer_id": 1, "amount": 50.25}
]"#;
let opts = IngestOptions {
table: "orders".into(),
mode: "replace".into(),
schema_override: None,
merge_key: None,
target_db: None,
};
ingest_json(&te.engine, orders, &opts).unwrap();
let customers = r#"[
{"customer_id": 1, "name": "Alice"},
{"customer_id": 2, "name": "Bob"}
]"#;
let opts = IngestOptions {
table: "customers".into(),
mode: "replace".into(),
schema_override: None,
merge_key: None,
target_db: None,
};
ingest_json(&te.engine, customers, &opts).unwrap();
let rows = te.engine.execute_query_to_json(
"SELECT c.name, SUM(o.amount) as total FROM orders o JOIN customers c ON o.customer_id = c.customer_id GROUP BY c.name ORDER BY total DESC"
).unwrap();
assert_eq!(rows.len(), 2);
}
#[test]
fn full_pipeline_csv_ingest_and_export() {
let te = TestEngine::new_ephemeral();
let csv_data = "product,quantity,price\nWidget,100,9.99\nGadget,50,19.99\n";
let opts = IngestOptions {
table: "products".into(),
mode: "replace".into(),
schema_override: None,
merge_key: None,
target_db: None,
};
ingest_csv(&te.engine, csv_data, &opts).unwrap();
let dir = tempfile::tempdir().unwrap();
let export_path = dir.path().join("export.csv");
let export_path_str = export_path.to_str().unwrap();
let export_opts = ExportOptions {
sql: Some(
"SELECT product, quantity * price as revenue FROM products ORDER BY revenue DESC"
.into(),
),
table: None,
path: export_path_str.into(),
format: "csv".into(),
overwrite: true,
format_options: None,
source_db: None,
};
let result = export_to_file(&te.engine, &export_opts).unwrap();
assert_eq!(result.rows, 2);
let contents = std::fs::read_to_string(export_path_str).unwrap();
assert!(contents.contains("Gadget"));
}
#[test]
fn describe_shows_all_tables() {
let te = TestEngine::new_ephemeral();
te.engine
.execute_command("CREATE TABLE t1 (a INT)")
.unwrap();
te.engine
.execute_command("CREATE TABLE t2 (b TEXT)")
.unwrap();
te.engine
.execute_command("INSERT INTO t1 VALUES (1)")
.unwrap();
let tables = te.engine.describe_tables().unwrap();
assert_eq!(tables.len(), 2);
let t1 = tables.iter().find(|t| t["name"] == "t1").unwrap();
assert_eq!(t1["row_count"], 1);
}
#[test]
fn status_reports_workspace_info() {
let te = TestEngine::new_ephemeral();
te.engine
.execute_command("CREATE TABLE metrics (id INT)")
.unwrap();
te.engine
.execute_command("INSERT INTO metrics VALUES (1)")
.unwrap();
let status = te.engine.status().unwrap();
assert_eq!(status["hyperd_running"], true);
assert_eq!(status["table_count"], 1);
assert_eq!(status["total_rows"], 1);
}
#[test]
fn append_mode_accumulates_data() {
let te = TestEngine::new_ephemeral();
let batch1 = r#"[{"v": 1}, {"v": 2}]"#;
let batch2 = r#"[{"v": 3}]"#;
let opts_replace = IngestOptions {
table: "acc".into(),
mode: "replace".into(),
schema_override: None,
merge_key: None,
target_db: None,
};
let opts_append = IngestOptions {
table: "acc".into(),
mode: "append".into(),
schema_override: None,
merge_key: None,
target_db: None,
};
ingest_json(&te.engine, batch1, &opts_replace).unwrap();
ingest_json(&te.engine, batch2, &opts_append).unwrap();
let rows = te
.engine
.execute_query_to_json("SELECT COUNT(*) as cnt FROM acc")
.unwrap();
assert_eq!(rows[0]["cnt"], 3);
}