Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a way to skip generating some sql type definitions #4002

Merged
merged 16 commits into from
May 3, 2024
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Increasing the minimal supported Rust version will always be coupled at least wi

### Added

* Support `[print_schema] exclude_custom_type_definitions=["Vector"]`. If a `custom type` matches one element on the list it's skipped.
* Added automatic usage of all sqlite `rowid` aliases when no explicit primary key is defined for `print-schema`
* Added a `#[dsl::auto_type]` attribute macro, allowing to infer type of query fragment functions
* Added the same type inference on `Selectable` derives, which allows skipping specifying `select_expression_type` most of the time, in turn enabling most queries to be written using just a `Selectable` derive.
Expand Down
22 changes: 15 additions & 7 deletions diesel_cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,14 @@ pub fn build_cli() -> Command {
.action(ArgAction::Append)
.help("Generate SQL type definitions for types not provided by diesel"),
)
.arg(
Arg::new("except-custom-type-definitions")
.action(ArgAction::Append)
.long("except-custom-type-definitions")
.num_args(1..)
.action(ArgAction::Append)
.help("A list of regexes to filter the custom types definitions generated")
)
.arg(
Arg::new("custom-type-derives")
.long("custom-type-derives")
Expand All @@ -322,15 +330,15 @@ pub fn build_cli() -> Command {
.default_values(["default"])
.help("select schema key from diesel.toml, use 'default' for print_schema without key."),
).arg(
position_sensitive_flag(Arg::new("sqlite-integer-primary-key-is-bigint"))
.long("sqlite-integer-primary-key-is-bigint")
.action(ArgAction::Append)
.help(
"For SQLite 3.37 and above, detect `INTEGER PRIMARY KEY` columns as `BigInt`, \
position_sensitive_flag(Arg::new("sqlite-integer-primary-key-is-bigint"))
.long("sqlite-integer-primary-key-is-bigint")
.action(ArgAction::Append)
.help(
"For SQLite 3.37 and above, detect `INTEGER PRIMARY KEY` columns as `BigInt`, \
when the table isn't declared with `WITHOUT ROWID`.\n\
See https://www.sqlite.org/lang_createtable.html#rowid for more information."
),
);
),
);

let config_arg = Arg::new("CONFIG_FILE")
.value_parser(clap::value_parser!(std::path::PathBuf))
Expand Down
30 changes: 27 additions & 3 deletions diesel_cli/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,12 @@ impl Config {
matches,
"sqlite-integer-primary-key-is-bigint",
)?;
let except_custom_type_definitions_with_indices =
get_values_with_indices::<Vec<Regex>>(
matches,
"except-custom-type-definitions",
)?;

for (key, boundary) in selected_schema_keys.values().cloned().zip(
selected_schema_keys
.keys()
Expand Down Expand Up @@ -239,7 +245,7 @@ impl Config {
_ => {
return Err(crate::errors::Error::UnsupportedFeature(format!(
"Invalid column sorting mode: {sorting}"
)))
)));
}
}
}
Expand Down Expand Up @@ -272,6 +278,14 @@ impl Config {
print_schema.generate_missing_sql_type_definitions = Some(false)
}

if let Some(except_rules) = &except_custom_type_definitions_with_indices {
if let Some(rules) = except_rules.range(boundary).nth(0) {
print_schema
.except_custom_type_definitions
.clone_from(rules.1);
}
}

let custom_type_derives = custom_type_derives_with_indices
.clone()
.map(|v| v.range(boundary).map(|v| v.1.clone()).collect())
Expand Down Expand Up @@ -317,7 +331,7 @@ impl Config {
_ => {
return Err(crate::errors::Error::UnsupportedFeature(format!(
"Invalid column sorting mode: {sorting}"
)))
)));
}
}
}
Expand All @@ -331,6 +345,14 @@ impl Config {
config.import_types = Some(types);
}

if let Some(except_rules) = matches.get_many("except-custom-type-definitions") {
let regexes: Vec<String> = except_rules.cloned().collect();
config.except_custom_type_definitions = regexes
.into_iter()
.map(|x| regex::Regex::new(&x).map(Into::into))
.collect::<Result<Vec<Regex>, _>>()?;
}

if matches.get_flag("generate-custom-type-definitions") {
config.generate_missing_sql_type_definitions = Some(false);
}
Expand Down Expand Up @@ -415,6 +437,8 @@ pub struct PrintSchema {
#[serde(default)]
pub generate_missing_sql_type_definitions: Option<bool>,
#[serde(default)]
pub except_custom_type_definitions: Vec<Regex>,
#[serde(default)]
pub custom_type_derives: Option<Vec<String>>,
#[serde(default)]
pub sqlite_integer_primary_key_is_bigint: Option<bool>,
Expand Down Expand Up @@ -568,7 +592,7 @@ impl<'de> Deserialize<'de> for Filtering {
return Err(de::Error::unknown_field(
&key,
&["only_tables", "except_tables"],
))
));
}
}
}
Expand Down
7 changes: 7 additions & 0 deletions diesel_cli/src/print_schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,13 @@ pub fn output_schema(
.map(|c| {
Some(&c.ty)
.filter(|ty| !diesel_provided_types.contains(ty.rust_name.as_str()))
// Skip types that are that match the regexes in the configuration
.filter(|ty| {
!config
.except_custom_type_definitions
.iter()
.any(|rx| rx.is_match(ty.rust_name.as_str()))
})
.map(|ty| match backend {
#[cfg(feature = "postgres")]
Backend::Pg => ty.clone(),
Expand Down
9 changes: 9 additions & 0 deletions diesel_cli/tests/print_schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ fn run_infer_schema_without_docs() {
test_print_schema("print_schema_simple_without_docs", vec![]);
}

#[test]
#[cfg(feature = "postgres")]
fn run_except_custom_type_definitions() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is run for all backends but it only contains files for postgresql. That's the reason it is failing for SQLite. There are two options to fix this:

  • Add the relevant test files for the other backends (SQLite, MySQL)
  • add a #[cfg(feature = "postgres")] to the test function to mark this test as postgres only

test_print_schema(
"print_schema_except_custom_type_definitions",
vec!["--except-custom-type-definitions", "MyType2"],
);
}

#[test]
fn run_infer_schema() {
test_print_schema("print_schema_simple", vec!["--with-docs"]);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[print_schema]
file = "src/schema.rs"
except_custom_type_definitions = ["MyType2"]
custom_type_derives = ["diesel::query_builder::QueryId", "Clone"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
source: diesel_cli/tests/print_schema.rs
description: "Test: print_schema_except_custom_type_definitions"
---
// @generated automatically by Diesel CLI.

pub mod sql_types {
#[derive(diesel::query_builder::QueryId, Clone, diesel::sql_types::SqlType)]
#[diesel(postgres_type(name = "my_type"))]
pub struct MyType;
}

diesel::table! {
use diesel::sql_types::*;
use super::sql_types::MyType;

custom_types (id) {
id -> Int4,
custom_enum -> MyType,
custom_enum_nullable -> Nullable<MyType>,
custom_enum2 -> MyType2,
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CREATE TYPE my_type AS ENUM ('foo', 'bar');
CREATE TYPE my_type2 AS ENUM ('foo', 'bar');
CREATE TABLE custom_types (
id SERIAL PRIMARY KEY,
custom_enum my_type NOT NULL,
custom_enum_nullable my_type,
custom_enum2 my_type2 NOT NULL
);
Loading