mod aggregate;
mod capacity;
mod cli;
mod config;
mod csv_handler;
mod database;
mod delim_handler;
mod error;
mod file_handler;
mod repl;
mod sql_executor;
mod storage;
mod table;
mod vm;
use anyhow::{Context, Result};
use config::AppConfig;
use database::Database;
use file_handler::FileHandler;
use repl::Repl;
use sql_executor::SqlExecutor;
fn main() -> Result<()> {
let args = cli::parse_args()?;
let config = AppConfig::new(
args.verbose, args.field_separator.clone(), args.tabledef.clone(), args.write, );
if config.verbose() {
println!("Running in verbose mode");
println!("Arguments: {args:?}");
}
let mut database = Database::new();
database
.compile_table_definitions(&config)
.context("Failed to compile table definitions")?;
let mut file_handler = FileHandler::new(&config, &mut database);
if args.interactive
&& args.files.iter().any(|spec| {
spec.split_once('=').map_or(spec.as_str(), |(_, path)| path) == file_handler::STDIN_SPEC
})
{
anyhow::bail!(
"cannot read a table from standard input in interactive mode: \
the REPL reads its own commands from stdin"
);
}
for file_spec in &args.files {
file_handler
.load_file(file_spec)
.with_context(|| format!("Failed to load file: {file_spec}"))?;
}
if config.verbose() {
let table_count = file_handler.table_count();
println!("Loaded {table_count} tables");
for table_name in file_handler.table_names() {
println!("Table '{table_name}' loaded");
}
}
if args.interactive {
file_handler.disable_stdin();
}
let mut sql_executor = SqlExecutor::new(&mut database, &mut file_handler, &config);
if args.interactive {
let mut repl = Repl::new(sql_executor, &config);
match repl.run() {
Ok(_) => return Ok(()),
Err(e) => return Err(anyhow::anyhow!("Failed to run interactive mode: {}", e)),
}
}
for sql in &args.sql {
let result = sql_executor
.execute(sql)
.with_context(|| format!("Failed to execute SQL: {sql}"))?;
for table in &result {
if config.verbose() {
let row_count = table.row_count();
println!("Query returned {row_count} rows");
}
table.print_to_stdout()?;
}
if result.is_empty() && config.verbose() {
println!("Query executed successfully (no results to display)");
}
}
if config.write_changes() {
sql_executor
.save_modified_tables()
.context("Failed to save modified tables")?;
} else if config.verbose() {
println!("Changes not saved: use --write to save changes to files");
}
Ok(())
}