From 8f834264d8d1b695b50273ddcb86c56f21839723 Mon Sep 17 00:00:00 2001 From: Dmitriy Pleshevskiy Date: Sat, 13 Feb 2021 23:44:41 +0300 Subject: [PATCH] refac: add struct for db connection --- migra-cli/src/commands/apply.rs | 8 +-- migra-cli/src/commands/downgrade.rs | 10 ++-- migra-cli/src/commands/list.rs | 6 +-- migra-cli/src/commands/upgrade.rs | 30 ++++++++--- migra-cli/src/database.rs | 82 ++++++++++++++++++----------- migra-cli/src/migration.rs | 23 ++++---- 6 files changed, 97 insertions(+), 62 deletions(-) diff --git a/migra-cli/src/commands/apply.rs b/migra-cli/src/commands/apply.rs index 75c75fd..e2b5ee7 100644 --- a/migra-cli/src/commands/apply.rs +++ b/migra-cli/src/commands/apply.rs @@ -1,12 +1,12 @@ use crate::config::Config; -use crate::database; +use crate::database::DatabaseConnection; use crate::opts::ApplyCommandOpt; use crate::path::PathBuilder; use crate::StdResult; +use std::convert::TryFrom; pub(crate) fn apply_sql(config: Config, opts: ApplyCommandOpt) -> StdResult<()> { - let database_connection_string = &config.database_connection_string()?; - let mut client = database::connect(database_connection_string)?; + let mut connection = DatabaseConnection::try_from(&config)?; let file_path = PathBuilder::from(config.directory_path()) .append(opts.file_name) @@ -15,7 +15,7 @@ pub(crate) fn apply_sql(config: Config, opts: ApplyCommandOpt) -> StdResult<()> let content = std::fs::read_to_string(file_path)?; - match database::apply_sql(&mut client, &content) { + match connection.apply_sql(&content) { Ok(_) => { println!("File was applied successfully"); } diff --git a/migra-cli/src/commands/downgrade.rs b/migra-cli/src/commands/downgrade.rs index 80f41e9..7d51887 100644 --- a/migra-cli/src/commands/downgrade.rs +++ b/migra-cli/src/commands/downgrade.rs @@ -1,12 +1,12 @@ use crate::config::Config; -use crate::database; +use crate::database::DatabaseConnection; use crate::StdResult; +use std::convert::TryFrom; pub(crate) fn downgrade_applied_migrations(config: Config) -> StdResult<()> { - let database_connection_string = &config.database_connection_string()?; - let mut client = database::connect(database_connection_string)?; + let mut connection = DatabaseConnection::try_from(&config)?; - let applied_migrations = database::applied_migrations(&mut client)?; + let applied_migrations = connection.applied_migration_names()?; let migrations = config.migrations()?; if let Some(first_applied_migration) = applied_migrations.first() { @@ -15,7 +15,7 @@ pub(crate) fn downgrade_applied_migrations(config: Config) -> StdResult<()> { .find(|m| m.name() == first_applied_migration) { println!("downgrade {}...", migration.name()); - migration.downgrade(&mut client)?; + migration.downgrade(&mut connection)?; } } diff --git a/migra-cli/src/commands/list.rs b/migra-cli/src/commands/list.rs index 2507d48..3118e2d 100644 --- a/migra-cli/src/commands/list.rs +++ b/migra-cli/src/commands/list.rs @@ -1,5 +1,5 @@ use crate::config::Config; -use crate::database; +use crate::database::DatabaseConnection; use crate::error::{ErrorKind, StdResult}; const EM_DASH: char = '—'; @@ -7,8 +7,8 @@ const EM_DASH: char = '—'; pub(crate) fn print_migration_lists(config: Config) -> StdResult<()> { let applied_migrations = match config.database_connection_string() { Ok(ref database_connection_string) => { - let mut client = database::connect(database_connection_string)?; - let applied_migrations = database::applied_migrations(&mut client)?; + let mut connection = DatabaseConnection::connect(database_connection_string)?; + let applied_migrations = connection.applied_migration_names()?; println!("Applied migrations:"); if applied_migrations.is_empty() { diff --git a/migra-cli/src/commands/upgrade.rs b/migra-cli/src/commands/upgrade.rs index efdeaa9..17d69f3 100644 --- a/migra-cli/src/commands/upgrade.rs +++ b/migra-cli/src/commands/upgrade.rs @@ -1,4 +1,5 @@ use crate::database; +use crate::migration::Migration; use crate::Config; use crate::StdResult; @@ -6,21 +7,34 @@ pub(crate) fn upgrade_pending_migrations(config: Config) -> StdResult<()> { let database_connection_string = &config.database_connection_string()?; let mut client = database::connect(database_connection_string)?; - let applied_migrations = database::applied_migrations(&mut client)?; + let applied_migration_names = database::applied_migration_names(&mut client)?; let migrations = config.migrations()?; - if migrations.is_empty() || migrations.last().map(|m| m.name()) == applied_migrations.first() { + if is_up_to_date_migrations(&migrations, &applied_migration_names) { println!("Up to date"); } else { - for m in migrations - .iter() - .filter(|m| !applied_migrations.contains(m.name())) - { - println!("upgrade {}...", m.name()); - m.upgrade(&mut client)?; + let pending_migrations = filter_pending_migrations(migrations, &applied_migration_names); + + for migration in pending_migrations.iter() { + println!("upgrade {}...", migration.name()); + migration.upgrade(&mut client)?; } } Ok(()) } + +fn is_up_to_date_migrations(migrations: &[Migration], applied_migration_names: &[String]) -> bool { + migrations.is_empty() || migrations.last().map(|m| m.name()) == applied_migration_names.first() +} + +fn filter_pending_migrations( + migrations: Vec, + applied_migration_names: &[String], +) -> Vec { + migrations + .into_iter() + .filter(|m| !applied_migration_names.contains(m.name())) + .collect() +} diff --git a/migra-cli/src/database.rs b/migra-cli/src/database.rs index c6c5c25..69feaa6 100644 --- a/migra-cli/src/database.rs +++ b/migra-cli/src/database.rs @@ -1,11 +1,25 @@ +use crate::config::Config; +use crate::StdResult; use postgres::{Client, Error, NoTls}; +use std::convert::TryFrom; -pub fn connect(connection_string: &str) -> Result { - Client::connect(connection_string, NoTls) +pub struct DatabaseConnection { + client: Client, } -pub fn apply_sql(client: &mut Client, sql_content: &str) -> Result<(), Error> { - client.batch_execute(sql_content) +impl TryFrom<&Config> for DatabaseConnection { + type Error = Box; + + fn try_from(config: &Config) -> Result { + DatabaseConnection::connect(&config.database_connection_string()?) + } +} + +impl DatabaseConnection { + pub fn connect(connection_string: &str) -> StdResult { + let client = Client::connect(connection_string, NoTls)?; + Ok(DatabaseConnection { client }) + } } pub fn is_migrations_table_not_found(e: &Error) -> bool { @@ -13,34 +27,42 @@ pub fn is_migrations_table_not_found(e: &Error) -> bool { .contains(r#"relation "migrations" does not exist"#) } -pub fn applied_migrations(client: &mut Client) -> Result, Error> { - let res = client - .query("SELECT name FROM migrations ORDER BY id DESC", &[]) - .or_else(|e| { - if is_migrations_table_not_found(&e) { - Ok(Vec::new()) - } else { - Err(e) - } - })?; +impl DatabaseConnection { + pub fn apply_sql(&mut self, sql_content: &str) -> Result<(), Error> { + self.client.batch_execute(sql_content) + } - Ok(res.into_iter().map(|row| row.get(0)).collect()) -} + pub fn applied_migration_names(&mut self) -> Result, Error> { + let res = self + .client + .query("SELECT name FROM migrations ORDER BY id DESC", &[]) + .or_else(|e| { + if is_migrations_table_not_found(&e) { + Ok(Vec::new()) + } else { + Err(e) + } + })?; -pub fn create_migrations_table(client: &mut Client) -> Result<(), Error> { - apply_sql( - client, - r#"CREATE TABLE IF NOT EXISTS migrations ( - id serial PRIMARY KEY, - name text NOT NULL UNIQUE - )"#, - ) -} + Ok(res.into_iter().map(|row| row.get(0)).collect()) + } -pub fn insert_migration_info(client: &mut Client, name: &str) -> Result { - client.execute("INSERT INTO migrations (name) VALUES ($1)", &[&name]) -} + pub fn create_migrations_table(&mut self) -> Result<(), Error> { + self.apply_sql( + r#"CREATE TABLE IF NOT EXISTS migrations ( + id serial PRIMARY KEY, + name text NOT NULL UNIQUE + )"#, + ) + } -pub fn delete_migration_info(client: &mut Client, name: &str) -> Result { - client.execute("DELETE FROM migrations WHERE name = $1", &[&name]) + pub fn insert_migration_info(&mut self, name: &str) -> Result { + self.client + .execute("INSERT INTO migrations (name) VALUES ($1)", &[&name]) + } + + pub fn delete_migration_info(&mut self, name: &str) -> Result { + self.client + .execute("DELETE FROM migrations WHERE name = $1", &[&name]) + } } diff --git a/migra-cli/src/migration.rs b/migra-cli/src/migration.rs index 6a5770d..6dba04b 100644 --- a/migra-cli/src/migration.rs +++ b/migra-cli/src/migration.rs @@ -1,6 +1,5 @@ -use crate::database; +use crate::database::DatabaseConnection; use crate::path::PathBuilder; -use postgres::Client; use std::fs; use std::path::PathBuf; @@ -37,27 +36,27 @@ impl Migration { &self.name } - pub fn upgrade(&self, client: &mut Client) -> Result<(), Box> { + pub fn upgrade( + &self, + connection: &mut DatabaseConnection, + ) -> Result<(), Box> { let content = fs::read_to_string(&self.upgrade_sql)?; - database::create_migrations_table(client)?; - - database::apply_sql(client, &content)?; - - database::insert_migration_info(client, self.name())?; + connection.create_migrations_table()?; + connection.apply_sql(&content)?; + connection.insert_migration_info(self.name())?; Ok(()) } pub fn downgrade( &self, - client: &mut Client, + connection: &mut DatabaseConnection, ) -> Result<(), Box> { let content = fs::read_to_string(&self.downgrade_sql)?; - database::apply_sql(client, &content)?; - - database::delete_migration_info(client, self.name())?; + connection.apply_sql(&content)?; + connection.delete_migration_info(self.name())?; Ok(()) }