diff options
Diffstat (limited to 'src/db/migration')
-rw-r--r-- | src/db/migration/change.rs | 62 | ||||
-rw-r--r-- | src/db/migration/mod.rs | 21 |
2 files changed, 81 insertions, 2 deletions
diff --git a/src/db/migration/change.rs b/src/db/migration/change.rs new file mode 100644 index 0000000..b5d0dd5 --- /dev/null +++ b/src/db/migration/change.rs @@ -0,0 +1,62 @@ +use diesel::Connection; + +use crate::db::backend::Connectable; +use crate::db::models::Field; + +pub enum DatabaseChange { + CreateModel { + name: &'static str, + fields: &'static [Field], + options: &'static [CreateModelOption] + }, +} + +impl DatabaseChange { + pub fn apply<C: Connectable>(&self, app_name: &str, connection: &C::Connection) { + use barrel::{Migration, Table, types}; + + match self { + DatabaseChange::CreateModel { name, fields, options } => { + let mut m = Migration::new(); + + let columns: Vec<(&'static str, _)> = fields.iter().map(|field| match field { + Field::CharField { name, max_length } => { + let name = *name; + let _type = match max_length { + None => types::text(), + Some(max_length) => types::varchar(*max_length), + }; + (name, _type) + } + Field::DateTimeField { name } => { + (*name, types::text()) // TODO do smart things on non-sqlite + } + Field::IntField { name } => { + (*name, types::integer()) + } + }).collect(); + + let callback = move |t: &mut Table| { + for (name, _type) in &columns { + t.add_column(*name, _type.clone()); + } + }; + + let table_name = format!("{}-{}", app_name, name); + + if options.contains(&CreateModelOption::IfNotExist) { + m.create_table_if_not_exists(table_name, callback); + } else { + m.create_table(table_name, callback); + } + + connection.execute(&m.make::<C::SqlGenerator>()).unwrap(); + } + } + } +} + +#[derive(PartialEq)] +pub enum CreateModelOption { + IfNotExist, +} diff --git a/src/db/migration/mod.rs b/src/db/migration/mod.rs index d53f46b..d511f88 100644 --- a/src/db/migration/mod.rs +++ b/src/db/migration/mod.rs @@ -1,5 +1,13 @@ pub use tosin_macros::gather_migrations as gather; +use diesel::{Connection, result::Error as DieselError}; + +use crate::db::backend::Connectable; + +mod change; + +pub use change::*; + pub struct Migration { pub id: usize, pub name: &'static str, @@ -7,6 +15,15 @@ pub struct Migration { pub changes: &'static [DatabaseChange], } -pub enum DatabaseChange { - CreateModel, +impl Migration { + pub fn apply<C: Connectable>(&self, app_name: &str, connection: &C::Connection) { + // TODO prevent double-applying + connection.transaction::<_, DieselError, _>(|| { + for change in self.changes { + change.apply::<C>(app_name, connection); + } + + Ok(()) + }).unwrap(); + } } |