Archived
1
0
Fork 0

chore: add support transactional ddl for client

I didn't know that mysql doesn't support transactional ddl.
It means that we cannot create table, alter table and etc. in
transaction. At the moment migra supports only postgres client,
that can be use transaction for ddl.
This commit is contained in:
Dmitriy Pleshevskiy 2021-04-24 22:39:42 +03:00
parent f98dd4f0c8
commit 7ae5eec2c3
12 changed files with 27 additions and 74 deletions

View file

@ -10,7 +10,7 @@ pub struct MySqlConnection {
impl OpenDatabaseConnection for MySqlConnection { impl OpenDatabaseConnection for MySqlConnection {
fn open(connection_string: &str) -> StdResult<Self> { fn open(connection_string: &str) -> StdResult<Self> {
let pool = Pool::new(connection_string)?; let pool = Pool::new_manual(1, 1, connection_string)?;
let conn = pool.get_conn()?; let conn = pool.get_conn()?;
Ok(MySqlConnection { conn }) Ok(MySqlConnection { conn })
} }
@ -25,6 +25,8 @@ impl DatabaseStatements for MySqlConnection {
} }
} }
impl SupportsTransactionalDDL for MySqlConnection {}
impl DatabaseConnection for MySqlConnection { impl DatabaseConnection for MySqlConnection {
fn batch_execute(&mut self, query: &str) -> StdResult<()> { fn batch_execute(&mut self, query: &str) -> StdResult<()> {
self.conn.query_drop(query)?; self.conn.query_drop(query)?;

View file

@ -23,6 +23,13 @@ impl DatabaseStatements for PostgresConnection {
} }
} }
impl SupportsTransactionalDDL for PostgresConnection {
#[inline]
fn supports_transactional_ddl(&self) -> bool {
true
}
}
impl DatabaseConnection for PostgresConnection { impl DatabaseConnection for PostgresConnection {
fn batch_execute(&mut self, query: &str) -> StdResult<()> { fn batch_execute(&mut self, query: &str) -> StdResult<()> {
self.client.batch_execute(query)?; self.client.batch_execute(query)?;

View file

@ -13,7 +13,14 @@ pub trait DatabaseStatements {
fn create_migration_table_stmt(&self) -> &'static str; fn create_migration_table_stmt(&self) -> &'static str;
} }
pub trait DatabaseConnection: DatabaseStatements { pub trait SupportsTransactionalDDL {
#[inline]
fn supports_transactional_ddl(&self) -> bool {
false
}
}
pub trait DatabaseConnection: DatabaseStatements + SupportsTransactionalDDL {
fn batch_execute(&mut self, query: &str) -> StdResult<()>; fn batch_execute(&mut self, query: &str) -> StdResult<()>;
fn execute<'b>(&mut self, query: &str, params: ToSqlParams<'b>) -> StdResult<u64>; fn execute<'b>(&mut self, query: &str, params: ToSqlParams<'b>) -> StdResult<u64>;

View file

@ -9,6 +9,7 @@ pub mod prelude {
pub use super::adapter::{ToSql, ToSqlParams, TryFromSql}; pub use super::adapter::{ToSql, ToSqlParams, TryFromSql};
pub use super::connection::{ pub use super::connection::{
AnyConnection, DatabaseConnection, DatabaseStatements, OpenDatabaseConnection, AnyConnection, DatabaseConnection, DatabaseStatements, OpenDatabaseConnection,
SupportsTransactionalDDL,
}; };
pub use super::migration::ManageMigration; pub use super::migration::ManageMigration;
pub use super::transaction::ManageTransaction; pub use super::transaction::ManageTransaction;

View file

@ -48,14 +48,14 @@ where
} }
pub fn maybe_with_transaction<TrxFnMut, Res>( pub fn maybe_with_transaction<TrxFnMut, Res>(
with: bool, is_needed: bool,
conn: &mut AnyConnection, conn: &mut AnyConnection,
trx_fn: &mut TrxFnMut, trx_fn: &mut TrxFnMut,
) -> StdResult<Res> ) -> StdResult<Res>
where where
TrxFnMut: FnMut(&mut AnyConnection) -> StdResult<Res>, TrxFnMut: FnMut(&mut AnyConnection) -> StdResult<Res>,
{ {
if with { if is_needed && conn.supports_transactional_ddl() {
with_transaction(conn, trx_fn) with_transaction(conn, trx_fn)
} else { } else {
trx_fn(conn) trx_fn(conn)

View file

@ -481,22 +481,6 @@ mod upgrade {
Ok(()) Ok(())
})?; })?;
#[cfg(feature = "mysql")]
inner("mysql_invalid", || {
use mysql::prelude::*;
let pool = mysql::Pool::new(MYSQL_URL)?;
let mut conn = pool.get_conn()?;
let articles_res = conn.query_drop("SELECT a.id FROM articles AS a");
let persons_res = conn.query_drop("SELECT p.id FROM persons AS p");
assert!(articles_res.is_ok());
assert!(persons_res.is_err());
Ok(())
})?;
Ok(()) Ok(())
} }
@ -533,23 +517,6 @@ mod upgrade {
Ok(()) Ok(())
})?; })?;
// TODO: Need to investigate how fix single transaction for Mysql
// #[cfg(feature = "mysql")]
// inner("mysql_invalid", || {
// use mysql::prelude::*;
// let pool = mysql::Pool::new(MYSQL_URL)?;
// let mut conn = pool.get_conn()?;
// let articles_res = conn.query_drop("SELECT a.id FROM articles AS a");
// let persons_res = conn.query_drop("SELECT p.id FROM persons AS p");
// assert!(articles_res.is_err());
// assert!(persons_res.is_err());
// Ok(())
// })?;
Ok(()) Ok(())
} }
} }

