feat: add managers
This commit is contained in:
parent
65ec318e9d
commit
1a59331ecf
4 changed files with 95 additions and 14 deletions
|
@ -1,11 +1,13 @@
|
||||||
use crate::error::MigraResult;
|
use crate::error::MigraResult;
|
||||||
use crate::migration;
|
use crate::migration;
|
||||||
|
use crate::migration::{DOWNGRADE_MIGRATION_FILE_NAME, UPGRADE_MIGRATION_FILE_NAME};
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_migration_dir(path: &Path) -> bool {
|
pub fn is_migration_dir(path: &Path) -> bool {
|
||||||
path.join("up.sql").exists() && path.join("down.sql").exists()
|
path.join(UPGRADE_MIGRATION_FILE_NAME).exists()
|
||||||
|
&& path.join(DOWNGRADE_MIGRATION_FILE_NAME).exists()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_all_migrations(dir_path: &Path) -> MigraResult<migration::List> {
|
pub fn get_all_migrations(dir_path: &Path) -> MigraResult<migration::List> {
|
||||||
|
|
|
@ -2,12 +2,15 @@
|
||||||
#![deny(clippy::all, clippy::pedantic)]
|
#![deny(clippy::all, clippy::pedantic)]
|
||||||
#![allow(clippy::missing_errors_doc)]
|
#![allow(clippy::missing_errors_doc)]
|
||||||
|
|
||||||
mod error;
|
|
||||||
pub mod fs;
|
pub mod fs;
|
||||||
|
pub mod managers;
|
||||||
pub mod migration;
|
pub mod migration;
|
||||||
|
|
||||||
|
mod error;
|
||||||
pub use error::{Error, MigraResult as Result};
|
pub use error::{Error, MigraResult as Result};
|
||||||
|
|
||||||
|
pub use migration::Migration;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
# list
|
# list
|
||||||
|
|
41
migra/src/managers.rs
Normal file
41
migra/src/managers.rs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
use crate::error::MigraResult;
|
||||||
|
use crate::migration::{self, Migration};
|
||||||
|
|
||||||
|
pub trait ManageTransaction {
|
||||||
|
fn begin_transaction(&mut self) -> MigraResult<()>;
|
||||||
|
|
||||||
|
fn rollback_transaction(&mut self) -> MigraResult<()>;
|
||||||
|
|
||||||
|
fn commit_transaction(&mut self) -> MigraResult<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ManageMigrations {
|
||||||
|
fn apply_sql(&mut self, sql_content: &str) -> MigraResult<()>;
|
||||||
|
|
||||||
|
fn create_migrations_table(&mut self) -> MigraResult<()>;
|
||||||
|
|
||||||
|
fn insert_migration(&mut self, name: &str) -> MigraResult<u64>;
|
||||||
|
|
||||||
|
fn delete_migration(&mut self, name: &str) -> MigraResult<u64>;
|
||||||
|
|
||||||
|
fn applied_migrations(&mut self) -> MigraResult<migration::List>;
|
||||||
|
|
||||||
|
fn apply_upgrade_migration(&mut self, migration: &Migration) -> MigraResult<()> {
|
||||||
|
let content = migration.read_upgrade_migration_sql()?;
|
||||||
|
|
||||||
|
self.create_migrations_table()?;
|
||||||
|
self.apply_sql(&content)?;
|
||||||
|
self.insert_migration(migration.name())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_downgrade_migration(&mut self, migration: &Migration) -> MigraResult<()> {
|
||||||
|
let content = migration.read_downgrade_migration_sql()?;
|
||||||
|
|
||||||
|
self.apply_sql(&content)?;
|
||||||
|
self.delete_migration(migration.name())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,15 +1,27 @@
|
||||||
|
use std::fs;
|
||||||
|
use std::io;
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
pub(crate) const UPGRADE_MIGRATION_FILE_NAME: &str = "up.sql";
|
||||||
|
pub(crate) const DOWNGRADE_MIGRATION_FILE_NAME: &str = "down.sql";
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, PartialEq, Eq)]
|
#[derive(Debug, Clone, Default, PartialEq, Eq)]
|
||||||
pub struct Migration {
|
pub struct Migration {
|
||||||
|
path: PathBuf,
|
||||||
name: String,
|
name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Migration {
|
impl Migration {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(name: &str) -> Self {
|
pub fn new(path: &Path) -> Self {
|
||||||
Migration {
|
Migration {
|
||||||
name: name.to_owned(),
|
path: PathBuf::from(path),
|
||||||
|
name: path
|
||||||
|
.file_name()
|
||||||
|
.and_then(std::ffi::OsStr::to_str)
|
||||||
|
.expect("Cannot read migration name")
|
||||||
|
.to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +29,14 @@ impl Migration {
|
||||||
pub fn name(&self) -> &String {
|
pub fn name(&self) -> &String {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn read_upgrade_migration_sql(&self) -> io::Result<String> {
|
||||||
|
fs::read_to_string(self.path.join(UPGRADE_MIGRATION_FILE_NAME))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_downgrade_migration_sql(&self) -> io::Result<String> {
|
||||||
|
fs::read_to_string(self.path.join(DOWNGRADE_MIGRATION_FILE_NAME))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, PartialEq, Eq)]
|
#[derive(Debug, Clone, Default, PartialEq, Eq)]
|
||||||
|
@ -24,7 +44,7 @@ pub struct List {
|
||||||
inner: Vec<Migration>,
|
inner: Vec<Migration>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: AsRef<str>> From<Vec<T>> for List {
|
impl<T: AsRef<Path>> From<Vec<T>> for List {
|
||||||
fn from(list: Vec<T>) -> Self {
|
fn from(list: Vec<T>) -> Self {
|
||||||
List {
|
List {
|
||||||
inner: list.iter().map(AsRef::as_ref).map(Migration::new).collect(),
|
inner: list.iter().map(AsRef::as_ref).map(Migration::new).collect(),
|
||||||
|
@ -50,8 +70,8 @@ impl List {
|
||||||
self.inner.push(migration)
|
self.inner.push(migration)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_name(&mut self, name: &str) {
|
pub fn push_name<P: AsRef<Path>>(&mut self, path: P) {
|
||||||
self.inner.push(Migration::new(name))
|
self.inner.push(Migration::new(path.as_ref()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
@ -67,7 +87,16 @@ impl List {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn maybe_next<'a>(&self, name: &'a str) -> Option<&'a str> {
|
pub fn maybe_contains<'a>(&self, name: &'a str) -> Option<&'a str> {
|
||||||
|
if self.contains_name(name) {
|
||||||
|
Some(name)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn maybe_missed<'a>(&self, name: &'a str) -> Option<&'a str> {
|
||||||
if self.contains_name(name) {
|
if self.contains_name(name) {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
@ -118,10 +147,10 @@ mod tests {
|
||||||
fn push_migration_to_list() {
|
fn push_migration_to_list() {
|
||||||
let mut list = List::new();
|
let mut list = List::new();
|
||||||
|
|
||||||
list.push(Migration::new(FIRST_MIGRATION));
|
list.push(Migration::new(&PathBuf::from(FIRST_MIGRATION)));
|
||||||
assert_eq!(list, List::from(vec![FIRST_MIGRATION]));
|
assert_eq!(list, List::from(vec![FIRST_MIGRATION]));
|
||||||
|
|
||||||
list.push(Migration::new(&String::from(SECOND_MIGRATION)));
|
list.push(Migration::new(&PathBuf::from(SECOND_MIGRATION)));
|
||||||
assert_eq!(list, List::from(vec![FIRST_MIGRATION, SECOND_MIGRATION]))
|
assert_eq!(list, List::from(vec![FIRST_MIGRATION, SECOND_MIGRATION]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,8 +169,14 @@ mod tests {
|
||||||
fn contains_migration() {
|
fn contains_migration() {
|
||||||
let list = List::from(vec![FIRST_MIGRATION]);
|
let list = List::from(vec![FIRST_MIGRATION]);
|
||||||
|
|
||||||
assert_eq!(list.contains(&Migration::new(FIRST_MIGRATION)), true);
|
assert_eq!(
|
||||||
assert_eq!(list.contains(&Migration::new(SECOND_MIGRATION)), false);
|
list.contains(&Migration::new(&PathBuf::from(FIRST_MIGRATION))),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
list.contains(&Migration::new(&PathBuf::from(SECOND_MIGRATION))),
|
||||||
|
false
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -156,8 +191,8 @@ mod tests {
|
||||||
fn maybe_next_migration_name() {
|
fn maybe_next_migration_name() {
|
||||||
let list = List::from(vec![FIRST_MIGRATION]);
|
let list = List::from(vec![FIRST_MIGRATION]);
|
||||||
|
|
||||||
assert_eq!(list.maybe_next(FIRST_MIGRATION), None);
|
assert_eq!(list.maybe_missed(FIRST_MIGRATION), None);
|
||||||
assert_eq!(list.maybe_next(SECOND_MIGRATION), Some(SECOND_MIGRATION));
|
assert_eq!(list.maybe_missed(SECOND_MIGRATION), Some(SECOND_MIGRATION));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Reference in a new issue