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 --- src/cli/make_migrations.rs | 65 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 2 deletions(-) (limited to 'src') 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