use serde::{Deserialize, Serialize};
use std::path::PathBuf;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CachedColumn {
pub name: String,
pub type_oid: u32,
#[serde(default)]
pub nullable: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CacheEntry {
pub sql: String,
pub hash: u64,
pub param_oids: Vec<u32>,
pub columns: Vec<CachedColumn>,
}
fn cache_dir() -> PathBuf {
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR")
.map(PathBuf::from)
.unwrap_or_else(|_| PathBuf::from("."));
let mut dir = manifest_dir.clone();
loop {
let candidate = dir.join(".resolute");
if candidate.is_dir() {
return candidate;
}
if !dir.pop() {
break;
}
}
let mut dir = manifest_dir;
loop {
let cargo_toml = dir.join("Cargo.toml");
if cargo_toml.exists() {
if let Ok(contents) = std::fs::read_to_string(&cargo_toml) {
if contents.contains("[workspace]") {
return dir.join(".resolute");
}
}
}
if !dir.pop() {
break;
}
}
PathBuf::from(".resolute")
}
fn cache_path(hash: u64) -> PathBuf {
cache_dir().join(format!("query-{hash:016x}.json"))
}
pub fn read_cache(hash: u64) -> Option<CacheEntry> {
let path = cache_path(hash);
let data = std::fs::read_to_string(&path).ok()?;
serde_json::from_str(&data).ok()
}
pub fn write_cache(entry: &CacheEntry) -> Result<(), String> {
let dir = cache_dir();
std::fs::create_dir_all(&dir)
.map_err(|e| format!("Failed to create .resolute directory: {e}"))?;
let path = dir.join(format!("query-{:016x}.json", entry.hash));
let json = serde_json::to_string_pretty(entry)
.map_err(|e| format!("Failed to serialize cache entry: {e}"))?;
std::fs::write(&path, json)
.map_err(|e| format!("Failed to write cache file {}: {e}", path.display()))?;
Ok(())
}