use anyhow::Result;
use clap::{Parser, Subcommand};
use std::path::PathBuf;
mod commands;
use commands::*;
#[derive(Parser)]
#[command(name = "rocksmap-cli")]
#[command(about = "A CLI tool for managing RocksMap databases")]
#[command(version = "0.1.0")]
struct Cli {
#[arg(short, long, default_value = "./rocksmap.db")]
database: PathBuf,
#[arg(short, long, default_value = "table")]
format: OutputFormat,
#[arg(short, long)]
verbose: bool,
#[command(subcommand)]
command: Commands,
}
#[derive(Clone, Debug)]
enum OutputFormat {
Json,
Csv,
Table,
}
impl std::str::FromStr for OutputFormat {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"json" => Ok(OutputFormat::Json),
"csv" => Ok(OutputFormat::Csv),
"table" => Ok(OutputFormat::Table),
_ => Err(format!("Invalid output format: {}", s)),
}
}
}
#[derive(Subcommand)]
enum Commands {
Put {
key: String,
value: String,
#[arg(short, long)]
cf: Option<String>,
},
Get {
key: String,
#[arg(short, long)]
cf: Option<String>,
},
Delete {
key: String,
#[arg(short, long)]
cf: Option<String>,
},
List {
#[arg(short, long)]
cf: Option<String>,
#[arg(short, long)]
limit: Option<usize>,
#[arg(short, long)]
prefix: Option<String>,
},
Scan {
from: String,
to: String,
#[arg(short, long)]
cf: Option<String>,
},
Admin {
#[command(subcommand)]
command: AdminCommands,
},
Import {
#[command(subcommand)]
command: ImportCommands,
},
Export {
#[command(subcommand)]
command: ExportCommands,
},
Diag {
#[command(subcommand)]
command: DiagCommands,
},
Shell,
}
#[derive(Subcommand)]
enum AdminCommands {
Compact {
#[arg(short, long)]
cf: Option<String>,
},
Stats,
Check,
Backup {
path: PathBuf,
},
CreateCf {
name: String,
},
ListCf,
}
#[derive(Subcommand)]
enum ImportCommands {
Json {
file: PathBuf,
#[arg(short, long)]
cf: Option<String>,
},
Csv {
file: PathBuf,
#[arg(short, long)]
cf: Option<String>,
#[arg(long, default_value = "key")]
key_column: String,
#[arg(long, default_value = "value")]
value_column: String,
},
}
#[derive(Subcommand)]
enum ExportCommands {
Json {
file: PathBuf,
#[arg(short, long)]
cf: Option<String>,
},
Csv {
file: PathBuf,
#[arg(short, long)]
cf: Option<String>,
},
}
#[derive(Subcommand)]
enum DiagCommands {
Analyze,
Check,
Stats,
Scan {
#[arg(short, long)]
pattern: Option<String>,
#[arg(long)]
key_sizes: bool,
#[arg(long)]
value_sizes: bool,
},
Benchmark {
#[arg(short, long, default_value = "1000")]
operations: usize,
#[arg(short = 't', long, default_value = "mixed")]
op_type: String,
},
}
fn main() -> Result<()> {
let cli = Cli::parse();
if cli.verbose {
println!("Database path: {:?}", cli.database);
println!("Output format: {:?}", cli.format);
}
match cli.command {
Commands::Put { key, value, cf } => {
put_command(&cli.database, &key, &value, cf.as_deref(), &cli.format)?
}
Commands::Get { key, cf } => get_command(&cli.database, &key, cf.as_deref(), &cli.format)?,
Commands::Delete { key, cf } => {
delete_command(&cli.database, &key, cf.as_deref(), &cli.format)?
}
Commands::List { cf, limit, prefix } => list_command(
&cli.database,
cf.as_deref(),
limit,
prefix.as_deref(),
&cli.format,
)?,
Commands::Scan { from, to, cf } => {
scan_command(&cli.database, &from, &to, cf.as_deref(), &cli.format)?
}
Commands::Admin { command } => admin_command(&cli.database, command, &cli.format)?,
Commands::Import { command } => import_command(&cli.database, command, &cli.format)?,
Commands::Export { command } => export_command(&cli.database, command, &cli.format)?,
Commands::Diag { command } => diag_command(&cli.database, command, &cli.format)?,
Commands::Shell => shell_command(&cli.database, &cli.format)?,
}
Ok(())
}