rocksmap 0.1.0

A high-level, type-safe abstraction over RocksDB with zero unsafe code and ergonomic map-like APIs
Documentation
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 {
    /// Path to the RocksDB database
    #[arg(short, long, default_value = "./rocksmap.db")]
    database: PathBuf,

    /// Output format (json, csv, table)
    #[arg(short, long, default_value = "table")]
    format: OutputFormat,

    /// Verbose output
    #[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 a key-value pair into the database
    Put {
        /// The key to store
        key: String,
        /// The value to store
        value: String,
        /// Column family name (optional)
        #[arg(short, long)]
        cf: Option<String>,
    },
    /// Get a value by key from the database
    Get {
        /// The key to retrieve
        key: String,
        /// Column family name (optional)
        #[arg(short, long)]
        cf: Option<String>,
    },
    /// Delete a key from the database
    Delete {
        /// The key to delete
        key: String,
        /// Column family name (optional)
        #[arg(short, long)]
        cf: Option<String>,
    },
    /// List all keys in the database
    List {
        /// Column family name (optional)
        #[arg(short, long)]
        cf: Option<String>,
        /// Limit the number of results
        #[arg(short, long)]
        limit: Option<usize>,
        /// Key prefix to filter by
        #[arg(short, long)]
        prefix: Option<String>,
    },
    /// Scan a range of keys
    Scan {
        /// Start key (inclusive)
        from: String,
        /// End key (inclusive)
        to: String,
        /// Column family name (optional)
        #[arg(short, long)]
        cf: Option<String>,
    },
    /// Database administration commands
    Admin {
        #[command(subcommand)]
        command: AdminCommands,
    },
    /// Import/export commands
    Import {
        #[command(subcommand)]
        command: ImportCommands,
    },
    /// Export data from the database
    Export {
        #[command(subcommand)]
        command: ExportCommands,
    },
    /// Database diagnostic tools
    Diag {
        #[command(subcommand)]
        command: DiagCommands,
    },
    /// Interactive shell mode
    Shell,
}

#[derive(Subcommand)]
enum AdminCommands {
    /// Compact the database
    Compact {
        /// Column family name (optional)
        #[arg(short, long)]
        cf: Option<String>,
    },
    /// Show database statistics
    Stats,
    /// Check database integrity
    Check,
    /// Backup the database
    Backup {
        /// Backup destination path
        path: PathBuf,
    },
    /// Create a column family
    CreateCf {
        /// Column family name
        name: String,
    },
    /// List column families
    ListCf,
}

#[derive(Subcommand)]
enum ImportCommands {
    /// Import from JSON file
    Json {
        /// Input JSON file path
        file: PathBuf,
        /// Column family name (optional)
        #[arg(short, long)]
        cf: Option<String>,
    },
    /// Import from CSV file
    Csv {
        /// Input CSV file path
        file: PathBuf,
        /// Column family name (optional)
        #[arg(short, long)]
        cf: Option<String>,
        /// Key column name
        #[arg(long, default_value = "key")]
        key_column: String,
        /// Value column name
        #[arg(long, default_value = "value")]
        value_column: String,
    },
}

#[derive(Subcommand)]
enum ExportCommands {
    /// Export to JSON file
    Json {
        /// Output JSON file path
        file: PathBuf,
        /// Column family name (optional)
        #[arg(short, long)]
        cf: Option<String>,
    },
    /// Export to CSV file
    Csv {
        /// Output CSV file path
        file: PathBuf,
        /// Column family name (optional)
        #[arg(short, long)]
        cf: Option<String>,
    },
}

#[derive(Subcommand)]
enum DiagCommands {
    /// Analyze key distribution and patterns
    Analyze,
    /// Check database integrity
    Check,
    /// Show detailed database statistics
    Stats,
    /// Scan keyspace for patterns
    Scan {
        /// Pattern to search for
        #[arg(short, long)]
        pattern: Option<String>,
        /// Show key size distribution
        #[arg(long)]
        key_sizes: bool,
        /// Show value size distribution
        #[arg(long)]
        value_sizes: bool,
    },
    /// Benchmark database performance
    Benchmark {
        /// Number of operations to perform
        #[arg(short, long, default_value = "1000")]
        operations: usize,
        /// Operation type (read, write, mixed)
        #[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(())
}