use std::path::Path;
use std::sync::Arc;
use crate::infra::io::durable::migrate_tier_entry;
use crate::platform::error::PlatformError;
use crate::platform::model::ProjectFileLayout;
fn migrate_legacy_data_dir_entry(
layout: &ProjectFileLayout,
old_name: &str,
new_path: &std::path::Path,
) -> Result<(), PlatformError> {
migrate_tier_entry(&layout.data_dir.join(old_name), new_path)
.map_err(|err| PlatformError::new("PLATFORM_DATA_TIER_MIGRATE", err.to_string()))
}
pub trait ProjectDataEngine: Send + Sync {
fn id(&self) -> &'static str;
fn initialize(&self, layout: &ProjectFileLayout) -> Result<(), PlatformError>;
}
pub trait ProjectDataFactory: Send + Sync {
fn id(&self) -> &'static str;
fn initialize_project(&self, layout: &ProjectFileLayout) -> Result<(), PlatformError>;
fn enabled_engines(&self) -> Vec<&'static str>;
}
#[derive(Default)]
pub struct ProjectSqliteEngine;
impl ProjectDataEngine for ProjectSqliteEngine {
fn id(&self) -> &'static str {
"project_data.sqlite"
}
fn initialize(&self, layout: &ProjectFileLayout) -> Result<(), PlatformError> {
migrate_legacy_data_dir_entry(layout, "local.db", &layout.data_store_local_db_file())?;
std::fs::create_dir_all(&layout.data_store_dir())?;
let db_path = layout.data_store_local_db_file();
let conn = rusqlite::Connection::open(&db_path)
.map_err(|e| PlatformError::new("PROJECT_DATA_SQLITE_INIT", e.to_string()))?;
conn.execute_batch("PRAGMA journal_mode=WAL; PRAGMA synchronous=NORMAL;")
.map_err(|e| PlatformError::new("PROJECT_DATA_SQLITE_PRAGMA", e.to_string()))?;
Ok(())
}
}
#[derive(Default)]
pub struct ProjectPostgresEngine;
impl ProjectDataEngine for ProjectPostgresEngine {
fn id(&self) -> &'static str {
"project_data.postgres"
}
fn initialize(&self, _layout: &ProjectFileLayout) -> Result<(), PlatformError> {
Ok(())
}
}
#[derive(Default)]
pub struct ProjectSekejapEngine;
impl ProjectDataEngine for ProjectSekejapEngine {
fn id(&self) -> &'static str {
"project_data.sekejap"
}
fn initialize(&self, layout: &ProjectFileLayout) -> Result<(), PlatformError> {
migrate_legacy_data_dir_entry(layout, "sekejap", &layout.data_store_sekejap_dir())?;
std::fs::create_dir_all(layout.data_store_sekejap_dir())?;
Ok(())
}
}
pub struct DefaultProjectDataFactory {
engines: Vec<Arc<dyn ProjectDataEngine>>,
}
impl Default for DefaultProjectDataFactory {
fn default() -> Self {
Self {
engines: vec![
Arc::new(ProjectSqliteEngine),
Arc::new(ProjectSekejapEngine),
],
}
}
}
impl ProjectDataFactory for DefaultProjectDataFactory {
fn id(&self) -> &'static str {
"project_data.default"
}
fn initialize_project(&self, layout: &ProjectFileLayout) -> Result<(), PlatformError> {
for engine in &self.engines {
engine.initialize(layout)?;
}
Ok(())
}
fn enabled_engines(&self) -> Vec<&'static str> {
self.engines.iter().map(|e| e.id()).collect()
}
}
pub fn build_project_data_factory(_data_root: &Path) -> Arc<dyn ProjectDataFactory> {
Arc::new(DefaultProjectDataFactory::default())
}