sqlrite 1.0.2

RAG-oriented SQLite wrapper for AI agent workloads
Documentation
use sqlrite::{
    CompactionOptions, RuntimeConfig, SqlRite, backup_file, build_health_report, verify_backup_file,
};
use std::path::PathBuf;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let args = std::env::args().skip(1).collect::<Vec<_>>();
    let command = args
        .first()
        .cloned()
        .ok_or_else(|| std::io::Error::other(usage()))?;

    match command.as_str() {
        "backup" => {
            let source = arg_value(&args, "--source")?;
            let destination = arg_value(&args, "--dest")?;
            backup_file(source, destination)?;
            println!("backup complete");
        }
        "verify" => {
            let path = arg_value(&args, "--path")?;
            let report = verify_backup_file(path)?;
            println!("backup verification:");
            println!("- integrity_ok={}", report.integrity_check_ok);
            println!("- chunk_count={}", report.chunk_count);
            println!("- schema_version={}", report.schema_version);
            println!("- index_mode={}", report.vector_index_mode);
        }
        "health" => {
            let db_path = arg_value(&args, "--db")?;
            let db = SqlRite::open_with_config(PathBuf::from(db_path), RuntimeConfig::default())?;
            let report = build_health_report(&db)?;
            println!("health:");
            println!("- integrity_ok={}", report.integrity_check_ok);
            println!("- chunk_count={}", report.chunk_count);
            println!("- schema_version={}", report.schema_version);
            println!("- index_mode={}", report.vector_index_mode);
            println!("- index_entries={}", report.vector_index_entries);
        }
        "compact" => {
            let db_path = arg_value(&args, "--db")?;
            let db = SqlRite::open_with_config(PathBuf::from(&db_path), RuntimeConfig::default())?;
            let report = db.compact(CompactionOptions::default())?;
            if arg_exists(&args, "--json") {
                println!("{}", serde_json::to_string_pretty(&report)?);
            } else {
                println!("compaction:");
                println!(
                    "- chunks(before={}, after={}, removed={}, deduplicated={})",
                    report.before_chunks,
                    report.after_chunks,
                    report.removed_chunks,
                    report.deduplicated_chunks
                );
                println!(
                    "- documents(before={}, after={}, orphan_removed={})",
                    report.before_documents,
                    report.after_documents,
                    report.orphan_documents_removed
                );
                println!(
                    "- duration_ms={:.2}, reclaimed_bytes={:?}",
                    report.duration_ms, report.reclaimed_bytes
                );
            }
        }
        _ => {
            return Err(std::io::Error::other(usage()).into());
        }
    }

    Ok(())
}

fn arg_value(args: &[String], flag: &str) -> Result<String, std::io::Error> {
    let pos = args
        .iter()
        .position(|arg| arg == flag)
        .ok_or_else(|| std::io::Error::other(format!("missing {flag}\n{}", usage())))?;
    args.get(pos + 1)
        .cloned()
        .ok_or_else(|| std::io::Error::other(format!("missing value for {flag}\n{}", usage())))
}

fn arg_exists(args: &[String], flag: &str) -> bool {
    args.iter().any(|arg| arg == flag)
}

fn usage() -> String {
    "usage:\n  cargo run --bin sqlrite-ops -- backup --source <db_path> --dest <backup_path>\n  cargo run --bin sqlrite-ops -- verify --path <backup_path>\n  cargo run --bin sqlrite-ops -- health --db <db_path>\n  cargo run --bin sqlrite-ops -- compact --db <db_path> [--json]"
        .to_string()
}