aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cli/make_migrations.rs65
1 files changed, 63 insertions, 2 deletions
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<Field>,
}
+impl AppTablesState {
+ fn changes_to(self, dest: AppTablesState) -> Vec<impl ToTokens> {
+ 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::<Vec<_>>();
+ 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::<PathBuf>();
+ // 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
}
}
}