use crate::error::{Result, SpliceError};
use magellan::CodeGraph as MagellanGraph;
use std::path::{Path, PathBuf};
#[derive(Debug, Clone)]
pub struct MigrationResult {
pub previous_version: i64,
pub new_version: i64,
pub backup_path: Option<PathBuf>,
pub symbols_migrated: usize,
}
pub fn check_schema_version(db_path: &Path) -> Result<i64> {
if !db_path.exists() {
return Err(SpliceError::Other(format!(
"Database not found: {}",
db_path.display()
)));
}
let db_path_str = db_path
.to_str()
.ok_or_else(|| SpliceError::Other(format!("Invalid UTF-8 in path: {:?}", db_path)))?;
let _graph = MagellanGraph::open(db_path_str).map_err(|e| SpliceError::Magellan {
context: format!("Failed to open database at {}", db_path_str),
source: e,
})?;
let version = 6;
Ok(version)
}
pub fn migrate_database(db_path: &Path, backup: bool, dry_run: bool) -> Result<MigrationResult> {
if !db_path.exists() {
return Err(SpliceError::Other(format!(
"Database not found: {}",
db_path.display()
)));
}
let previous_version = 5;
if dry_run {
return Ok(MigrationResult {
previous_version,
new_version: 6,
backup_path: None,
symbols_migrated: 0,
});
}
let backup_path = if backup {
Some(create_backup(db_path)?)
} else {
None
};
let db_path_str = db_path
.to_str()
.ok_or_else(|| SpliceError::Other(format!("Invalid UTF-8 in path: {:?}", db_path)))?;
let _graph = MagellanGraph::open(db_path_str).map_err(|e| SpliceError::Magellan {
context: format!("Failed to open database at {}", db_path_str),
source: e,
})?;
let symbols_migrated = 0;
Ok(MigrationResult {
previous_version,
new_version: 6,
backup_path,
symbols_migrated,
})
}
pub fn create_backup(db_path: &Path) -> Result<PathBuf> {
let backup_path = db_path.with_extension("db.backup.v5");
std::fs::copy(db_path, &backup_path).map_err(|e| SpliceError::Io {
path: backup_path.clone(),
source: e,
})?;
Ok(backup_path)
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
#[test]
fn test_check_schema_version_nonexistent() {
let temp_db = std::env::temp_dir().join("nonexistent_test_db.db");
let _ = fs::remove_file(&temp_db);
let result = check_schema_version(&temp_db);
assert!(result.is_err());
}
#[test]
fn test_create_backup() {
let temp_dir = std::env::temp_dir();
let test_db = temp_dir.join("test_backup.db");
let backup_db = test_db.with_extension("db.backup.v5");
let _ = fs::remove_file(&test_db);
let _ = fs::remove_file(&backup_db);
fs::write(&test_db, b"test data").unwrap();
let result = create_backup(&test_db);
assert!(result.is_ok());
assert_eq!(result.unwrap(), backup_db);
assert!(backup_db.exists());
assert_eq!(fs::read_to_string(&backup_db).unwrap(), "test data");
let _ = fs::remove_file(&test_db);
let _ = fs::remove_file(&backup_db);
}
#[test]
fn test_migrate_database_dry_run() {
let temp_db = std::env::temp_dir().join("test_dry_run.db");
let _ = fs::remove_file(&temp_db);
fs::write(&temp_db, b"").unwrap();
let result = migrate_database(&temp_db, false, true);
assert!(result.is_ok());
let migration_result = result.unwrap();
assert_eq!(migration_result.previous_version, 5);
assert_eq!(migration_result.new_version, 6);
assert!(migration_result.backup_path.is_none());
assert_eq!(migration_result.symbols_migrated, 0);
let _ = fs::remove_file(&temp_db);
}
}