diff --git a/CHANGELOG.md b/CHANGELOG.md index 08afbbb1ed9e..531b0119c2bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,6 +55,9 @@ for Rust libraries in [RFC #1105](https://github.com/rust-lang/rfcs/blob/master/ For the postgres backend additionally type information where added to the `RawValue` type. This allows to dynamically deserialize `RawValues` in container types. +* CLI flags of `only-tables` and `except-tables` are now interpreted as regular expressions. + Similary, `only_tabels` and `except_tables` in `diesel.toml` are treated as regular expressions. + ### Fixed * Many types were incorrectly considered non-aggregate when they should not diff --git a/diesel_cli/Cargo.toml b/diesel_cli/Cargo.toml index 9a5812bbfcca..2228f5c51d28 100644 --- a/diesel_cli/Cargo.toml +++ b/diesel_cli/Cargo.toml @@ -28,12 +28,12 @@ toml = "0.4.6" url = { version = "2.1.0", optional = true } barrel = { version = ">= 0.5.0", optional = true, features = ["diesel"] } libsqlite3-sys = { version = ">=0.8.0, <0.17.0", optional = true, features = ["min_sqlite_version_3_7_16"] } +regex = "1.0.6" +serde_regex = "0.3.1" [dev-dependencies] difference = "1.0" tempdir = "0.3.4" -regex = "0.2" -url = { version = "2.1.0" } [features] default = ["postgres", "sqlite", "mysql"] diff --git a/diesel_cli/src/cli.rs b/diesel_cli/src/cli.rs index ea11e3826217..e9813f152137 100644 --- a/diesel_cli/src/cli.rs +++ b/diesel_cli/src/cli.rs @@ -123,7 +123,7 @@ pub fn build_cli() -> App<'static, 'static> { Arg::with_name("only-tables") .short("o") .long("only-tables") - .help("Only include tables from table-name") + .help("Only include tables from table-name that matches regexp") .conflicts_with("except-tables") .conflicts_with("blacklist"), ) @@ -139,7 +139,7 @@ pub fn build_cli() -> App<'static, 'static> { Arg::with_name("except-tables") .short("e") .long("except-tables") - .help("Exclude tables from table-name") + .help("Exclude tables from table-name that matches regex") .conflicts_with("only-tables") .conflicts_with("whitelist"), ) diff --git a/diesel_cli/src/main.rs b/diesel_cli/src/main.rs index 80061c60754d..7f3bff876453 100644 --- a/diesel_cli/src/main.rs +++ b/diesel_cli/src/main.rs @@ -24,6 +24,8 @@ extern crate heck; extern crate migrations_internals; #[macro_use] extern crate serde; +extern crate regex; +extern crate serde_regex; extern crate tempfile; extern crate toml; #[cfg(feature = "url")] @@ -46,6 +48,7 @@ mod query_helper; use chrono::*; use clap::{ArgMatches, Shell}; use migrations_internals::{self as migrations, MigrationConnection}; +use regex::Regex; use std::any::Any; use std::error::Error; use std::fmt::Display; @@ -382,17 +385,27 @@ fn run_infer_schema(matches: &ArgMatches) -> Result<(), Box> { config.schema = Some(String::from(schema_name)) } - let filter = matches - .values_of("table-name") - .unwrap_or_default() - .map(|table_name| { - if let Some(schema) = config.schema_name() { - TableName::new(table_name, schema) - } else { - table_name.parse().unwrap() - } - }) - .collect(); + let filter = { + matches + .values_of("table-name") + .unwrap_or_default() + .map(|table_name| { + if let Some(schema) = config.schema_name() { + TableName::new(table_name, schema) + } else { + table_name.parse().unwrap() + } + }) + .collect() + }; + let filter_regex = || { + matches + .values_of("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.is_present("whitelist") { eprintln!("The `whitelist` option has been deprecated and renamed to `only-tables`."); @@ -402,10 +415,14 @@ fn run_infer_schema(matches: &ArgMatches) -> Result<(), Box> { eprintln!("The `blacklist` option has been deprecated and renamed to `except-tables`."); } - if matches.is_present("only-tables") || matches.is_present("whitelist") { + if matches.is_present("whitelist") { config.filter = Filtering::OnlyTables(filter) - } else if matches.is_present("except-tables") || matches.is_present("blacklist") { + } else if matches.is_present("only-tables") { + config.filter = Filtering::OnlyTableRegexes(filter_regex()?) + } else if matches.is_present("blacklist") { config.filter = Filtering::ExceptTables(filter) + } else if matches.is_present("except-tables") { + config.filter = Filtering::ExceptTableRegexes(filter_regex()?) } if matches.is_present("with-docs") { diff --git a/diesel_cli/src/print_schema.rs b/diesel_cli/src/print_schema.rs index 737544359103..3680e6b94ae8 100644 --- a/diesel_cli/src/print_schema.rs +++ b/diesel_cli/src/print_schema.rs @@ -3,6 +3,7 @@ use config; use infer_schema_internals::*; use serde::de::{self, MapAccess, Visitor}; use serde::{Deserialize, Deserializer}; +use serde_regex::Serde as RegexWrapper; use std::error::Error; use std::fmt::{self, Display, Formatter, Write}; use std::fs::File; @@ -11,9 +12,13 @@ use std::path::Path; use std::process::Command; use tempfile::NamedTempFile; +type Regex = RegexWrapper<::regex::Regex>; + pub enum Filtering { OnlyTables(Vec), + OnlyTableRegexes(Vec), ExceptTables(Vec), + ExceptTableRegexes(Vec), None, } @@ -29,7 +34,13 @@ impl Filtering { match *self { OnlyTables(ref names) => !names.contains(name), + OnlyTableRegexes(ref regexes) => { + !regexes.iter().any(|regex| regex.is_match(&name.name)) + } ExceptTables(ref names) => names.contains(name), + ExceptTableRegexes(ref regexes) => { + regexes.iter().any(|regex| regex.is_match(&name.name)) + } None => false, } } @@ -324,21 +335,21 @@ impl<'de> Deserialize<'de> for Filtering { where V: MapAccess<'de>, { - let mut only_tables = None; - let mut except_tables = None; - while let Some((key, value)) = map.next_entry()? { + let mut only_tables = None::>; + let mut except_tables = None::>; + while let Some(key) = map.next_key()? { match key { "only_tables" => { if only_tables.is_some() { return Err(de::Error::duplicate_field("only_tables")); } - only_tables = Some(value); + only_tables = Some(map.next_value()?); } "except_tables" => { if except_tables.is_some() { return Err(de::Error::duplicate_field("except_tables")); } - except_tables = Some(value); + except_tables = Some(map.next_value()?); } _ => { return Err(de::Error::unknown_field( @@ -349,10 +360,10 @@ impl<'de> Deserialize<'de> for Filtering { } } match (only_tables, except_tables) { - (Some(_), Some(_)) => Err(de::Error::duplicate_field("except_tables")), - (Some(w), None) => Ok(Filtering::OnlyTables(w)), - (None, Some(b)) => Ok(Filtering::ExceptTables(b)), + (Some(t), None) => Ok(Filtering::OnlyTableRegexes(t)), + (None, Some(t)) => Ok(Filtering::ExceptTableRegexes(t)), (None, None) => Ok(Filtering::None), + _ => Err(de::Error::duplicate_field("only_tables except_tables")), } } } diff --git a/diesel_cli/tests/print_schema.rs b/diesel_cli/tests/print_schema.rs index 0fbd52bc7d99..3166268f58c6 100644 --- a/diesel_cli/tests/print_schema.rs +++ b/diesel_cli/tests/print_schema.rs @@ -22,6 +22,14 @@ fn run_infer_schema_include() { ); } +#[test] +fn run_infer_schema_include_regex() { + test_print_schema( + "print_schema_only_table_regexes", + vec!["--with-docs", "-w", "users1"], + ); +} + #[test] fn run_infer_schema_exclude() { test_print_schema( @@ -30,6 +38,14 @@ fn run_infer_schema_exclude() { ); } +#[test] +fn run_infer_schema_exclude_regex() { + test_print_schema( + "print_schema_except_table_regexes", + vec!["--with-docs", "-b", "users1"], + ); +} + #[test] fn run_infer_schema_order() { test_print_schema("print_schema_order", vec!["--with-docs"]); diff --git a/diesel_cli/tests/print_schema/print_schema_except_table_regexes/diesel.toml b/diesel_cli/tests/print_schema/print_schema_except_table_regexes/diesel.toml new file mode 100644 index 000000000000..f1ac714489d2 --- /dev/null +++ b/diesel_cli/tests/print_schema/print_schema_except_table_regexes/diesel.toml @@ -0,0 +1,4 @@ +[print_schema] +file = "src/schema.rs" +with_docs = true +filter = { except_tables = [".*1"] } diff --git a/diesel_cli/tests/print_schema/print_schema_except_table_regexes/mysql/expected.rs b/diesel_cli/tests/print_schema/print_schema_except_table_regexes/mysql/expected.rs new file mode 100644 index 000000000000..91928b107c1c --- /dev/null +++ b/diesel_cli/tests/print_schema/print_schema_except_table_regexes/mysql/expected.rs @@ -0,0 +1,13 @@ +table! { + /// Representation of the `users2` table. + /// + /// (Automatically generated by Diesel.) + users2 (id) { + /// The `id` column of the `users2` table. + /// + /// Its SQL type is `Integer`. + /// + /// (Automatically generated by Diesel.) + id -> Integer, + } +} diff --git a/diesel_cli/tests/print_schema/print_schema_except_table_regexes/mysql/schema.sql b/diesel_cli/tests/print_schema/print_schema_except_table_regexes/mysql/schema.sql new file mode 100644 index 000000000000..556e9f7b54e8 --- /dev/null +++ b/diesel_cli/tests/print_schema/print_schema_except_table_regexes/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE users1 (id INTEGER PRIMARY KEY); +CREATE TABLE users2 (id INTEGER PRIMARY KEY); diff --git a/diesel_cli/tests/print_schema/print_schema_except_table_regexes/postgres/expected.rs b/diesel_cli/tests/print_schema/print_schema_except_table_regexes/postgres/expected.rs new file mode 100644 index 000000000000..55227d5f784e --- /dev/null +++ b/diesel_cli/tests/print_schema/print_schema_except_table_regexes/postgres/expected.rs @@ -0,0 +1,13 @@ +table! { + /// Representation of the `users2` table. + /// + /// (Automatically generated by Diesel.) + users2 (id) { + /// The `id` column of the `users2` table. + /// + /// Its SQL type is `Int4`. + /// + /// (Automatically generated by Diesel.) + id -> Int4, + } +} diff --git a/diesel_cli/tests/print_schema/print_schema_except_table_regexes/postgres/schema.sql b/diesel_cli/tests/print_schema/print_schema_except_table_regexes/postgres/schema.sql new file mode 100644 index 000000000000..37d66071ac40 --- /dev/null +++ b/diesel_cli/tests/print_schema/print_schema_except_table_regexes/postgres/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE users1 (id SERIAL PRIMARY KEY); +CREATE TABLE users2 (id SERIAL PRIMARY KEY); diff --git a/diesel_cli/tests/print_schema/print_schema_except_table_regexes/sqlite/expected.rs b/diesel_cli/tests/print_schema/print_schema_except_table_regexes/sqlite/expected.rs new file mode 100644 index 000000000000..dccff6e34548 --- /dev/null +++ b/diesel_cli/tests/print_schema/print_schema_except_table_regexes/sqlite/expected.rs @@ -0,0 +1,13 @@ +table! { + /// Representation of the `users2` table. + /// + /// (Automatically generated by Diesel.) + users2 (id) { + /// The `id` column of the `users2` table. + /// + /// Its SQL type is `Nullable`. + /// + /// (Automatically generated by Diesel.) + id -> Nullable, + } +} diff --git a/diesel_cli/tests/print_schema/print_schema_except_table_regexes/sqlite/schema.sql b/diesel_cli/tests/print_schema/print_schema_except_table_regexes/sqlite/schema.sql new file mode 100644 index 000000000000..556e9f7b54e8 --- /dev/null +++ b/diesel_cli/tests/print_schema/print_schema_except_table_regexes/sqlite/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE users1 (id INTEGER PRIMARY KEY); +CREATE TABLE users2 (id INTEGER PRIMARY KEY); diff --git a/diesel_cli/tests/print_schema/print_schema_only_table_regexes/diesel.toml b/diesel_cli/tests/print_schema/print_schema_only_table_regexes/diesel.toml new file mode 100644 index 000000000000..5f058f8cd628 --- /dev/null +++ b/diesel_cli/tests/print_schema/print_schema_only_table_regexes/diesel.toml @@ -0,0 +1,4 @@ +[print_schema] +file = "src/schema.rs" +with_docs = true +filter = { only_tables = [".*1"] } diff --git a/diesel_cli/tests/print_schema/print_schema_only_table_regexes/mysql/expected.rs b/diesel_cli/tests/print_schema/print_schema_only_table_regexes/mysql/expected.rs new file mode 100644 index 000000000000..0cd54c052913 --- /dev/null +++ b/diesel_cli/tests/print_schema/print_schema_only_table_regexes/mysql/expected.rs @@ -0,0 +1,13 @@ +table! { + /// Representation of the `users1` table. + /// + /// (Automatically generated by Diesel.) + users1 (id) { + /// The `id` column of the `users1` table. + /// + /// Its SQL type is `Integer`. + /// + /// (Automatically generated by Diesel.) + id -> Integer, + } +} diff --git a/diesel_cli/tests/print_schema/print_schema_only_table_regexes/mysql/schema.sql b/diesel_cli/tests/print_schema/print_schema_only_table_regexes/mysql/schema.sql new file mode 100644 index 000000000000..556e9f7b54e8 --- /dev/null +++ b/diesel_cli/tests/print_schema/print_schema_only_table_regexes/mysql/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE users1 (id INTEGER PRIMARY KEY); +CREATE TABLE users2 (id INTEGER PRIMARY KEY); diff --git a/diesel_cli/tests/print_schema/print_schema_only_table_regexes/postgres/expected.rs b/diesel_cli/tests/print_schema/print_schema_only_table_regexes/postgres/expected.rs new file mode 100644 index 000000000000..5bcfd1001180 --- /dev/null +++ b/diesel_cli/tests/print_schema/print_schema_only_table_regexes/postgres/expected.rs @@ -0,0 +1,13 @@ +table! { + /// Representation of the `users1` table. + /// + /// (Automatically generated by Diesel.) + users1 (id) { + /// The `id` column of the `users1` table. + /// + /// Its SQL type is `Int4`. + /// + /// (Automatically generated by Diesel.) + id -> Int4, + } +} diff --git a/diesel_cli/tests/print_schema/print_schema_only_table_regexes/postgres/schema.sql b/diesel_cli/tests/print_schema/print_schema_only_table_regexes/postgres/schema.sql new file mode 100644 index 000000000000..37d66071ac40 --- /dev/null +++ b/diesel_cli/tests/print_schema/print_schema_only_table_regexes/postgres/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE users1 (id SERIAL PRIMARY KEY); +CREATE TABLE users2 (id SERIAL PRIMARY KEY); diff --git a/diesel_cli/tests/print_schema/print_schema_only_table_regexes/sqlite/expected.rs b/diesel_cli/tests/print_schema/print_schema_only_table_regexes/sqlite/expected.rs new file mode 100644 index 000000000000..5fabf42032c6 --- /dev/null +++ b/diesel_cli/tests/print_schema/print_schema_only_table_regexes/sqlite/expected.rs @@ -0,0 +1,13 @@ +table! { + /// Representation of the `users1` table. + /// + /// (Automatically generated by Diesel.) + users1 (id) { + /// The `id` column of the `users1` table. + /// + /// Its SQL type is `Nullable`. + /// + /// (Automatically generated by Diesel.) + id -> Nullable, + } +} diff --git a/diesel_cli/tests/print_schema/print_schema_only_table_regexes/sqlite/schema.sql b/diesel_cli/tests/print_schema/print_schema_only_table_regexes/sqlite/schema.sql new file mode 100644 index 000000000000..556e9f7b54e8 --- /dev/null +++ b/diesel_cli/tests/print_schema/print_schema_only_table_regexes/sqlite/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE users1 (id INTEGER PRIMARY KEY); +CREATE TABLE users2 (id INTEGER PRIMARY KEY);