springtime_migrate_refinery/
config.rs1use config::{Config, File};
8use serde::Deserialize;
9use springtime::config::CONFIG_FILE;
10use springtime::future::{BoxFuture, FutureExt};
11use springtime_di::component_registry::conditional::unregistered_component;
12use springtime_di::instance_provider::ErrorPtr;
13use springtime_di::{component_alias, injectable, Component};
14use std::sync::Arc;
15
16#[derive(Clone, Copy, Debug, Deserialize)]
18pub enum Target {
19 Latest,
21 Version(u32),
23 Fake,
25 FakeVersion(u32),
27}
28
29impl From<Target> for refinery_core::Target {
30 fn from(value: Target) -> Self {
31 match value {
32 Target::Latest => refinery_core::Target::Latest,
33 Target::Version(version) => refinery_core::Target::Version(version),
34 Target::Fake => refinery_core::Target::Fake,
35 Target::FakeVersion(version) => refinery_core::Target::FakeVersion(version),
36 }
37 }
38}
39
40#[non_exhaustive]
42#[derive(Clone, Debug, Deserialize)]
43#[serde(default)]
44pub struct MigrationConfig {
45 pub run_migrations_on_start: bool,
47 pub target: Target,
49 pub grouped: bool,
51 pub abort_divergent: bool,
54 pub abort_missing: bool,
58 pub migration_table_name: String,
60}
61
62impl Default for MigrationConfig {
63 fn default() -> Self {
64 Self {
65 run_migrations_on_start: true,
66 target: Target::Latest,
67 grouped: false,
68 abort_divergent: true,
69 abort_missing: true,
70 migration_table_name: "refinery_schema_history".to_string(),
71 }
72 }
73}
74
75impl MigrationConfig {
76 fn init_from_config() -> Result<Self, ErrorPtr> {
77 Config::builder()
78 .add_source(File::with_name(CONFIG_FILE).required(false))
79 .build()
80 .and_then(|config| config.try_deserialize::<MigrationConfigWrapper>())
81 .map(|config| config.migration)
82 .map_err(|error| Arc::new(error) as ErrorPtr)
83 }
84}
85
86#[injectable]
89pub trait MigrationConfigProvider {
90 fn config(&self) -> BoxFuture<'_, Result<&MigrationConfig, ErrorPtr>>;
92}
93
94#[derive(Component)]
95#[component(priority = -128, condition = "unregistered_component::<dyn MigrationConfigProvider + Send + Sync>", constructor = "DefaultMigrationConfigProvider::new")]
96struct DefaultMigrationConfigProvider {
97 #[component(ignore)]
99 config: Result<MigrationConfig, ErrorPtr>,
100}
101
102#[component_alias]
103impl MigrationConfigProvider for DefaultMigrationConfigProvider {
104 fn config(&self) -> BoxFuture<'_, Result<&MigrationConfig, ErrorPtr>> {
105 async {
106 match &self.config {
107 Ok(config) => Ok(config),
108 Err(error) => Err(error.clone()),
109 }
110 }
111 .boxed()
112 }
113}
114
115impl DefaultMigrationConfigProvider {
116 fn new() -> BoxFuture<'static, Result<Self, ErrorPtr>> {
117 async {
118 Ok(Self {
119 config: MigrationConfig::init_from_config(),
120 })
121 }
122 .boxed()
123 }
124}
125
126#[derive(Deserialize, Default)]
127#[serde(default)]
128struct MigrationConfigWrapper {
129 migration: MigrationConfig,
130}