aboutsummaryrefslogtreecommitdiff
path: root/src/db/migration
diff options
context:
space:
mode:
authorMelody Horn / boringcactus <melody@boringcactus.com>2021-06-16 14:22:50 -0600
committerMelody Horn / boringcactus <melody@boringcactus.com>2021-06-16 14:22:50 -0600
commit58d2f63f4577bc701b6bd655064cefebb65118b4 (patch)
tree0427ac03e6d0d0ed7879aecaa45cd3937939aa4e /src/db/migration
parent685b47247aad71468f190c42929ca6f0dce843fa (diff)
downloadtosin-58d2f63f4577bc701b6bd655064cefebb65118b4.tar.gz
tosin-58d2f63f4577bc701b6bd655064cefebb65118b4.zip
actually run migrations
Diffstat (limited to 'src/db/migration')
-rw-r--r--src/db/migration/change.rs62
-rw-r--r--src/db/migration/mod.rs21
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();
+ }
}