use config::{Config, File};
use serde::Deserialize;
use springtime::config::CONFIG_FILE;
use springtime::future::{BoxFuture, FutureExt};
use springtime_di::component_registry::conditional::unregistered_component;
use springtime_di::instance_provider::ErrorPtr;
use springtime_di::{component_alias, injectable, Component};
use std::sync::Arc;
#[derive(Clone, Copy, Debug, Deserialize)]
pub enum Target {
Latest,
Version(u32),
Fake,
FakeVersion(u32),
}
impl From<Target> for refinery_core::Target {
fn from(value: Target) -> Self {
match value {
Target::Latest => refinery_core::Target::Latest,
Target::Version(version) => refinery_core::Target::Version(version),
Target::Fake => refinery_core::Target::Fake,
Target::FakeVersion(version) => refinery_core::Target::FakeVersion(version),
}
}
}
#[non_exhaustive]
#[derive(Clone, Debug, Deserialize)]
#[serde(default)]
pub struct MigrationConfig {
pub run_migrations_on_start: bool,
pub target: Target,
pub grouped: bool,
pub abort_divergent: bool,
pub abort_missing: bool,
pub migration_table_name: String,
}
impl Default for MigrationConfig {
fn default() -> Self {
Self {
run_migrations_on_start: true,
target: Target::Latest,
grouped: false,
abort_divergent: true,
abort_missing: true,
migration_table_name: "refinery_schema_history".to_string(),
}
}
}
impl MigrationConfig {
fn init_from_config() -> Result<Self, ErrorPtr> {
Config::builder()
.add_source(File::with_name(CONFIG_FILE).required(false))
.build()
.and_then(|config| config.try_deserialize::<MigrationConfigWrapper>())
.map(|config| config.migration)
.map_err(|error| Arc::new(error) as ErrorPtr)
}
}
#[injectable]
pub trait MigrationConfigProvider {
fn config(&self) -> BoxFuture<'_, Result<&MigrationConfig, ErrorPtr>>;
}
#[derive(Component)]
#[component(priority = -128, condition = "unregistered_component::<dyn MigrationConfigProvider + Send + Sync>", constructor = "DefaultMigrationConfigProvider::new")]
struct DefaultMigrationConfigProvider {
#[component(ignore)]
config: Result<MigrationConfig, ErrorPtr>,
}
#[component_alias]
impl MigrationConfigProvider for DefaultMigrationConfigProvider {
fn config(&self) -> BoxFuture<'_, Result<&MigrationConfig, ErrorPtr>> {
async {
match &self.config {
Ok(config) => Ok(config),
Err(error) => Err(error.clone()),
}
}
.boxed()
}
}
impl DefaultMigrationConfigProvider {
fn new() -> BoxFuture<'static, Result<Self, ErrorPtr>> {
async {
Ok(Self {
config: MigrationConfig::init_from_config(),
})
}
.boxed()
}
}
#[derive(Deserialize, Default)]
#[serde(default)]
struct MigrationConfigWrapper {
migration: MigrationConfig,
}