diff --git a/diesel_cli/src/cli.rs b/diesel_cli/src/cli.rs index af9b63c7ec4f..25bf28de6028 100644 --- a/diesel_cli/src/cli.rs +++ b/diesel_cli/src/cli.rs @@ -98,6 +98,8 @@ pub fn build_cli() -> Command { ) .arg( Arg::new("MIGRATION_NAME") + .index(1) + .num_args(1) .help("The name of the migration to create.") .required(true), ) @@ -145,6 +147,29 @@ pub fn build_cli() -> Command { .default_missing_value("NOT_SET") .num_args(0..=1) .require_equals(true), + ) + .arg( + Arg::new("table-name") + .index(2) + .num_args(1..) + .action(clap::ArgAction::Append) + .help("Table names to filter."), + ) + .arg( + Arg::new("only-tables") + .short('o') + .long("only-tables") + .action(ArgAction::SetTrue) + .help("Only include tables from table-name that matches regexp.") + .conflicts_with("except-tables"), + ) + .arg( + Arg::new("except-tables") + .short('e') + .long("except-tables") + .action(ArgAction::SetTrue) + .help("Exclude tables from table-name that matches regex.") + .conflicts_with("only-tables"), ), ) .subcommand_required(true) @@ -198,7 +223,7 @@ pub fn build_cli() -> Command { .index(1) .num_args(1..) .action(clap::ArgAction::Append) - .help("Table names to filter (default only-tables if not empty)."), + .help("Table names to filter."), ) .arg( Arg::new("only-tables") diff --git a/diesel_cli/src/config.rs b/diesel_cli/src/config.rs index 9a8206e4b7af..9486a55a0e8f 100644 --- a/diesel_cli/src/config.rs +++ b/diesel_cli/src/config.rs @@ -1,11 +1,14 @@ use clap::ArgMatches; -use serde::Deserialize; -use std::env; +use serde::de::{self, MapAccess, Visitor}; +use serde::{Deserialize, Deserializer}; +use serde_regex::Serde as RegexWrapper; use std::error::Error; use std::fs; use std::path::{Path, PathBuf}; +use std::{env, fmt}; use super::find_project_root; +use crate::infer_schema_internals::TableName; use crate::print_schema; use crate::print_schema::ColumnSorting; @@ -46,6 +49,26 @@ impl Config { migration.set_relative_path_base(base); } } + + pub fn set_filter( + mut self, + matches: &ArgMatches, + ) -> Result> { + let table_names = matches + .get_many::("table-name") + .unwrap_or_default() + .map(|table_name_regex| regex::Regex::new(table_name_regex).map(Into::into)) + .collect::, _>>() + .map_err(|e| format!("invalid argument for table filtering regex: {e}"))?; + + if matches.get_flag("only-tables") { + self.print_schema.filter = Filtering::OnlyTables(table_names) + } else if matches.get_flag("except-tables") { + self.print_schema.filter = Filtering::ExceptTables(table_names) + } + + Ok(self) + } } #[derive(Default, Deserialize)] @@ -56,7 +79,7 @@ pub struct PrintSchema { #[serde(default)] pub with_docs: print_schema::DocConfig, #[serde(default)] - pub filter: print_schema::Filtering, + pub filter: Filtering, #[serde(default)] pub column_sorting: ColumnSorting, #[serde(default)] @@ -129,3 +152,86 @@ impl MigrationsDirectory { } } } + +type Regex = RegexWrapper<::regex::Regex>; + +#[derive(Clone)] +pub enum Filtering { + OnlyTables(Vec), + ExceptTables(Vec), + None, +} + +#[allow(clippy::derivable_impls)] // that's not supported on rust 1.65 +impl Default for Filtering { + fn default() -> Self { + Filtering::None + } +} + +impl Filtering { + pub fn should_ignore_table(&self, name: &TableName) -> bool { + use self::Filtering::*; + + match *self { + OnlyTables(ref regexes) => !regexes.iter().any(|regex| regex.is_match(&name.sql_name)), + ExceptTables(ref regexes) => regexes.iter().any(|regex| regex.is_match(&name.sql_name)), + None => false, + } + } +} + +impl<'de> Deserialize<'de> for Filtering { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct FilteringVisitor; + + impl<'de> Visitor<'de> for FilteringVisitor { + type Value = Filtering; + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("either only_tables or except_tables") + } + + fn visit_map(self, mut map: V) -> Result + where + V: MapAccess<'de>, + { + let mut only_tables = None::>; + let mut except_tables = None::>; + while let Some(key) = map.next_key::()? { + match &key as &str { + "only_tables" => { + if only_tables.is_some() { + return Err(de::Error::duplicate_field("only_tables")); + } + only_tables = Some(map.next_value()?); + } + "except_tables" => { + if except_tables.is_some() { + return Err(de::Error::duplicate_field("except_tables")); + } + except_tables = Some(map.next_value()?); + } + _ => { + return Err(de::Error::unknown_field( + &key, + &["only_tables", "except_tables"], + )) + } + } + } + match (only_tables, except_tables) { + (Some(t), None) => Ok(Filtering::OnlyTables(t)), + (None, Some(t)) => Ok(Filtering::ExceptTables(t)), + (None, None) => Ok(Filtering::None), + _ => Err(de::Error::duplicate_field("only_tables except_tables")), + } + } + } + + deserializer.deserialize_map(FilteringVisitor) + } +} diff --git a/diesel_cli/src/infer_schema_internals/inference.rs b/diesel_cli/src/infer_schema_internals/inference.rs index 55327403fd67..37d5094a2174 100644 --- a/diesel_cli/src/infer_schema_internals/inference.rs +++ b/diesel_cli/src/infer_schema_internals/inference.rs @@ -4,6 +4,9 @@ use diesel::result::Error::NotFound; use super::data_structures::*; use super::table_data::*; + +use crate::config::Filtering; + use crate::database::InferConnection; use crate::print_schema::{ColumnSorting, DocConfig}; @@ -124,6 +127,13 @@ pub fn load_table_names( } } +pub fn filter_table_names(table_names: Vec, table_filter: &Filtering) -> Vec { + table_names + .into_iter() + .filter(|t| !table_filter.should_ignore_table(t)) + .collect::<_>() +} + fn get_table_comment( conn: &mut InferConnection, table: &TableName, diff --git a/diesel_cli/src/main.rs b/diesel_cli/src/main.rs index fc5e82fbdee2..62f4fb844ea7 100644 --- a/diesel_cli/src/main.rs +++ b/diesel_cli/src/main.rs @@ -31,7 +31,6 @@ use database::InferConnection; use diesel::backend::Backend; use diesel::Connection; use diesel_migrations::{FileBasedMigrations, HarnessWithOutput, MigrationHarness}; -use regex::Regex; use std::error::Error; use std::fmt::Display; use std::io::stdout; @@ -220,25 +219,12 @@ fn run_infer_schema(matches: &ArgMatches) -> Result<(), Box("schema") { config.schema = Some(schema_name.clone()) } - let filter = matches - .get_many::("table-name") - .unwrap_or_default() - .map(|table_name_regex| Regex::new(table_name_regex).map(Into::into)) - .collect::>() - .map_err(|e| format!("invalid argument for table filtering regex: {e}")); - - if matches.get_flag("only-tables") { - config.filter = Filtering::OnlyTables(filter?) - } else if matches.get_flag("except-tables") { - config.filter = Filtering::ExceptTables(filter?) - } - if matches.get_flag("with-docs") { config.with_docs = DocConfig::DatabaseCommentsFallbackToAutoGeneratedDocComment; } @@ -282,8 +268,8 @@ fn regenerate_schema_if_file_specified( ) -> Result<(), Box> { use std::io::Read; - let config = Config::read(matches)?; - if let Some(ref path) = config.print_schema.file { + let config = Config::read(matches)?.print_schema; + if let Some(ref path) = config.file { let mut connection = InferConnection::from_matches(matches); if let Some(parent) = path.parent() { fs::create_dir_all(parent)?; @@ -291,7 +277,7 @@ fn regenerate_schema_if_file_specified( if matches.get_flag("LOCKED_SCHEMA") { let mut buf = Vec::new(); - print_schema::run_print_schema(&mut connection, &config.print_schema, &mut buf)?; + print_schema::run_print_schema(&mut connection, &config, &mut buf)?; let mut old_buf = Vec::new(); let mut file = fs::File::open(path)?; @@ -309,7 +295,7 @@ fn regenerate_schema_if_file_specified( use std::io::Write; let mut file = fs::File::create(path)?; - let schema = print_schema::output_schema(&mut connection, &config.print_schema)?; + let schema = print_schema::output_schema(&mut connection, &config)?; file.write_all(schema.as_bytes())?; } } diff --git a/diesel_cli/src/migrations/diff_schema.rs b/diesel_cli/src/migrations/diff_schema.rs index c2945492ab68..36e381889a89 100644 --- a/diesel_cli/src/migrations/diff_schema.rs +++ b/diesel_cli/src/migrations/diff_schema.rs @@ -13,7 +13,8 @@ use syn::visit::Visit; use crate::config::Config; use crate::database::InferConnection; use crate::infer_schema_internals::{ - ColumnDefinition, ColumnType, ForeignKeyConstraint, TableData, TableName, + filter_table_names, load_table_names, ColumnDefinition, ColumnType, ForeignKeyConstraint, + TableData, TableName, }; use crate::print_schema::DocConfig; @@ -27,10 +28,12 @@ fn compatible_type_list() -> HashMap<&'static str, Vec<&'static str>> { } pub fn generate_sql_based_on_diff_schema( - _config: Config, + config: Config, matches: &ArgMatches, schema_file_path: &Path, ) -> Result<(String, String), Box> { + let config = config.set_filter(matches)?; + let project_root = crate::find_project_root()?; let schema_path = project_root.join(schema_file_path); @@ -43,7 +46,11 @@ pub fn generate_sql_based_on_diff_schema( tables_from_schema.visit_file(&syn_file); let mut conn = InferConnection::from_matches(matches); - let tables_from_database = crate::infer_schema_internals::load_table_names(&mut conn, None)?; + let tables_from_database = filter_table_names( + load_table_names(&mut conn, None)?, + &config.print_schema.filter, + ); + let foreign_keys = crate::infer_schema_internals::load_foreign_key_constraints(&mut conn, None)?; let foreign_key_map = foreign_keys.into_iter().fold(HashMap::new(), |mut acc, t| { diff --git a/diesel_cli/src/migrations/mod.rs b/diesel_cli/src/migrations/mod.rs index b12e7308c104..bcbea6868a30 100644 --- a/diesel_cli/src/migrations/mod.rs +++ b/diesel_cli/src/migrations/mod.rs @@ -88,7 +88,7 @@ pub(super) fn run_migration_command( if let Some(diff_schema) = diff_schema { self::diff_schema::generate_sql_based_on_diff_schema( config, - matches, + args, &diff_schema, )? } else { diff --git a/diesel_cli/src/print_schema.rs b/diesel_cli/src/print_schema.rs index a64f75c8089b..b11d1ee84846 100644 --- a/diesel_cli/src/print_schema.rs +++ b/diesel_cli/src/print_schema.rs @@ -2,9 +2,7 @@ use crate::config; use crate::database::{Backend, InferConnection}; use crate::infer_schema_internals::*; -use serde::de::{self, MapAccess, Visitor}; -use serde::{Deserialize, Deserializer, Serialize}; -use serde_regex::Serde as RegexWrapper; +use serde::{Deserialize, Serialize}; use std::collections::HashSet; use std::error::Error; use std::fmt::{self, Display, Formatter, Write}; @@ -12,33 +10,6 @@ use std::io::Write as IoWrite; const SCHEMA_HEADER: &str = "// @generated automatically by Diesel CLI.\n"; -type Regex = RegexWrapper<::regex::Regex>; - -pub enum Filtering { - OnlyTables(Vec), - ExceptTables(Vec), - None, -} - -#[allow(clippy::derivable_impls)] // that's not supported on rust 1.65 -impl Default for Filtering { - fn default() -> Self { - Filtering::None - } -} - -impl Filtering { - pub fn should_ignore_table(&self, name: &TableName) -> bool { - use self::Filtering::*; - - match *self { - OnlyTables(ref regexes) => !regexes.iter().any(|regex| regex.is_match(&name.sql_name)), - ExceptTables(ref regexes) => regexes.iter().any(|regex| regex.is_match(&name.sql_name)), - None => false, - } - } -} - /// How to sort columns when querying the table schema. #[derive(Debug, Deserialize, Serialize)] pub enum ColumnSorting { @@ -176,10 +147,11 @@ pub fn output_schema( connection: &mut InferConnection, config: &config::PrintSchema, ) -> Result> { - let table_names = load_table_names(connection, config.schema_name())? - .into_iter() - .filter(|t| !config.filter.should_ignore_table(t)) - .collect::>(); + let table_names = filter_table_names( + load_table_names(connection, config.schema_name())?, + &config.filter, + ); + let foreign_keys = load_foreign_key_constraints(connection, config.schema_name())?; let foreign_keys = remove_unsafe_foreign_keys_for_codegen(connection, &foreign_keys, &table_names); @@ -772,61 +744,6 @@ impl<'a, 'b: 'a> Write for PadAdapter<'a, 'b> { } } -impl<'de> Deserialize<'de> for Filtering { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct FilteringVisitor; - - impl<'de> Visitor<'de> for FilteringVisitor { - type Value = Filtering; - - fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("either only_tables or except_tables") - } - - fn visit_map(self, mut map: V) -> Result - where - V: MapAccess<'de>, - { - let mut only_tables = None::>; - let mut except_tables = None::>; - while let Some(key) = map.next_key::()? { - match &key as &str { - "only_tables" => { - if only_tables.is_some() { - return Err(de::Error::duplicate_field("only_tables")); - } - only_tables = Some(map.next_value()?); - } - "except_tables" => { - if except_tables.is_some() { - return Err(de::Error::duplicate_field("except_tables")); - } - except_tables = Some(map.next_value()?); - } - _ => { - return Err(de::Error::unknown_field( - &key, - &["only_tables", "except_tables"], - )) - } - } - } - match (only_tables, except_tables) { - (Some(t), None) => Ok(Filtering::OnlyTables(t)), - (None, Some(t)) => Ok(Filtering::ExceptTables(t)), - (None, None) => Ok(Filtering::None), - _ => Err(de::Error::duplicate_field("only_tables except_tables")), - } - } - } - - deserializer.deserialize_map(FilteringVisitor) - } -} - impl DocConfig { pub const VARIANTS_STR: &'static [&'static str] = &[ "database-comments-fallback-to-auto-generated-doc-comment", diff --git a/diesel_cli/tests/generate_migrations/diff_except_tables/diesel.toml b/diesel_cli/tests/generate_migrations/diff_except_tables/diesel.toml new file mode 100644 index 000000000000..885aaed16632 --- /dev/null +++ b/diesel_cli/tests/generate_migrations/diff_except_tables/diesel.toml @@ -0,0 +1,2 @@ +[print_schema] +filter = { except_tables = ["table_b", "table_c"] } diff --git a/diesel_cli/tests/generate_migrations/diff_except_tables/mysql/down.sql/expected.snap b/diesel_cli/tests/generate_migrations/diff_except_tables/mysql/down.sql/expected.snap new file mode 100644 index 000000000000..97ad299447dd --- /dev/null +++ b/diesel_cli/tests/generate_migrations/diff_except_tables/mysql/down.sql/expected.snap @@ -0,0 +1,9 @@ +--- +source: diesel_cli/tests/migration_generate.rs +description: "Test: diff_except_tables" +--- +-- This file should undo anything in `up.sql` +ALTER TABLE `table_a` DROP COLUMN `script`; +ALTER TABLE `table_a` ADD COLUMN `code` TEXT NOT NULL; + + diff --git a/diesel_cli/tests/generate_migrations/diff_except_tables/mysql/initial_schema.sql b/diesel_cli/tests/generate_migrations/diff_except_tables/mysql/initial_schema.sql new file mode 100644 index 000000000000..aa1640d6ea45 --- /dev/null +++ b/diesel_cli/tests/generate_migrations/diff_except_tables/mysql/initial_schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE table_a(id INTEGER NOT NULL PRIMARY KEY, code TEXT NOT NULL); +CREATE TABLE table_b(id INTEGER NOT NULL PRIMARY KEY); +CREATE TABLE table_c(id INTEGER NOT NULL PRIMARY KEY); diff --git a/diesel_cli/tests/generate_migrations/diff_except_tables/mysql/schema_out.rs/expected.snap b/diesel_cli/tests/generate_migrations/diff_except_tables/mysql/schema_out.rs/expected.snap new file mode 100644 index 000000000000..6a964649cc86 --- /dev/null +++ b/diesel_cli/tests/generate_migrations/diff_except_tables/mysql/schema_out.rs/expected.snap @@ -0,0 +1,13 @@ +--- +source: diesel_cli/tests/migration_generate.rs +description: "Test: diff_except_tables" +--- +// @generated automatically by Diesel CLI. + +diesel::table! { + table_a (id) { + id -> Integer, + script -> Text, + } +} + diff --git a/diesel_cli/tests/generate_migrations/diff_except_tables/mysql/up.sql/expected.snap b/diesel_cli/tests/generate_migrations/diff_except_tables/mysql/up.sql/expected.snap new file mode 100644 index 000000000000..0c3cb1b956a4 --- /dev/null +++ b/diesel_cli/tests/generate_migrations/diff_except_tables/mysql/up.sql/expected.snap @@ -0,0 +1,9 @@ +--- +source: diesel_cli/tests/migration_generate.rs +description: "Test: diff_except_tables" +--- +-- Your SQL goes here +ALTER TABLE `table_a` DROP COLUMN `code`; +ALTER TABLE `table_a` ADD COLUMN `script` TEXT NOT NULL; + + diff --git a/diesel_cli/tests/generate_migrations/diff_except_tables/postgres/down.sql/expected.snap b/diesel_cli/tests/generate_migrations/diff_except_tables/postgres/down.sql/expected.snap new file mode 100644 index 000000000000..39788a83da29 --- /dev/null +++ b/diesel_cli/tests/generate_migrations/diff_except_tables/postgres/down.sql/expected.snap @@ -0,0 +1,9 @@ +--- +source: diesel_cli/tests/migration_generate.rs +description: "Test: diff_except_tables" +--- +-- This file should undo anything in `up.sql` +ALTER TABLE "table_a" DROP COLUMN "script"; +ALTER TABLE "table_a" ADD COLUMN "code" TEXT NOT NULL; + + diff --git a/diesel_cli/tests/generate_migrations/diff_except_tables/postgres/initial_schema.sql b/diesel_cli/tests/generate_migrations/diff_except_tables/postgres/initial_schema.sql new file mode 100644 index 000000000000..aa1640d6ea45 --- /dev/null +++ b/diesel_cli/tests/generate_migrations/diff_except_tables/postgres/initial_schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE table_a(id INTEGER NOT NULL PRIMARY KEY, code TEXT NOT NULL); +CREATE TABLE table_b(id INTEGER NOT NULL PRIMARY KEY); +CREATE TABLE table_c(id INTEGER NOT NULL PRIMARY KEY); diff --git a/diesel_cli/tests/generate_migrations/diff_except_tables/postgres/schema_out.rs/expected.snap b/diesel_cli/tests/generate_migrations/diff_except_tables/postgres/schema_out.rs/expected.snap new file mode 100644 index 000000000000..a5c7110333b3 --- /dev/null +++ b/diesel_cli/tests/generate_migrations/diff_except_tables/postgres/schema_out.rs/expected.snap @@ -0,0 +1,13 @@ +--- +source: diesel_cli/tests/migration_generate.rs +description: "Test: diff_except_tables" +--- +// @generated automatically by Diesel CLI. + +diesel::table! { + table_a (id) { + id -> Int4, + script -> Text, + } +} + diff --git a/diesel_cli/tests/generate_migrations/diff_except_tables/postgres/up.sql/expected.snap b/diesel_cli/tests/generate_migrations/diff_except_tables/postgres/up.sql/expected.snap new file mode 100644 index 000000000000..4aee338f541d --- /dev/null +++ b/diesel_cli/tests/generate_migrations/diff_except_tables/postgres/up.sql/expected.snap @@ -0,0 +1,9 @@ +--- +source: diesel_cli/tests/migration_generate.rs +description: "Test: diff_except_tables" +--- +-- Your SQL goes here +ALTER TABLE "table_a" DROP COLUMN "code"; +ALTER TABLE "table_a" ADD COLUMN "script" TEXT NOT NULL; + + diff --git a/diesel_cli/tests/generate_migrations/diff_except_tables/schema.rs b/diesel_cli/tests/generate_migrations/diff_except_tables/schema.rs new file mode 100644 index 000000000000..eea0858b09b3 --- /dev/null +++ b/diesel_cli/tests/generate_migrations/diff_except_tables/schema.rs @@ -0,0 +1,6 @@ +diesel::table! { + table_a (id) { + id -> Integer, + script -> Text, + } +} diff --git a/diesel_cli/tests/generate_migrations/diff_except_tables/sqlite/down.sql/expected.snap b/diesel_cli/tests/generate_migrations/diff_except_tables/sqlite/down.sql/expected.snap new file mode 100644 index 000000000000..97ad299447dd --- /dev/null +++ b/diesel_cli/tests/generate_migrations/diff_except_tables/sqlite/down.sql/expected.snap @@ -0,0 +1,9 @@ +--- +source: diesel_cli/tests/migration_generate.rs +description: "Test: diff_except_tables" +--- +-- This file should undo anything in `up.sql` +ALTER TABLE `table_a` DROP COLUMN `script`; +ALTER TABLE `table_a` ADD COLUMN `code` TEXT NOT NULL; + + diff --git a/diesel_cli/tests/generate_migrations/diff_except_tables/sqlite/initial_schema.sql b/diesel_cli/tests/generate_migrations/diff_except_tables/sqlite/initial_schema.sql new file mode 100644 index 000000000000..aa1640d6ea45 --- /dev/null +++ b/diesel_cli/tests/generate_migrations/diff_except_tables/sqlite/initial_schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE table_a(id INTEGER NOT NULL PRIMARY KEY, code TEXT NOT NULL); +CREATE TABLE table_b(id INTEGER NOT NULL PRIMARY KEY); +CREATE TABLE table_c(id INTEGER NOT NULL PRIMARY KEY); diff --git a/diesel_cli/tests/generate_migrations/diff_except_tables/sqlite/schema_out.rs/expected.snap b/diesel_cli/tests/generate_migrations/diff_except_tables/sqlite/schema_out.rs/expected.snap new file mode 100644 index 000000000000..6a964649cc86 --- /dev/null +++ b/diesel_cli/tests/generate_migrations/diff_except_tables/sqlite/schema_out.rs/expected.snap @@ -0,0 +1,13 @@ +--- +source: diesel_cli/tests/migration_generate.rs +description: "Test: diff_except_tables" +--- +// @generated automatically by Diesel CLI. + +diesel::table! { + table_a (id) { + id -> Integer, + script -> Text, + } +} + diff --git a/diesel_cli/tests/generate_migrations/diff_except_tables/sqlite/up.sql/expected.snap b/diesel_cli/tests/generate_migrations/diff_except_tables/sqlite/up.sql/expected.snap new file mode 100644 index 000000000000..0c3cb1b956a4 --- /dev/null +++ b/diesel_cli/tests/generate_migrations/diff_except_tables/sqlite/up.sql/expected.snap @@ -0,0 +1,9 @@ +--- +source: diesel_cli/tests/migration_generate.rs +description: "Test: diff_except_tables" +--- +-- Your SQL goes here +ALTER TABLE `table_a` DROP COLUMN `code`; +ALTER TABLE `table_a` ADD COLUMN `script` TEXT NOT NULL; + + diff --git a/diesel_cli/tests/generate_migrations/diff_only_tables/diesel.toml b/diesel_cli/tests/generate_migrations/diff_only_tables/diesel.toml new file mode 100644 index 000000000000..66ee2f8dc43f --- /dev/null +++ b/diesel_cli/tests/generate_migrations/diff_only_tables/diesel.toml @@ -0,0 +1,2 @@ +[print_schema] +filter = { only_tables = ["table_a"] } diff --git a/diesel_cli/tests/generate_migrations/diff_only_tables/mysql/down.sql/expected.snap b/diesel_cli/tests/generate_migrations/diff_only_tables/mysql/down.sql/expected.snap new file mode 100644 index 000000000000..6a5aef194160 --- /dev/null +++ b/diesel_cli/tests/generate_migrations/diff_only_tables/mysql/down.sql/expected.snap @@ -0,0 +1,9 @@ +--- +source: diesel_cli/tests/migration_generate.rs +description: "Test: diff_only_tables" +--- +-- This file should undo anything in `up.sql` +ALTER TABLE `table_a` DROP COLUMN `script`; +ALTER TABLE `table_a` ADD COLUMN `code` TEXT NOT NULL; + + diff --git a/diesel_cli/tests/generate_migrations/diff_only_tables/mysql/initial_schema.sql b/diesel_cli/tests/generate_migrations/diff_only_tables/mysql/initial_schema.sql new file mode 100644 index 000000000000..aa1640d6ea45 --- /dev/null +++ b/diesel_cli/tests/generate_migrations/diff_only_tables/mysql/initial_schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE table_a(id INTEGER NOT NULL PRIMARY KEY, code TEXT NOT NULL); +CREATE TABLE table_b(id INTEGER NOT NULL PRIMARY KEY); +CREATE TABLE table_c(id INTEGER NOT NULL PRIMARY KEY); diff --git a/diesel_cli/tests/generate_migrations/diff_only_tables/mysql/schema_out.rs/expected.snap b/diesel_cli/tests/generate_migrations/diff_only_tables/mysql/schema_out.rs/expected.snap new file mode 100644 index 000000000000..f9623dc70f1d --- /dev/null +++ b/diesel_cli/tests/generate_migrations/diff_only_tables/mysql/schema_out.rs/expected.snap @@ -0,0 +1,13 @@ +--- +source: diesel_cli/tests/migration_generate.rs +description: "Test: diff_only_tables" +--- +// @generated automatically by Diesel CLI. + +diesel::table! { + table_a (id) { + id -> Integer, + script -> Text, + } +} + diff --git a/diesel_cli/tests/generate_migrations/diff_only_tables/mysql/up.sql/expected.snap b/diesel_cli/tests/generate_migrations/diff_only_tables/mysql/up.sql/expected.snap new file mode 100644 index 000000000000..5aa41c0e26a4 --- /dev/null +++ b/diesel_cli/tests/generate_migrations/diff_only_tables/mysql/up.sql/expected.snap @@ -0,0 +1,9 @@ +--- +source: diesel_cli/tests/migration_generate.rs +description: "Test: diff_only_tables" +--- +-- Your SQL goes here +ALTER TABLE `table_a` DROP COLUMN `code`; +ALTER TABLE `table_a` ADD COLUMN `script` TEXT NOT NULL; + + diff --git a/diesel_cli/tests/generate_migrations/diff_only_tables/postgres/down.sql/expected.snap b/diesel_cli/tests/generate_migrations/diff_only_tables/postgres/down.sql/expected.snap new file mode 100644 index 000000000000..a9e89d29b22a --- /dev/null +++ b/diesel_cli/tests/generate_migrations/diff_only_tables/postgres/down.sql/expected.snap @@ -0,0 +1,9 @@ +--- +source: diesel_cli/tests/migration_generate.rs +description: "Test: diff_only_tables" +--- +-- This file should undo anything in `up.sql` +ALTER TABLE "table_a" DROP COLUMN "script"; +ALTER TABLE "table_a" ADD COLUMN "code" TEXT NOT NULL; + + diff --git a/diesel_cli/tests/generate_migrations/diff_only_tables/postgres/initial_schema.sql b/diesel_cli/tests/generate_migrations/diff_only_tables/postgres/initial_schema.sql new file mode 100644 index 000000000000..aa1640d6ea45 --- /dev/null +++ b/diesel_cli/tests/generate_migrations/diff_only_tables/postgres/initial_schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE table_a(id INTEGER NOT NULL PRIMARY KEY, code TEXT NOT NULL); +CREATE TABLE table_b(id INTEGER NOT NULL PRIMARY KEY); +CREATE TABLE table_c(id INTEGER NOT NULL PRIMARY KEY); diff --git a/diesel_cli/tests/generate_migrations/diff_only_tables/postgres/schema_out.rs/expected.snap b/diesel_cli/tests/generate_migrations/diff_only_tables/postgres/schema_out.rs/expected.snap new file mode 100644 index 000000000000..1356f0468ec6 --- /dev/null +++ b/diesel_cli/tests/generate_migrations/diff_only_tables/postgres/schema_out.rs/expected.snap @@ -0,0 +1,13 @@ +--- +source: diesel_cli/tests/migration_generate.rs +description: "Test: diff_only_tables" +--- +// @generated automatically by Diesel CLI. + +diesel::table! { + table_a (id) { + id -> Int4, + script -> Text, + } +} + diff --git a/diesel_cli/tests/generate_migrations/diff_only_tables/postgres/up.sql/expected.snap b/diesel_cli/tests/generate_migrations/diff_only_tables/postgres/up.sql/expected.snap new file mode 100644 index 000000000000..bac54f32c019 --- /dev/null +++ b/diesel_cli/tests/generate_migrations/diff_only_tables/postgres/up.sql/expected.snap @@ -0,0 +1,9 @@ +--- +source: diesel_cli/tests/migration_generate.rs +description: "Test: diff_only_tables" +--- +-- Your SQL goes here +ALTER TABLE "table_a" DROP COLUMN "code"; +ALTER TABLE "table_a" ADD COLUMN "script" TEXT NOT NULL; + + diff --git a/diesel_cli/tests/generate_migrations/diff_only_tables/schema.rs b/diesel_cli/tests/generate_migrations/diff_only_tables/schema.rs new file mode 100644 index 000000000000..eea0858b09b3 --- /dev/null +++ b/diesel_cli/tests/generate_migrations/diff_only_tables/schema.rs @@ -0,0 +1,6 @@ +diesel::table! { + table_a (id) { + id -> Integer, + script -> Text, + } +} diff --git a/diesel_cli/tests/generate_migrations/diff_only_tables/sqlite/down.sql/expected.snap b/diesel_cli/tests/generate_migrations/diff_only_tables/sqlite/down.sql/expected.snap new file mode 100644 index 000000000000..6a5aef194160 --- /dev/null +++ b/diesel_cli/tests/generate_migrations/diff_only_tables/sqlite/down.sql/expected.snap @@ -0,0 +1,9 @@ +--- +source: diesel_cli/tests/migration_generate.rs +description: "Test: diff_only_tables" +--- +-- This file should undo anything in `up.sql` +ALTER TABLE `table_a` DROP COLUMN `script`; +ALTER TABLE `table_a` ADD COLUMN `code` TEXT NOT NULL; + + diff --git a/diesel_cli/tests/generate_migrations/diff_only_tables/sqlite/initial_schema.sql b/diesel_cli/tests/generate_migrations/diff_only_tables/sqlite/initial_schema.sql new file mode 100644 index 000000000000..aa1640d6ea45 --- /dev/null +++ b/diesel_cli/tests/generate_migrations/diff_only_tables/sqlite/initial_schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE table_a(id INTEGER NOT NULL PRIMARY KEY, code TEXT NOT NULL); +CREATE TABLE table_b(id INTEGER NOT NULL PRIMARY KEY); +CREATE TABLE table_c(id INTEGER NOT NULL PRIMARY KEY); diff --git a/diesel_cli/tests/generate_migrations/diff_only_tables/sqlite/schema_out.rs/expected.snap b/diesel_cli/tests/generate_migrations/diff_only_tables/sqlite/schema_out.rs/expected.snap new file mode 100644 index 000000000000..f9623dc70f1d --- /dev/null +++ b/diesel_cli/tests/generate_migrations/diff_only_tables/sqlite/schema_out.rs/expected.snap @@ -0,0 +1,13 @@ +--- +source: diesel_cli/tests/migration_generate.rs +description: "Test: diff_only_tables" +--- +// @generated automatically by Diesel CLI. + +diesel::table! { + table_a (id) { + id -> Integer, + script -> Text, + } +} + diff --git a/diesel_cli/tests/generate_migrations/diff_only_tables/sqlite/up.sql/expected.snap b/diesel_cli/tests/generate_migrations/diff_only_tables/sqlite/up.sql/expected.snap new file mode 100644 index 000000000000..5aa41c0e26a4 --- /dev/null +++ b/diesel_cli/tests/generate_migrations/diff_only_tables/sqlite/up.sql/expected.snap @@ -0,0 +1,9 @@ +--- +source: diesel_cli/tests/migration_generate.rs +description: "Test: diff_only_tables" +--- +-- Your SQL goes here +ALTER TABLE `table_a` DROP COLUMN `code`; +ALTER TABLE `table_a` ADD COLUMN `script` TEXT NOT NULL; + + diff --git a/diesel_cli/tests/migration_generate.rs b/diesel_cli/tests/migration_generate.rs index c3402993dece..68ea79808485 100644 --- a/diesel_cli/tests/migration_generate.rs +++ b/diesel_cli/tests/migration_generate.rs @@ -4,7 +4,7 @@ use std::{fs::File, io::Read}; use chrono::prelude::*; use regex::Regex; -use crate::support::project; +use crate::support::{project, Project}; pub static TIMESTAMP_FORMAT: &str = "%Y-%m-%d-%H%M%S"; #[test] @@ -260,6 +260,16 @@ fn migration_generate_from_diff_drop_table_composite_key() { test_generate_migration("diff_drop_table_composite_key", Vec::new()); } +#[test] +fn migration_generate_from_diff_only_tables() { + test_generate_migration("diff_only_tables", vec!["-o", "table_a"]); +} + +#[test] +fn migration_generate_from_diff_except_tables() { + test_generate_migration("diff_except_tables", vec!["-e", "table_b", "table_c"]); +} + #[cfg(feature = "sqlite")] const BACKEND: &str = "sqlite"; #[cfg(feature = "postgres")] @@ -278,6 +288,24 @@ fn backend_file_path(test_name: &str, file: &str) -> PathBuf { fn test_generate_migration(test_name: &str, args: Vec<&str>) { let p = project(test_name).build(); + run_generate_migration_test(test_name, args, p); + + let config_path = Path::new(env!("CARGO_MANIFEST_DIR")) + .join("tests") + .join("generate_migrations") + .join(test_name) + .join("diesel.toml"); + + if Path::new(&config_path).exists() { + let p = project(test_name) + .file("diesel.toml", &read_file(&config_path)) + .build(); + + run_generate_migration_test(test_name, Vec::new(), p); + } +} + +fn run_generate_migration_test(test_name: &str, args: Vec<&str>, p: Project) { let db = crate::support::database(&p.database_url()); p.command("setup").run(); @@ -306,7 +334,7 @@ fn test_generate_migration(test_name: &str, args: Vec<&str>) { "--diff-schema={schema_rs}", schema_rs = schema_rs.display() )) - .args(args) + .args(args.clone()) .run(); assert!(result.is_success(), "Result was unsuccessful {:?}", result); @@ -338,7 +366,7 @@ fn test_generate_migration(test_name: &str, args: Vec<&str>) { assert!(result.is_success(), "Result was unsuccessful {:?}", result); // check that we get back the expected schema - let result = p.command("print-schema").run(); + let result = p.command("print-schema").args(args).run(); assert!(result.is_success(), "Result was unsuccessful {:?}", result); let result = result.stdout().replace("\r\n", "\n"); diff --git a/diesel_cli/tests/support/mod.rs b/diesel_cli/tests/support/mod.rs index 56f407bf9cce..10e86f9b2ff2 100644 --- a/diesel_cli/tests/support/mod.rs +++ b/diesel_cli/tests/support/mod.rs @@ -30,7 +30,7 @@ mod postgres_database; #[cfg(rustfmt)] mod sqlite_database; -pub use self::project_builder::project; +pub use self::project_builder::{project, Project}; pub fn database(url: &str) -> database::Database { database::Database::new(url)