From bb9be306d9c6752028f21287a652fd200a40a5e7 Mon Sep 17 00:00:00 2001 From: Dmitriy Pleshevskiy Date: Sun, 30 May 2021 23:28:06 +0300 Subject: [PATCH] refac: mysql client with core lib --- migra-cli/src/database/clients/mysql.rs | 121 ++++++++++++++++-------- migra-cli/src/error.rs | 3 + migra-cli/src/main.rs | 2 + 3 files changed, 88 insertions(+), 38 deletions(-) diff --git a/migra-cli/src/database/clients/mysql.rs b/migra-cli/src/database/clients/mysql.rs index 6453230..a490214 100644 --- a/migra-cli/src/database/clients/mysql.rs +++ b/migra-cli/src/database/clients/mysql.rs @@ -1,53 +1,98 @@ -use crate::database::builder::merge_query_with_params; -use crate::database::prelude::*; -use crate::error::StdResult; +use crate::error::MigraResult; +use migra::managers::{ManageMigrations, ManageTransaction}; +use migra::migration; use mysql::prelude::*; use mysql::{Pool, PooledConn}; -pub struct MySqlConnection { +pub struct MySqlClient { conn: PooledConn, + migrations_table_name: String, } -impl OpenDatabaseConnection for MySqlConnection { - fn open(connection_string: &str) -> StdResult { - let pool = Pool::new_manual(1, 1, connection_string)?; - let conn = pool.get_conn()?; - Ok(MySqlConnection { conn }) +impl MySqlClient { + fn new(connection_string: &str, migrations_table_name: &str) -> MigraResult { + let conn = Pool::new_manual(1, 1, connection_string) + .and_then(|pool| pool.get_conn()) + .map_err(|_| crate::Error::FailedDatabaseConnection)?; + + Ok(MySqlClient { + conn, + migrations_table_name: migrations_table_name.to_owned(), + }) } } -impl DatabaseStatements for MySqlConnection { - fn create_migration_table_stmt(&self, migrations_table_name: &str) -> String { - format!( +impl ManageTransaction for MySqlClient { + fn begin_transaction(&mut self) -> migra::Result<()> { + self.conn + .query_drop("BEGIN") + .map_err(|_| migra::Error::FailedOpenTransaction) + } + + fn rollback_transaction(&mut self) -> migra::Result<()> { + self.conn + .query_drop("ROLLBACK") + .map_err(|_| migra::Error::FailedRollbackTransaction) + } + + fn commit_transaction(&mut self) -> migra::Result<()> { + self.conn + .query_drop("COMMIT") + .map_err(|_| migra::Error::FailedCommitTransaction) + } +} + +impl ManageMigrations for MySqlClient { + fn apply_sql(&mut self, sql_content: &str) -> migra::Result<()> { + self.conn + .query_drop(sql_content) + .map_err(|_| migra::Error::FailedApplySql) + } + + fn create_migrations_table(&mut self) -> migra::Result<()> { + let stmt = format!( r#"CREATE TABLE IF NOT EXISTS {} ( id int AUTO_INCREMENT PRIMARY KEY, name varchar(256) NOT NULL UNIQUE )"#, - migrations_table_name - ) - } -} - -impl SupportsTransactionalDdl for MySqlConnection {} - -impl DatabaseConnection for MySqlConnection { - fn batch_execute(&mut self, query: &str) -> StdResult<()> { - self.conn.query_drop(query)?; - Ok(()) - } - - fn execute<'b>(&mut self, query: &str, params: ToSqlParams<'b>) -> StdResult { - let stmt = merge_query_with_params(query, params); - - let res = self.conn.query_first(stmt)?.unwrap_or_default(); - Ok(res) - } - - fn query<'b>(&mut self, query: &str, params: ToSqlParams<'b>) -> StdResult>> { - let stmt = merge_query_with_params(query, params); - - let res = self.conn.query_map(stmt, |(column,)| vec![column])?; - - Ok(res) + &self.migrations_table_name + ); + + self.conn + .query_drop(stmt) + .map_err(|_| migra::Error::FailedCreateMigrationsTable) + } + + fn insert_migration(&mut self, name: &str) -> migra::Result { + let stmt = format!( + "INSERT INTO {} (name) VALUES ($1)", + &self.migrations_table_name + ); + + self.conn + .exec_first(&stmt, (name,)) + .map(|res| res.unwrap_or_default()) + .map_err(|_| migra::Error::FailedInsertMigration) + } + + fn delete_migration(&mut self, name: &str) -> migra::Result { + let stmt = format!( + "DELETE FROM {} WHERE name = $1", + &self.migrations_table_name + ); + + self.conn + .exec_first(&stmt, (name,)) + .map(|res| res.unwrap_or_default()) + .map_err(|_| migra::Error::FailedDeleteMigration) + } + + fn applied_migrations(&mut self) -> migra::Result { + let stmt = format!("SELECT name FROM {}", &self.migrations_table_name); + + self.conn + .query::(stmt) + .map(From::from) + .map_err(|_| migra::Error::FailedGetAppliedMigrations) } } diff --git a/migra-cli/src/error.rs b/migra-cli/src/error.rs index 45c53c7..ddcd6ae 100644 --- a/migra-cli/src/error.rs +++ b/migra-cli/src/error.rs @@ -9,6 +9,8 @@ pub type MigraResult = result::Result; #[derive(Debug)] pub enum Error { + FailedDatabaseConnection, + RootNotFound, MissedEnvVar(String), @@ -22,6 +24,7 @@ impl fmt::Display for Error { Error::MissedEnvVar(ref name) => { write!(fmt, r#"Missed "{}" environment variable"#, name) } + Error::FailedDatabaseConnection => fmt.write_str("Failed database connection"), Error::Io(ref error) => write!(fmt, "{}", error), } } diff --git a/migra-cli/src/main.rs b/migra-cli/src/main.rs index f9f77da..026d663 100644 --- a/migra-cli/src/main.rs +++ b/migra-cli/src/main.rs @@ -12,6 +12,8 @@ mod commands; mod config; mod database; mod error; +pub use error::Error; + mod opts; use crate::error::StdResult;