ccql 0.2.1

Claude Code Query Language - SQL query engine for Claude Code data
Documentation
use crate::error::{Error, Result};
use std::path::PathBuf;

#[derive(Debug, Clone)]
pub struct Config {
    pub data_dir: PathBuf,
    codex_data_dir: PathBuf,
}

impl Config {
    pub fn new(data_dir: PathBuf) -> Result<Self> {
        let codex_data_dir = Self::resolve_codex_data_dir();
        Self::new_with_codex_data_dir(data_dir, codex_data_dir)
    }

    pub fn new_with_codex_data_dir(data_dir: PathBuf, codex_data_dir: PathBuf) -> Result<Self> {
        if !data_dir.exists() {
            return Err(Error::InvalidPath(format!(
                "Data directory does not exist: {}",
                data_dir.display()
            )));
        }

        Ok(Self {
            data_dir,
            codex_data_dir,
        })
    }

    pub fn default_data_dir() -> PathBuf {
        dirs::home_dir()
            .map(|p| p.join(".claude"))
            .unwrap_or_else(|| PathBuf::from(".claude"))
    }

    pub fn default_codex_data_dir() -> PathBuf {
        dirs::home_dir()
            .map(|p| p.join(".codex"))
            .unwrap_or_else(|| PathBuf::from(".codex"))
    }

    fn resolve_codex_data_dir() -> PathBuf {
        std::env::var_os("CODEX_HOME")
            .map(PathBuf::from)
            .unwrap_or_else(Self::default_codex_data_dir)
    }

    pub fn transcripts_dir(&self) -> PathBuf {
        self.data_dir.join("transcripts")
    }

    pub fn history_file(&self) -> PathBuf {
        self.data_dir.join("history.jsonl")
    }

    pub fn codex_data_dir(&self) -> PathBuf {
        self.codex_data_dir.clone()
    }

    pub fn jhistory_file(&self) -> PathBuf {
        self.codex_data_dir().join("history.jsonl")
    }

    pub fn projects_dir(&self) -> PathBuf {
        self.data_dir.join("projects")
    }

    pub fn todos_dir(&self) -> PathBuf {
        self.data_dir.join("todos")
    }

    pub fn stats_file(&self) -> PathBuf {
        self.data_dir.join("stats-cache.json")
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn jhistory_path_uses_injected_codex_dir() {
        let temp = tempfile::tempdir().expect("temp dir");
        let codex_dir = temp.path().join("my-codex");
        std::fs::create_dir_all(&codex_dir).expect("create codex dir");

        let config = Config::new_with_codex_data_dir(temp.path().to_path_buf(), codex_dir.clone())
            .expect("config");

        assert_eq!(config.codex_data_dir(), codex_dir);
        assert_eq!(config.jhistory_file(), codex_dir.join("history.jsonl"));
    }
}