#![cfg(feature = "write-support")]
use std::path::PathBuf;
use std::process::{Command, Output};
use tempfile::TempDir;
fn project_root() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.parent()
.unwrap()
.to_path_buf()
}
#[allow(dead_code)]
fn schemas_dir() -> PathBuf {
project_root().join("test-data/schemas")
}
fn run_write_cli(args: &[&str]) -> Output {
Command::new("cargo")
.args([
"run",
"--quiet",
"--package",
"cqlite-cli",
"--features",
"write-support",
"--",
])
.args(args)
.current_dir(project_root())
.output()
.expect("Failed to execute CLI command")
}
fn create_simple_schema(dir: &TempDir) -> PathBuf {
let schema_path = dir.path().join("test_schema.cql");
std::fs::write(
&schema_path,
r#"
CREATE KEYSPACE IF NOT EXISTS test_write WITH replication = {
'class': 'SimpleStrategy',
'replication_factor': 1
};
USE test_write;
CREATE TABLE IF NOT EXISTS users (
id INT PRIMARY KEY,
name TEXT,
age INT,
active BOOLEAN
);
"#,
)
.expect("Failed to write schema file");
schema_path
}
fn create_clustered_schema(dir: &TempDir) -> PathBuf {
let schema_path = dir.path().join("test_schema.cql");
std::fs::write(
&schema_path,
r#"
CREATE KEYSPACE IF NOT EXISTS test_write WITH replication = {
'class': 'SimpleStrategy',
'replication_factor': 1
};
USE test_write;
CREATE TABLE IF NOT EXISTS events (
user_id INT,
event_time TIMESTAMP,
event_type TEXT,
data TEXT,
PRIMARY KEY (user_id, event_time)
) WITH CLUSTERING ORDER BY (event_time ASC);
"#,
)
.expect("Failed to write schema file");
schema_path
}
#[test]
fn test_cli_execute_insert_basic() {
let temp_dir = TempDir::new().unwrap();
let schema_path = create_simple_schema(&temp_dir);
let write_dir = temp_dir.path().join("write_data");
let output = run_write_cli(&[
"--writable",
"--write-dir",
write_dir.to_str().unwrap(),
"--schema",
schema_path.to_str().unwrap(),
"--execute",
"INSERT INTO test_write.users (id, name, age, active) VALUES (1, 'Alice', 30, true)",
]);
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
output.status.success(),
"INSERT should succeed. stdout: {stdout}, stderr: {stderr}"
);
assert!(
stdout.contains("OK"),
"Should print OK on successful INSERT. stdout: {stdout}"
);
}
#[test]
fn test_cli_execute_insert_with_timestamp() {
let temp_dir = TempDir::new().unwrap();
let schema_path = create_simple_schema(&temp_dir);
let write_dir = temp_dir.path().join("write_data");
let output = run_write_cli(&[
"--writable",
"--write-dir",
write_dir.to_str().unwrap(),
"--schema",
schema_path.to_str().unwrap(),
"--execute",
"INSERT INTO test_write.users (id, name, age) VALUES (2, 'Bob', 25) USING TIMESTAMP 1704067200000000",
]);
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
output.status.success(),
"INSERT with TIMESTAMP should succeed. stderr: {stderr}"
);
assert!(stdout.contains("OK"));
}
#[test]
fn test_cli_execute_insert_with_clustering_key() {
let temp_dir = TempDir::new().unwrap();
let schema_path = create_clustered_schema(&temp_dir);
let write_dir = temp_dir.path().join("write_data");
let output = run_write_cli(&[
"--writable",
"--write-dir",
write_dir.to_str().unwrap(),
"--schema",
schema_path.to_str().unwrap(),
"--execute",
"INSERT INTO test_write.events (user_id, event_time, event_type, data) VALUES (1, 1704067200000, 'login', 'from_web')",
]);
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
output.status.success(),
"INSERT with clustering key should succeed. stderr: {stderr}"
);
assert!(stdout.contains("OK"));
}
#[test]
fn test_cli_execute_update_basic() {
let temp_dir = TempDir::new().unwrap();
let schema_path = create_simple_schema(&temp_dir);
let write_dir = temp_dir.path().join("write_data");
run_write_cli(&[
"--writable",
"--write-dir",
write_dir.to_str().unwrap(),
"--schema",
schema_path.to_str().unwrap(),
"--execute",
"INSERT INTO test_write.users (id, name, age) VALUES (1, 'Alice', 30)",
]);
let output = run_write_cli(&[
"--writable",
"--write-dir",
write_dir.to_str().unwrap(),
"--schema",
schema_path.to_str().unwrap(),
"--execute",
"UPDATE test_write.users SET name = 'Alicia', age = 31 WHERE id = 1",
]);
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
output.status.success(),
"UPDATE should succeed. stderr: {stderr}"
);
assert!(stdout.contains("OK"));
}
#[test]
fn test_cli_execute_update_with_clustering() {
let temp_dir = TempDir::new().unwrap();
let schema_path = create_clustered_schema(&temp_dir);
let write_dir = temp_dir.path().join("write_data");
let output = run_write_cli(&[
"--writable",
"--write-dir",
write_dir.to_str().unwrap(),
"--schema",
schema_path.to_str().unwrap(),
"--execute",
"UPDATE test_write.events SET event_type = 'logout', data = 'session_end' WHERE user_id = 1 AND event_time = 1704067200000",
]);
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
output.status.success(),
"UPDATE with clustering key should succeed. stderr: {stderr}"
);
assert!(stdout.contains("OK"));
}
#[test]
fn test_cli_execute_delete_row() {
let temp_dir = TempDir::new().unwrap();
let schema_path = create_simple_schema(&temp_dir);
let write_dir = temp_dir.path().join("write_data");
run_write_cli(&[
"--writable",
"--write-dir",
write_dir.to_str().unwrap(),
"--schema",
schema_path.to_str().unwrap(),
"--execute",
"INSERT INTO test_write.users (id, name, age) VALUES (1, 'Alice', 30)",
]);
let output = run_write_cli(&[
"--writable",
"--write-dir",
write_dir.to_str().unwrap(),
"--schema",
schema_path.to_str().unwrap(),
"--execute",
"DELETE FROM test_write.users WHERE id = 1",
]);
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
output.status.success(),
"DELETE should succeed. stderr: {stderr}"
);
assert!(stdout.contains("OK"));
}
#[test]
fn test_cli_execute_delete_with_clustering() {
let temp_dir = TempDir::new().unwrap();
let schema_path = create_clustered_schema(&temp_dir);
let write_dir = temp_dir.path().join("write_data");
let output = run_write_cli(&[
"--writable",
"--write-dir",
write_dir.to_str().unwrap(),
"--schema",
schema_path.to_str().unwrap(),
"--execute",
"DELETE FROM test_write.events WHERE user_id = 1 AND event_time = 1704067200000",
]);
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
output.status.success(),
"DELETE with clustering key should succeed. stderr: {stderr}"
);
assert!(stdout.contains("OK"));
}
#[test]
fn test_cli_execute_delete_columns() {
let temp_dir = TempDir::new().unwrap();
let schema_path = create_clustered_schema(&temp_dir);
let write_dir = temp_dir.path().join("write_data");
let output = run_write_cli(&[
"--writable",
"--write-dir",
write_dir.to_str().unwrap(),
"--schema",
schema_path.to_str().unwrap(),
"--execute",
"DELETE event_type, data FROM test_write.events WHERE user_id = 1 AND event_time = 1704067200000",
]);
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
output.status.success(),
"DELETE columns should succeed. stderr: {stderr}"
);
assert!(stdout.contains("OK"));
}
#[test]
fn test_cli_execute_dml_without_writable_flag() {
let temp_dir = TempDir::new().unwrap();
let schema_path = create_simple_schema(&temp_dir);
let output = run_write_cli(&[
"--schema",
schema_path.to_str().unwrap(),
"--execute",
"INSERT INTO test_write.users (id, name) VALUES (1, 'Alice')",
]);
assert!(
!output.status.success(),
"INSERT without --writable should fail"
);
}
#[test]
fn test_cli_execute_insert_then_flush() {
let temp_dir = TempDir::new().unwrap();
let schema_path = create_simple_schema(&temp_dir);
let write_dir = temp_dir.path().join("write_data");
let output = run_write_cli(&[
"--writable",
"--write-dir",
write_dir.to_str().unwrap(),
"--schema",
schema_path.to_str().unwrap(),
"--execute",
"INSERT INTO test_write.users (id, name, age) VALUES (1, 'Alice', 30)",
"--flush",
]);
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
output.status.success(),
"INSERT + flush should succeed. stderr: {stderr}"
);
assert!(
stdout.contains("OK"),
"Should print OK for INSERT. stdout: {stdout}"
);
}