diff --git a/CHANGELOG.md b/CHANGELOG.md index b5e1263bc6..52b3fd5d15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 .fetch_all(&mut conn).await?; ``` +- [[#940]] Rename the `#[sqlx(rename)]` attribute used to specify the type name on the database + side to `#[sqlx(type_name)]` [[@jplatte]]. + ## 0.4.2 - 2020-12-19 - [[#908]] Fix `whoami` crash on FreeBSD platform [[@fundon]] [[@AldaronLau]] diff --git a/sqlx-core/src/postgres/types/mod.rs b/sqlx-core/src/postgres/types/mod.rs index dff2ba2d3c..9ed490963f 100644 --- a/sqlx-core/src/postgres/types/mod.rs +++ b/sqlx-core/src/postgres/types/mod.rs @@ -117,7 +117,7 @@ //! //! ```rust,ignore //! #[derive(sqlx::Type)] -//! #[sqlx(rename = "inventory_item")] +//! #[sqlx(type_name = "inventory_item")] //! struct InventoryItem { //! name: String, //! supplier_id: i32, @@ -142,7 +142,7 @@ //! //! ```rust,ignore //! #[derive(sqlx::Type)] -//! #[sqlx(rename = "mood", rename_all = "lowercase")] +//! #[sqlx(type_name = "mood", rename_all = "lowercase")] //! enum Mood { Sad, Ok, Happy } //! ``` //! diff --git a/sqlx-core/src/types/mod.rs b/sqlx-core/src/types/mod.rs index cf1e356353..fe153fe803 100644 --- a/sqlx-core/src/types/mod.rs +++ b/sqlx-core/src/types/mod.rs @@ -108,11 +108,11 @@ pub use json::Json; /// /// ##### Attributes /// -/// * `#[sqlx(rename = "")]` on struct definition: instead of inferring the SQL type name from the inner -/// field (in the above case, `BIGINT`), explicitly set it to `` instead. May trigger -/// errors or unexpected behavior if the encoding of the given type is different than that of the -/// inferred type (e.g. if you rename the above to `VARCHAR`). -/// Affects Postgres only. +/// * `#[sqlx(type_name = "")]` on struct definition: instead of inferring the SQL +/// type name from the inner field (in the above case, `BIGINT`), explicitly set it to +/// `` instead. May trigger errors or unexpected behavior if the encoding of the +/// given type is different than that of the inferred type (e.g. if you rename the above to +/// `VARCHAR`). Affects Postgres only. /// /// ### Enumeration /// @@ -131,7 +131,7 @@ pub use json::Json; /// /// ```rust,ignore /// #[derive(sqlx::Type)] -/// #[sqlx(rename = "color")] // only for PostgreSQL to match a type definition +/// #[sqlx(type_name = "color")] // only for PostgreSQL to match a type definition /// #[sqlx(rename_all = "lowercase")] /// enum Color { Red, Green, Blue } /// ``` @@ -144,7 +144,7 @@ pub use json::Json; /// /// ```rust,ignore /// #[derive(sqlx::Type)] -/// #[sqlx(rename = "interface_type")] +/// #[sqlx(type_name = "interface_type")] /// struct InterfaceType { /// name: String, /// supplier_id: i32, diff --git a/sqlx-macros/src/derives/attributes.rs b/sqlx-macros/src/derives/attributes.rs index 373feaae98..ba1b382b06 100644 --- a/sqlx-macros/src/derives/attributes.rs +++ b/sqlx-macros/src/derives/attributes.rs @@ -1,5 +1,7 @@ -use proc_macro2::Ident; +use proc_macro2::{Ident, Span, TokenStream}; +use quote::{quote, quote_spanned}; use syn::punctuated::Punctuated; +use syn::spanned::Spanned; use syn::token::Comma; use syn::{Attribute, DeriveInput, Field, Lit, Meta, MetaNameValue, NestedMeta, Variant}; @@ -26,6 +28,27 @@ macro_rules! try_set { }; } +pub struct TypeName { + pub val: String, + pub span: Span, + /// Whether the old sqlx(rename) syntax was used instead of sqlx(type_name) + pub deprecated_rename: bool, +} + +impl TypeName { + pub fn get(&self) -> TokenStream { + let val = &self.val; + if self.deprecated_rename { + quote_spanned!(self.span=> { + sqlx::_rename(); + #val + }) + } else { + quote! { #val } + } + } +} + #[derive(Copy, Clone)] pub enum RenameAll { LowerCase, @@ -39,7 +62,7 @@ pub enum RenameAll { pub struct SqlxContainerAttributes { pub transparent: bool, - pub rename: Option, + pub type_name: Option, pub rename_all: Option, pub repr: Option, } @@ -52,10 +75,13 @@ pub struct SqlxChildAttributes { pub fn parse_container_attributes(input: &[Attribute]) -> syn::Result { let mut transparent = None; let mut repr = None; - let mut rename = None; + let mut type_name = None; let mut rename_all = None; - for attr in input.iter().filter(|a| a.path.is_ident("sqlx") || a.path.is_ident("repr")) { + for attr in input + .iter() + .filter(|a| a.path.is_ident("sqlx") || a.path.is_ident("repr")) + { let meta = attr .parse_meta() .map_err(|e| syn::Error::new_spanned(attr, e))?; @@ -91,7 +117,33 @@ pub fn parse_container_attributes(input: &[Attribute]) -> syn::Result try_set!(rename, val.value(), value), + }) if path.is_ident("type_name") => { + try_set!( + type_name, + TypeName { + val: val.value(), + span: value.span(), + deprecated_rename: false + }, + value + ) + } + + Meta::NameValue(MetaNameValue { + path, + lit: Lit::Str(val), + .. + }) if path.is_ident("rename") => { + try_set!( + type_name, + TypeName { + val: val.value(), + span: value.span(), + deprecated_rename: true + }, + value + ) + } u => fail!(u, "unexpected attribute"), }, @@ -117,7 +169,7 @@ pub fn parse_container_attributes(input: &[Attribute]) -> syn::Result for #ident #ty_generics { @@ -142,7 +145,10 @@ fn expand_derive_has_sql_type_strong_enum( } if cfg!(feature = "postgres") { - let ty_name = attributes.rename.unwrap_or_else(|| ident.to_string()); + let ty_name = attributes + .type_name + .map(|tn| tn.get()) + .unwrap_or_else(|| quote! { #ident }); tts.extend(quote!( impl sqlx::Type< sqlx::Postgres > for #ident { @@ -180,7 +186,10 @@ fn expand_derive_has_sql_type_struct( let mut tts = proc_macro2::TokenStream::new(); if cfg!(feature = "postgres") { - let ty_name = attributes.rename.unwrap_or_else(|| ident.to_string()); + let ty_name = attributes + .type_name + .map(|tn| tn.get()) + .unwrap_or_else(|| quote! { #ident }); tts.extend(quote!( impl sqlx::Type< sqlx::Postgres > for #ident { diff --git a/src/lib.rs b/src/lib.rs index e2a404b074..e9d9b7ee8a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -150,3 +150,8 @@ pub mod prelude { pub use super::Statement; pub use super::Type; } + +#[doc(hidden)] +#[inline(always)] +#[deprecated = "`#[sqlx(rename = \"...\")]` is now `#[sqlx(type_name = \"...\")`"] +pub fn _rename() {} diff --git a/tests/postgres/derives.rs b/tests/postgres/derives.rs index c85ced0e62..8abdf5c761 100644 --- a/tests/postgres/derives.rs +++ b/tests/postgres/derives.rs @@ -21,7 +21,7 @@ enum Weak { // "Strong" enums can map to TEXT (25) #[derive(PartialEq, Debug, sqlx::Type)] -#[sqlx(rename = "text")] +#[sqlx(type_name = "text")] #[sqlx(rename_all = "lowercase")] enum Strong { One, @@ -33,7 +33,7 @@ enum Strong { // rename_all variants #[derive(PartialEq, Debug, sqlx::Type)] -#[sqlx(rename = "color_lower")] +#[sqlx(type_name = "color_lower")] #[sqlx(rename_all = "lowercase")] enum ColorLower { Red, @@ -42,7 +42,7 @@ enum ColorLower { } #[derive(PartialEq, Debug, sqlx::Type)] -#[sqlx(rename = "color_snake")] +#[sqlx(type_name = "color_snake")] #[sqlx(rename_all = "snake_case")] enum ColorSnake { RedGreen, @@ -50,7 +50,7 @@ enum ColorSnake { } #[derive(PartialEq, Debug, sqlx::Type)] -#[sqlx(rename = "color_upper")] +#[sqlx(type_name = "color_upper")] #[sqlx(rename_all = "UPPERCASE")] enum ColorUpper { Red, @@ -59,7 +59,7 @@ enum ColorUpper { } #[derive(PartialEq, Debug, sqlx::Type)] -#[sqlx(rename = "color_screaming_snake")] +#[sqlx(type_name = "color_screaming_snake")] #[sqlx(rename_all = "SCREAMING_SNAKE_CASE")] enum ColorScreamingSnake { RedGreen, @@ -67,7 +67,7 @@ enum ColorScreamingSnake { } #[derive(PartialEq, Debug, sqlx::Type)] -#[sqlx(rename = "color_kebab_case")] +#[sqlx(type_name = "color_kebab_case")] #[sqlx(rename_all = "kebab-case")] enum ColorKebabCase { RedGreen, @@ -75,7 +75,7 @@ enum ColorKebabCase { } #[derive(PartialEq, Debug, sqlx::Type)] -#[sqlx(rename = "color_mixed_case")] +#[sqlx(type_name = "color_mixed_case")] #[sqlx(rename_all = "camelCase")] enum ColorCamelCase { RedGreen, @@ -83,7 +83,7 @@ enum ColorCamelCase { } #[derive(PartialEq, Debug, sqlx::Type)] -#[sqlx(rename = "color_camel_case")] +#[sqlx(type_name = "color_camel_case")] #[sqlx(rename_all = "PascalCase")] enum ColorPascalCase { RedGreen, @@ -92,7 +92,7 @@ enum ColorPascalCase { // "Strong" enum can map to a custom type #[derive(PartialEq, Debug, sqlx::Type)] -#[sqlx(rename = "mood")] +#[sqlx(type_name = "mood")] #[sqlx(rename_all = "lowercase")] enum Mood { Ok, @@ -103,7 +103,7 @@ enum Mood { // Records must map to a custom type // Note that all types are types in Postgres #[derive(PartialEq, Debug, sqlx::Type)] -#[sqlx(rename = "inventory_item")] +#[sqlx(type_name = "inventory_item")] struct InventoryItem { name: String, supplier_id: Option, @@ -112,12 +112,12 @@ struct InventoryItem { // Custom range type #[derive(sqlx::Type, Debug, PartialEq)] -#[sqlx(rename = "float_range")] +#[sqlx(type_name = "float_range")] struct FloatRange(PgRange); // Custom domain type #[derive(sqlx::Type, Debug)] -#[sqlx(rename = "int4rangeL0pC")] +#[sqlx(type_name = "int4rangeL0pC")] struct RangeInclusive(PgRange); test_type!(transparent(Postgres, diff --git a/tests/ui/postgres/deprecated_rename.rs b/tests/ui/postgres/deprecated_rename.rs new file mode 100644 index 0000000000..bcedf3fb1b --- /dev/null +++ b/tests/ui/postgres/deprecated_rename.rs @@ -0,0 +1,11 @@ +#[derive(sqlx::Type)] +#[sqlx(rename = "foo")] +enum Foo { + One, + Two, + Three, +} + +fn main() { + compile_error!("trybuild test needs to fail for stderr checking"); +} diff --git a/tests/ui/postgres/deprecated_rename.stderr b/tests/ui/postgres/deprecated_rename.stderr new file mode 100644 index 0000000000..df9ba2f018 --- /dev/null +++ b/tests/ui/postgres/deprecated_rename.stderr @@ -0,0 +1,13 @@ +error: trybuild test needs to fail for stderr checking + --> $DIR/deprecated_rename.rs:10:5 + | +10 | compile_error!("trybuild test needs to fail for stderr checking"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated function `sqlx::_rename`: `#[sqlx(rename = "...")]` is now `#[sqlx(type_name = "...")` + --> $DIR/deprecated_rename.rs:2:8 + | +2 | #[sqlx(rename = "foo")] + | ^^^^^^ + | + = note: `#[warn(deprecated)]` on by default diff --git a/tests/ui/postgres/gated/chrono.stderr b/tests/ui/postgres/gated/chrono.stderr index c6f42af448..51c0d30156 100644 --- a/tests/ui/postgres/gated/chrono.stderr +++ b/tests/ui/postgres/gated/chrono.stderr @@ -1,4 +1,4 @@ -error: optional feature `chrono` required for type DATE of column #1 ("now") +error: optional feature `time` required for type DATE of column #1 ("now") --> $DIR/chrono.rs:2:13 | 2 | let _ = sqlx::query!("select now()::date"); @@ -6,7 +6,7 @@ error: optional feature `chrono` required for type DATE of column #1 ("now") | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: optional feature `chrono` required for type TIME of column #1 ("now") +error: optional feature `time` required for type TIME of column #1 ("now") --> $DIR/chrono.rs:4:13 | 4 | let _ = sqlx::query!("select now()::time"); @@ -14,7 +14,7 @@ error: optional feature `chrono` required for type TIME of column #1 ("now") | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: optional feature `chrono` required for type TIMESTAMP of column #1 ("now") +error: optional feature `time` required for type TIMESTAMP of column #1 ("now") --> $DIR/chrono.rs:6:13 | 6 | let _ = sqlx::query!("select now()::timestamp"); @@ -22,7 +22,7 @@ error: optional feature `chrono` required for type TIMESTAMP of column #1 ("now" | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: optional feature `chrono` required for type TIMESTAMPTZ of column #1 ("now") +error: optional feature `time` required for type TIMESTAMPTZ of column #1 ("now") --> $DIR/chrono.rs:8:13 | 8 | let _ = sqlx::query!("select now()::timestamptz"); @@ -30,7 +30,7 @@ error: optional feature `chrono` required for type TIMESTAMPTZ of column #1 ("no | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: optional feature `chrono` required for type DATE of param #1 +error: optional feature `time` required for type DATE of param #1 --> $DIR/chrono.rs:10:13 | 10 | let _ = sqlx::query!("select $1::date", ()); @@ -38,7 +38,7 @@ error: optional feature `chrono` required for type DATE of param #1 | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: optional feature `chrono` required for type TIME of param #1 +error: optional feature `time` required for type TIME of param #1 --> $DIR/chrono.rs:12:13 | 12 | let _ = sqlx::query!("select $1::time", ()); @@ -46,7 +46,7 @@ error: optional feature `chrono` required for type TIME of param #1 | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: optional feature `chrono` required for type TIMESTAMP of param #1 +error: optional feature `time` required for type TIMESTAMP of param #1 --> $DIR/chrono.rs:14:13 | 14 | let _ = sqlx::query!("select $1::timestamp", ()); @@ -54,7 +54,7 @@ error: optional feature `chrono` required for type TIMESTAMP of param #1 | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: optional feature `chrono` required for type TIMESTAMPTZ of param #1 +error: optional feature `time` required for type TIMESTAMPTZ of param #1 --> $DIR/chrono.rs:16:13 | 16 | let _ = sqlx::query!("select $1::timestamptz", ()); diff --git a/tests/ui/postgres/issue_30.stderr b/tests/ui/postgres/issue_30.stderr index 8ed7261a19..66dd2030e7 100644 --- a/tests/ui/postgres/issue_30.stderr +++ b/tests/ui/postgres/issue_30.stderr @@ -1,4 +1,4 @@ -error: "\'1" is not a valid Rust identifier +error: column name "\'1" is invalid: "\'1" is not a valid Rust identifier --> $DIR/issue_30.rs:2:17 | 2 | let query = sqlx::query!("select 1 as \"'1\""); diff --git a/tests/ui/postgres/wrong_param_type.stderr b/tests/ui/postgres/wrong_param_type.stderr index 706dbd3d77..50274e1213 100644 --- a/tests/ui/postgres/wrong_param_type.stderr +++ b/tests/ui/postgres/wrong_param_type.stderr @@ -1,55 +1,47 @@ error[E0308]: mismatched types - --> $DIR/wrong_param_type.rs:2:18 + --> $DIR/wrong_param_type.rs:2:50 | 2 | let _query = sqlx::query!("select $1::text", 0i32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&str`, found `i32` - | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^^^ expected `&str`, found `i32` error[E0308]: mismatched types - --> $DIR/wrong_param_type.rs:4:18 + --> $DIR/wrong_param_type.rs:4:50 | 4 | let _query = sqlx::query!("select $1::text", &0i32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `str`, found `i32` + | ^ expected `str`, found `i32` | = note: expected reference `&str` found reference `&i32` - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types - --> $DIR/wrong_param_type.rs:6:18 + --> $DIR/wrong_param_type.rs:6:50 | 6 | let _query = sqlx::query!("select $1::text", Some(0i32)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&str`, found `i32` + | ^^^^ expected `&str`, found `i32` | - = note: expected enum `std::option::Option<&str>` - found enum `std::option::Option` - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: expected enum `Option<&str>` + found enum `Option` error[E0308]: mismatched types - --> $DIR/wrong_param_type.rs:9:18 + --> $DIR/wrong_param_type.rs:9:50 | 9 | let _query = sqlx::query!("select $1::text", arg); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&str`, found `i32` - | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^^ expected `&str`, found `i32` error[E0308]: mismatched types - --> $DIR/wrong_param_type.rs:12:18 + --> $DIR/wrong_param_type.rs:12:50 | 12 | let _query = sqlx::query!("select $1::text", arg); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&str`, found `i32` + | ^^^ expected `&str`, found `i32` | - = note: expected enum `std::option::Option<&str>` - found enum `std::option::Option` - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: expected enum `Option<&str>` + found enum `Option` error[E0308]: mismatched types - --> $DIR/wrong_param_type.rs:13:18 + --> $DIR/wrong_param_type.rs:13:50 | 13 | let _query = sqlx::query!("select $1::text", arg.as_ref()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `str`, found `i32` + | ^^^ expected `str`, found `i32` | - = note: expected enum `std::option::Option<&str>` - found enum `std::option::Option<&i32>` - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: expected enum `Option<&str>` + found enum `Option<&i32>`