feat: add migrations config to manifest
- added migrations directory path - added migrations table name
This commit is contained in:
parent
83a4155d76
commit
11874bd8a4
7 changed files with 142 additions and 44 deletions
|
@ -10,7 +10,7 @@ pub(crate) fn apply_sql(app: &App, cmd_opts: ApplyCommandOpt) -> StdResult<()> {
|
||||||
let mut connection_manager = DatabaseConnectionManager::connect(&config.database)?;
|
let mut connection_manager = DatabaseConnectionManager::connect(&config.database)?;
|
||||||
let conn = connection_manager.connection();
|
let conn = connection_manager.connection();
|
||||||
|
|
||||||
let migration_manager = MigrationManager::new();
|
let migration_manager = MigrationManager::from(&config);
|
||||||
|
|
||||||
let file_contents = cmd_opts
|
let file_contents = cmd_opts
|
||||||
.file_paths
|
.file_paths
|
||||||
|
|
|
@ -10,7 +10,7 @@ pub(crate) fn rollback_applied_migrations(app: &App, opts: DowngradeCommandOpt)
|
||||||
let config = app.config()?;
|
let config = app.config()?;
|
||||||
let mut connection_manager = DatabaseConnectionManager::connect(&config.database)?;
|
let mut connection_manager = DatabaseConnectionManager::connect(&config.database)?;
|
||||||
let conn = connection_manager.connection();
|
let conn = connection_manager.connection();
|
||||||
let migration_manager = MigrationManager::new();
|
let migration_manager = MigrationManager::from(&config);
|
||||||
|
|
||||||
let applied_migrations = migration_manager.applied_migration_names(conn)?;
|
let applied_migrations = migration_manager.applied_migration_names(conn)?;
|
||||||
let migrations = config.migrations()?;
|
let migrations = config.migrations()?;
|
||||||
|
|
|
@ -16,7 +16,7 @@ pub(crate) fn print_migration_lists(app: &App) -> StdResult<()> {
|
||||||
)?;
|
)?;
|
||||||
let conn = connection_manager.connection();
|
let conn = connection_manager.connection();
|
||||||
|
|
||||||
let migration_manager = MigrationManager::new();
|
let migration_manager = MigrationManager::from(&config);
|
||||||
let applied_migration_names = migration_manager.applied_migration_names(conn)?;
|
let applied_migration_names = migration_manager.applied_migration_names(conn)?;
|
||||||
|
|
||||||
show_applied_migrations(&applied_migration_names);
|
show_applied_migrations(&applied_migration_names);
|
||||||
|
|
|
@ -10,7 +10,7 @@ pub(crate) fn upgrade_pending_migrations(app: &App, opts: UpgradeCommandOpt) ->
|
||||||
let mut connection_manager = DatabaseConnectionManager::connect(&config.database)?;
|
let mut connection_manager = DatabaseConnectionManager::connect(&config.database)?;
|
||||||
let conn = connection_manager.connection();
|
let conn = connection_manager.connection();
|
||||||
|
|
||||||
let migration_manager = MigrationManager::new();
|
let migration_manager = MigrationManager::from(&config);
|
||||||
|
|
||||||
let applied_migration_names = migration_manager.applied_migration_names(conn)?;
|
let applied_migration_names = migration_manager.applied_migration_names(conn)?;
|
||||||
let migrations = config.migrations()?;
|
let migrations = config.migrations()?;
|
||||||
|
|
|
@ -4,11 +4,31 @@ use serde::{Deserialize, Serialize};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::{env, fs, io};
|
use std::{env, fs, io};
|
||||||
|
|
||||||
pub(crate) const MIGRA_TOML_FILENAME: &str = "Migra.toml";
|
//===========================================================================//
|
||||||
pub(crate) const DEFAULT_DATABASE_CONNECTION_ENV: &str = "$DATABASE_URL";
|
// Default values for optional manifest variables //
|
||||||
|
//===========================================================================//
|
||||||
|
|
||||||
fn default_database_connection_env() -> String {
|
pub(crate) const MIGRA_TOML_FILENAME: &str = "Migra.toml";
|
||||||
DEFAULT_DATABASE_CONNECTION_ENV.to_owned()
|
|
||||||
|
//===========================================================================//
|
||||||
|
// Internal Config Utils / Macros //
|
||||||
|
//===========================================================================//
|
||||||
|
|
||||||
|
fn search_for_directory_containing_file(path: &Path, file_name: &str) -> MigraResult<PathBuf> {
|
||||||
|
let file_path = path.join(file_name);
|
||||||
|
if file_path.is_file() {
|
||||||
|
Ok(path.to_owned())
|
||||||
|
} else {
|
||||||
|
path.parent()
|
||||||
|
.ok_or(Error::RootNotFound)
|
||||||
|
.and_then(|p| search_for_directory_containing_file(p, file_name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn recursive_find_project_root() -> MigraResult<PathBuf> {
|
||||||
|
let current_dir = std::env::current_dir()?;
|
||||||
|
|
||||||
|
search_for_directory_containing_file(¤t_dir, MIGRA_TOML_FILENAME)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(not(feature = "postgres"), not(feature = "mysql")))]
|
#[cfg(any(not(feature = "postgres"), not(feature = "mysql")))]
|
||||||
|
@ -24,15 +44,12 @@ cargo install migra-cli --features ${database_name}"#,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
//===========================================================================//
|
||||||
pub(crate) struct Config {
|
// Database config //
|
||||||
#[serde(skip)]
|
//===========================================================================//
|
||||||
manifest_root: PathBuf,
|
|
||||||
|
|
||||||
root: PathBuf,
|
fn default_database_connection_env() -> String {
|
||||||
|
String::from("$DATABASE_URL")
|
||||||
#[serde(default)]
|
|
||||||
pub database: DatabaseConfig,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
@ -56,7 +73,7 @@ impl Default for SupportedDatabaseClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub(crate) struct DatabaseConfig {
|
pub(crate) struct DatabaseConfig {
|
||||||
pub client: Option<SupportedDatabaseClient>,
|
pub client: Option<SupportedDatabaseClient>,
|
||||||
|
|
||||||
|
@ -64,6 +81,15 @@ pub(crate) struct DatabaseConfig {
|
||||||
pub connection: String,
|
pub connection: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for DatabaseConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
DatabaseConfig {
|
||||||
|
connection: default_database_connection_env(),
|
||||||
|
client: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl DatabaseConfig {
|
impl DatabaseConfig {
|
||||||
pub fn client(&self) -> SupportedDatabaseClient {
|
pub fn client(&self) -> SupportedDatabaseClient {
|
||||||
self.client.clone().unwrap_or_else(|| {
|
self.client.clone().unwrap_or_else(|| {
|
||||||
|
@ -103,36 +129,97 @@ impl DatabaseConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===========================================================================//
|
||||||
|
// Migrations config //
|
||||||
|
//===========================================================================//
|
||||||
|
|
||||||
|
fn default_migrations_directory() -> String {
|
||||||
|
String::from("migrations")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_migrations_table_name() -> String {
|
||||||
|
String::from("migrations")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub(crate) struct MigrationsConfig {
|
||||||
|
#[serde(rename = "directory", default = "default_migrations_directory")]
|
||||||
|
directory: String,
|
||||||
|
|
||||||
|
#[serde(default = "default_migrations_table_name")]
|
||||||
|
table_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for MigrationsConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
MigrationsConfig {
|
||||||
|
directory: default_migrations_directory(),
|
||||||
|
table_name: default_migrations_table_name(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MigrationsConfig {
|
||||||
|
pub fn directory(&self) -> String {
|
||||||
|
if let Some(directory_env) = self.directory.strip_prefix("$") {
|
||||||
|
env::var(directory_env).unwrap_or_else(|_| {
|
||||||
|
println!(
|
||||||
|
"WARN: Cannot read {} variable and use {} directory by default",
|
||||||
|
directory_env,
|
||||||
|
default_migrations_directory()
|
||||||
|
);
|
||||||
|
default_migrations_directory()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
self.directory.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn table_name(&self) -> String {
|
||||||
|
if let Some(table_name_env) = self.table_name.strip_prefix("$") {
|
||||||
|
env::var(table_name_env).unwrap_or_else(|_| {
|
||||||
|
println!(
|
||||||
|
"WARN: Cannot read {} variable and use {} table_name by default",
|
||||||
|
table_name_env,
|
||||||
|
default_migrations_table_name()
|
||||||
|
);
|
||||||
|
default_migrations_table_name()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
self.table_name.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================//
|
||||||
|
// Main config //
|
||||||
|
//===========================================================================//
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub(crate) struct Config {
|
||||||
|
#[serde(skip)]
|
||||||
|
manifest_root: PathBuf,
|
||||||
|
|
||||||
|
root: PathBuf,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub(crate) database: DatabaseConfig,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub(crate) migrations: MigrationsConfig,
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
fn default() -> Config {
|
fn default() -> Config {
|
||||||
Config {
|
Config {
|
||||||
manifest_root: PathBuf::default(),
|
manifest_root: PathBuf::default(),
|
||||||
root: PathBuf::from("database"),
|
root: PathBuf::from("database"),
|
||||||
database: DatabaseConfig {
|
database: DatabaseConfig::default(),
|
||||||
connection: default_database_connection_env(),
|
migrations: MigrationsConfig::default(),
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn search_for_directory_containing_file(path: &Path, file_name: &str) -> MigraResult<PathBuf> {
|
|
||||||
let file_path = path.join(file_name);
|
|
||||||
if file_path.is_file() {
|
|
||||||
Ok(path.to_owned())
|
|
||||||
} else {
|
|
||||||
path.parent()
|
|
||||||
.ok_or(Error::RootNotFound)
|
|
||||||
.and_then(|p| search_for_directory_containing_file(p, file_name))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recursive_find_project_root() -> MigraResult<PathBuf> {
|
|
||||||
let current_dir = std::env::current_dir()?;
|
|
||||||
|
|
||||||
search_for_directory_containing_file(¤t_dir, MIGRA_TOML_FILENAME)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn read(config_path: Option<&PathBuf>) -> MigraResult<Config> {
|
pub fn read(config_path: Option<&PathBuf>) -> MigraResult<Config> {
|
||||||
let config_path = match config_path {
|
let config_path = match config_path {
|
||||||
|
@ -160,15 +247,13 @@ impl Config {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Config {
|
|
||||||
pub fn directory_path(&self) -> PathBuf {
|
pub fn directory_path(&self) -> PathBuf {
|
||||||
self.manifest_root.join(&self.root)
|
self.manifest_root.join(&self.root)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn migration_dir_path(&self) -> PathBuf {
|
pub fn migration_dir_path(&self) -> PathBuf {
|
||||||
self.directory_path().join("migrations")
|
self.directory_path().join(self.migrations.directory())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn migrations(&self) -> MigraResult<Vec<Migration>> {
|
pub fn migrations(&self) -> MigraResult<Vec<Migration>> {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use super::connection::AnyConnection;
|
use super::connection::AnyConnection;
|
||||||
|
use crate::Config;
|
||||||
use crate::StdResult;
|
use crate::StdResult;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
@ -54,10 +55,10 @@ pub struct MigrationManager {
|
||||||
migrations_table_name: String,
|
migrations_table_name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MigrationManager {
|
impl From<&Config> for MigrationManager {
|
||||||
pub fn new() -> Self {
|
fn from(config: &Config) -> Self {
|
||||||
MigrationManager {
|
MigrationManager {
|
||||||
migrations_table_name: String::from("migrations"),
|
migrations_table_name: config.migrations.table_name(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,8 @@ mod init {
|
||||||
fn init_manifest_with_default_config() -> TestResult {
|
fn init_manifest_with_default_config() -> TestResult {
|
||||||
let manifest_path = "Migra.toml";
|
let manifest_path = "Migra.toml";
|
||||||
|
|
||||||
|
fs::remove_file(&manifest_path).ok();
|
||||||
|
|
||||||
Command::cargo_bin("migra")?
|
Command::cargo_bin("migra")?
|
||||||
.arg("init")
|
.arg("init")
|
||||||
.assert()
|
.assert()
|
||||||
|
@ -58,6 +60,10 @@ mod init {
|
||||||
|
|
||||||
[database]
|
[database]
|
||||||
connection = "$DATABASE_URL"
|
connection = "$DATABASE_URL"
|
||||||
|
|
||||||
|
[migrations]
|
||||||
|
directory = "migrations"
|
||||||
|
table_name = "migrations"
|
||||||
"#
|
"#
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -70,6 +76,8 @@ connection = "$DATABASE_URL"
|
||||||
fn init_manifest_in_custom_path() -> TestResult {
|
fn init_manifest_in_custom_path() -> TestResult {
|
||||||
let manifest_path = path_to_file("Migra.toml");
|
let manifest_path = path_to_file("Migra.toml");
|
||||||
|
|
||||||
|
fs::remove_file(&manifest_path).ok();
|
||||||
|
|
||||||
Command::cargo_bin("migra")?
|
Command::cargo_bin("migra")?
|
||||||
.arg("-c")
|
.arg("-c")
|
||||||
.arg(&manifest_path)
|
.arg(&manifest_path)
|
||||||
|
@ -86,6 +94,10 @@ connection = "$DATABASE_URL"
|
||||||
|
|
||||||
[database]
|
[database]
|
||||||
connection = "$DATABASE_URL"
|
connection = "$DATABASE_URL"
|
||||||
|
|
||||||
|
[migrations]
|
||||||
|
directory = "migrations"
|
||||||
|
table_name = "migrations"
|
||||||
"#
|
"#
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
Reference in a new issue