View file

@ -1,4 +0,0 @@
root = "./mysql_invalid"
[database]
connection = "mysql://mysql:mysql@localhost:6001/migra_tests"

View file

@ -1,3 +0,0 @@
-- This file should undo anything in `up.sql`
DROP TABLE articles;

View file

@ -1,8 +0,0 @@
-- Your SQL goes here
CREATE TABLE articles (
id int AUTO_INCREMENT PRIMARY KEY,
title text NOT NULL CHECK (length(title) > 0),
content text NOT NULL,
created_at timestamp NOT NULL DEFAULT current_timestamp
);

View file

@ -1,6 +0,0 @@
-- This file should undo anything in `up.sql`
ALTER TABLE articles
DROP COLUMN author_person_id;
DROP TABLE persons;

View file

@ -1,12 +0,0 @@
-- Your SQL goes here
CREATE TABLE persons (
id int AUTO_INCREMENT PRIMARY KEY
email varchar(256) NOT NULL UNIQUE
display_name text NOT NULL
created_at timestamp NOT NULL DEFAULT current_timestamp
);
ALTER TABLE articles
ADD COLUMN author_person_id int NULL
REFERENCES persons (id) ON UPDATE CASCADE ON DELETE CASCADE;

View file

@ -1,12 +1,14 @@
-- Your SQL goes here -- Your SQL goes here
CREATE TABLE persons ( CREATE TABLE persons (
id SERIAL PRIMARY KEY id SERIAL PRIMARY KEY,
email text NOT NULL UNIQUE email text NOT NULL UNIQUE,
display_name text NOT NULL display_name text NOT NULL,
created_at timestamp NOT NULL DEFAULT current_timestamp created_at timestamp NOT NULL DEFAULT current_timestamp
); );
ALTER TABLE articles /* This table doesn't exist
*/
ALTER TABLE recipes
ADD COLUMN author_person_id int NULL ADD COLUMN author_person_id int NULL
REFERENCES persons (id) ON UPDATE CASCADE ON DELETE CASCADE; REFERENCES persons (id) ON UPDATE CASCADE ON DELETE CASCADE;