From a4c1595619986938aec698edb5e17286e3839e42 Mon Sep 17 00:00:00 2001 From: Melody Horn / boringcactus Date: Fri, 18 Jun 2021 16:03:24 -0600 Subject: actually make migrations --- Cargo.toml | 2 ++ src/cli/make_migrations.rs | 65 ++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ed90c9c..76282f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,9 @@ edition = "2018" barrel = { version = "0.6.5", features = ["sqlite3"] } diesel = { version = "1.4.4", features = ["sqlite"] } hyper = { version = "0.14", features = ["full"] } +quote = "1.0" structopt = "0.3.21" +syn = { version = "1.0", features = ["full", "extra-traits"] } time = "0.2.27" tokio = { version = "1", features = ["full"] } tosin-macros = { version = "0.1.0", path = "./tosin-macros" } diff --git a/src/cli/make_migrations.rs b/src/cli/make_migrations.rs index 767639f..f4edf94 100644 --- a/src/cli/make_migrations.rs +++ b/src/cli/make_migrations.rs @@ -1,5 +1,8 @@ use std::collections::HashMap; +use std::fs; +use std::path::PathBuf; +use quote::{quote, ToTokens}; use structopt::StructOpt; use crate::{Settings, UrlMap, db::backend::Connectable}; @@ -21,6 +24,36 @@ struct TableState { fields: Vec, } +impl AppTablesState { + fn changes_to(self, dest: AppTablesState) -> Vec { + let mut result = vec![]; + for table in dest.db.keys() { + if !self.db.contains_key(table) { + let fields = &dest.db[table].fields.iter().map(|field| { + match field { + Field::CharField { name, max_length: Some(max_length) } => quote! { Field::CharField { name: #name, max_length: Some(#max_length) } }, + Field::CharField { name, max_length: None } => quote! { Field::CharField { name: #name, max_length: None } }, + + Field::DateTimeField { name } => quote! { Field::DateTimeField { name: #name } }, + + Field::IntField { name } => quote! { Field::IntField { name: #name } }, + } + }).collect::>(); + result.push(quote! { + DatabaseChange::CreateModel { + name: #table, + fields: &[ + #(#fields),* + ], + options: &[], + } + }); + } + } + result + } +} + impl From<&[ModelMeta]> for AppTablesState { fn from(models: &[ModelMeta]) -> Self { let mut db = HashMap::new(); @@ -59,8 +92,36 @@ impl MakeMigrations { for app in settings.installed_apps { let expected_table_state = AppTablesState::from(app.models); let actual_table_state = AppTablesState::from(app.migrations); - dbg!(expected_table_state, actual_table_state); - todo!(); + let next_id = app.migrations.iter().map(|m| m.id).max().map_or(1, |x| x + 1); + let name = "auto"; // TODO names + let changes = actual_table_state.changes_to(expected_table_state); + if changes.is_empty() { continue; } + let migration = quote! { + Migration { + id: #next_id, + name: #name, + prereqs: &[], // TODO + changes: &[ #(#changes),* ], + } + }; + let file = quote! { + use crate::db::migration::Migration; + + pub const MIGRATION: Migration = #migration; + }; + let file_name = format!("m_{:04}_{}.rs", next_id, name); + let file_text = file.into_token_stream().to_string(); + let app_folder = app.name.split("::") + .skip(1) + .collect::(); + // TODO don't explode if running in a weird place + let file_path = PathBuf::from("src") + .join(app_folder) + .join("migrations") + .join(file_name); + println!("Saving migration to {}...", file_path.display()); + fs::write(file_path, file_text).unwrap(); + // TODO cargo fmt } } } -- cgit v1.2.3