From d885624003078e1a7b6bb7123a9128c06f8d12fb Mon Sep 17 00:00:00 2001 From: Federico Rampazzo Date: Fri, 27 Nov 2020 16:55:32 +0000 Subject: [PATCH 1/7] Add mixedCase and CamelCase to rename-all, added rename-all to FromRow --- sqlx-macros/src/derives/attributes.rs | 5 +- sqlx-macros/src/derives/mod.rs | 5 +- sqlx-macros/src/derives/row.rs | 18 ++++-- tests/postgres/derives.rs | 82 +++++++++++++++++++++++++-- 4 files changed, 99 insertions(+), 11 deletions(-) diff --git a/sqlx-macros/src/derives/attributes.rs b/sqlx-macros/src/derives/attributes.rs index 40412e98a9..dad7ec7ab6 100644 --- a/sqlx-macros/src/derives/attributes.rs +++ b/sqlx-macros/src/derives/attributes.rs @@ -33,6 +33,8 @@ pub enum RenameAll { UpperCase, ScreamingSnakeCase, KebabCase, + MixedCase, + CamelCase, } pub struct SqlxContainerAttributes { @@ -77,7 +79,8 @@ pub fn parse_container_attributes(input: &[Attribute]) -> syn::Result RenameAll::UpperCase, "SCREAMING_SNAKE_CASE" => RenameAll::ScreamingSnakeCase, "kebab-case" => RenameAll::KebabCase, - + "mixedCase" => RenameAll::MixedCase, + "CamelCase" => RenameAll::CamelCase, _ => fail!(meta, "unexpected value for rename_all"), }; diff --git a/sqlx-macros/src/derives/mod.rs b/sqlx-macros/src/derives/mod.rs index 0785c894f6..994f826e93 100644 --- a/sqlx-macros/src/derives/mod.rs +++ b/sqlx-macros/src/derives/mod.rs @@ -10,7 +10,7 @@ pub(crate) use r#type::expand_derive_type; pub(crate) use row::expand_derive_from_row; use self::attributes::RenameAll; -use heck::{KebabCase, ShoutySnakeCase, SnakeCase}; +use heck::{KebabCase, ShoutySnakeCase, SnakeCase, CamelCase, MixedCase}; use std::iter::FromIterator; use syn::DeriveInput; @@ -35,5 +35,8 @@ pub(crate) fn rename_all(s: &str, pattern: RenameAll) -> String { RenameAll::UpperCase => s.to_uppercase(), RenameAll::ScreamingSnakeCase => s.to_shouty_snake_case(), RenameAll::KebabCase => s.to_kebab_case(), + RenameAll::MixedCase => s.to_mixed_case(), + RenameAll::CamelCase => s.to_camel_case(), + } } diff --git a/sqlx-macros/src/derives/row.rs b/sqlx-macros/src/derives/row.rs index 2409c7fbfe..90d177858e 100644 --- a/sqlx-macros/src/derives/row.rs +++ b/sqlx-macros/src/derives/row.rs @@ -5,7 +5,7 @@ use syn::{ Fields, FieldsNamed, FieldsUnnamed, Lifetime, Stmt, }; -use super::attributes::parse_child_attributes; +use super::{attributes::{parse_child_attributes, parse_container_attributes}, rename_all}; pub fn expand_derive_from_row(input: &DeriveInput) -> syn::Result { match &input.data { @@ -69,13 +69,21 @@ fn expand_derive_from_row_struct( let (impl_generics, _, where_clause) = generics.split_for_impl(); + let container_attributes = parse_container_attributes(&input.attrs)?; + let reads = fields.iter().filter_map(|field| -> Option { + + let id = &field.ident.as_ref()?; let attributes = parse_child_attributes(&field.attrs).unwrap(); - let id_s = match attributes.rename { - Some(rename) => rename, - None => id.to_string().trim_start_matches("r#").to_owned(), - }; + let id_s = attributes.rename + .or_else(|| Some(id.to_string().trim_start_matches("r#").to_owned())) + .map(|s| match container_attributes.rename_all { + Some(pattern) => rename_all(&s, pattern), + None => s + }) + .unwrap(); + let ty = &field.ty; if attributes.default { diff --git a/tests/postgres/derives.rs b/tests/postgres/derives.rs index a218db3efe..199d89a9cf 100644 --- a/tests/postgres/derives.rs +++ b/tests/postgres/derives.rs @@ -67,13 +67,29 @@ enum ColorScreamingSnake { } #[derive(PartialEq, Debug, sqlx::Type)] -#[sqlx(rename = "color-kebab-case")] +#[sqlx(rename = "color_kebab_case")] #[sqlx(rename_all = "kebab-case")] enum ColorKebabCase { RedGreen, BlueBlack, } +#[derive(PartialEq, Debug, sqlx::Type)] +#[sqlx(rename = "color_mixed_case")] +#[sqlx(rename_all = "mixedCase")] +enum ColorMixedCase { + RedGreen, + BlueBlack, +} + +#[derive(PartialEq, Debug, sqlx::Type)] +#[sqlx(rename = "color_camel_case")] +#[sqlx(rename_all = "CamelCase")] +enum ColorCamelCase { + RedGreen, + BlueBlack, +} + // "Strong" enum can map to a custom type #[derive(PartialEq, Debug, sqlx::Type)] #[sqlx(rename = "mood")] @@ -141,13 +157,19 @@ DROP TYPE IF EXISTS color_lower CASCADE; DROP TYPE IF EXISTS color_snake CASCADE; DROP TYPE IF EXISTS color_upper CASCADE; DROP TYPE IF EXISTS color_screaming_snake CASCADE; -DROP TYPE IF EXISTS "color-kebab-case" CASCADE; +DROP TYPE IF EXISTS color_kebab_case CASCADE; +DROP TYPE IF EXISTS color_mixed_case CASCADE; +DROP TYPE IF EXISTS color_camel_case CASCADE; + CREATE TYPE color_lower AS ENUM ( 'red', 'green', 'blue' ); CREATE TYPE color_snake AS ENUM ( 'red_green', 'blue_black' ); CREATE TYPE color_upper AS ENUM ( 'RED', 'GREEN', 'BLUE' ); CREATE TYPE color_screaming_snake AS ENUM ( 'RED_GREEN', 'BLUE_BLACK' ); -CREATE TYPE "color-kebab-case" AS ENUM ( 'red-green', 'blue-black' ); +CREATE TYPE color_kebab_case" AS ENUM ( 'red-green', 'blue-black' ); +CREATE TYPE color_mixed_case AS ENUM ( 'redGreen', 'blueBlack' ); +CREATE TYPE color_camel_case AS ENUM ( 'RedGreen', 'BlueBlack' ); + CREATE TABLE people ( id serial PRIMARY KEY, @@ -276,7 +298,7 @@ SELECT id, mood FROM people WHERE id = $1 let rec: (bool, ColorKebabCase) = sqlx::query_as( " - SELECT $1 = 'red-green'::\"color-kebab-case\", $1 + SELECT $1 = 'red-green'::color_kebab_case, $1 ", ) .bind(&ColorKebabCase::RedGreen) @@ -286,6 +308,30 @@ SELECT id, mood FROM people WHERE id = $1 assert!(rec.0); assert_eq!(rec.1, ColorKebabCase::RedGreen); + let rec: (bool, ColorMixedCase) = sqlx::query_as( + " + SELECT $1 = 'redGreen'::color_mixed_case, $1 + ", + ) + .bind(&ColorMixedCase::RedGreen) + .fetch_one(&mut conn) + .await?; + + assert!(rec.0); + assert_eq!(rec.1, ColorMixedCase::RedGreen); + + let rec: (bool, ColorCamelCase) = sqlx::query_as( + " + SELECT $1 = 'RedGreen'::color_camel_case, $1 + ", + ) + .bind(&ColorCamelCase::RedGreen) + .fetch_one(&mut conn) + .await?; + + assert!(rec.0); + assert_eq!(rec.1, ColorCamelCase::RedGreen); + Ok(()) } @@ -426,6 +472,34 @@ async fn test_from_row_with_rename() -> anyhow::Result<()> { Ok(()) } +#[cfg(feature = "macros")] +#[sqlx_macros::test] +async fn test_from_row_with_rename_all() -> anyhow::Result<()> { + #[derive(Debug, sqlx::FromRow)] + #[sqlx(rename_all = "mixedCase")] + struct AccountKeyword { + user_id: i32, + user_name: String, + user_surname: String, + } + + let mut conn = new::().await?; + + let account: AccountKeyword = sqlx::query_as( + r#"SELECT * from (VALUES (1, 'foo', 'bar')) accounts(userId, userName, userSurname)"# + ) + .fetch_one(&mut conn) + .await?; + println!("{:?}", account); + + assert_eq!(1, account.user_id); + assert_eq!("foo", account.user_name); + assert_eq!("bar8", account.user_surname); + + + Ok(()) +} + #[cfg(feature = "macros")] #[sqlx_macros::test] async fn test_from_row_tuple() -> anyhow::Result<()> { From 30882ef1072d1868b614a0f4b170fbb5eaf6fc2b Mon Sep 17 00:00:00 2001 From: Federico Rampazzo Date: Sat, 28 Nov 2020 00:55:50 +0000 Subject: [PATCH 2/7] Updated rename-all docs --- sqlx-core/src/from_row.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sqlx-core/src/from_row.rs b/sqlx-core/src/from_row.rs index 2c2ce3a702..08d0be3be1 100644 --- a/sqlx-core/src/from_row.rs +++ b/sqlx-core/src/from_row.rs @@ -53,7 +53,7 @@ use crate::row::Row; /// /// ```rust,ignore /// #[derive(sqlx::FromRow)] -/// #[sqlx(rename_all = "camelCase")] +/// #[sqlx(rename_all = "mixedCase")] /// struct UserPost { /// id: i32, /// // remapped to "userId" @@ -63,7 +63,7 @@ use crate::row::Row; /// ``` /// /// The supported values are `snake_case` (available if you have non-snake-case field names for some -/// reason), `lowercase`, `UPPERCASE`, `camelCase`, `SCREAMING_SNAKE_CASE` and `kebab-case`. +/// reason), `lowercase`, `UPPERCASE`, `mixedCase`, `CamelCase`, `SCREAMING_SNAKE_CASE` and `kebab-case`. /// The styling of each option is intended to be an example of its behavior. /// /// #### `default` From f70d3bfe4f27f49537f9bd5aba22de44a5810073 Mon Sep 17 00:00:00 2001 From: Federico Rampazzo Date: Sat, 28 Nov 2020 01:01:45 +0000 Subject: [PATCH 3/7] Rename mixedCase to camelCase, CamelCase to PascalCase, aligning with serde --- sqlx-core/src/from_row.rs | 4 ++-- sqlx-macros/src/derives/attributes.rs | 6 +++--- sqlx-macros/src/derives/mod.rs | 4 ++-- tests/postgres/derives.rs | 22 +++++++++++----------- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/sqlx-core/src/from_row.rs b/sqlx-core/src/from_row.rs index 08d0be3be1..ef934ea37a 100644 --- a/sqlx-core/src/from_row.rs +++ b/sqlx-core/src/from_row.rs @@ -53,7 +53,7 @@ use crate::row::Row; /// /// ```rust,ignore /// #[derive(sqlx::FromRow)] -/// #[sqlx(rename_all = "mixedCase")] +/// #[sqlx(rename_all = "camelCase")] /// struct UserPost { /// id: i32, /// // remapped to "userId" @@ -63,7 +63,7 @@ use crate::row::Row; /// ``` /// /// The supported values are `snake_case` (available if you have non-snake-case field names for some -/// reason), `lowercase`, `UPPERCASE`, `mixedCase`, `CamelCase`, `SCREAMING_SNAKE_CASE` and `kebab-case`. +/// reason), `lowercase`, `UPPERCASE`, `camelCase`, `PascalCase`, `SCREAMING_SNAKE_CASE` and `kebab-case`. /// The styling of each option is intended to be an example of its behavior. /// /// #### `default` diff --git a/sqlx-macros/src/derives/attributes.rs b/sqlx-macros/src/derives/attributes.rs index dad7ec7ab6..ef38421f9b 100644 --- a/sqlx-macros/src/derives/attributes.rs +++ b/sqlx-macros/src/derives/attributes.rs @@ -33,8 +33,8 @@ pub enum RenameAll { UpperCase, ScreamingSnakeCase, KebabCase, - MixedCase, CamelCase, + PascalCase, } pub struct SqlxContainerAttributes { @@ -79,8 +79,8 @@ pub fn parse_container_attributes(input: &[Attribute]) -> syn::Result RenameAll::UpperCase, "SCREAMING_SNAKE_CASE" => RenameAll::ScreamingSnakeCase, "kebab-case" => RenameAll::KebabCase, - "mixedCase" => RenameAll::MixedCase, - "CamelCase" => RenameAll::CamelCase, + "camelCase" => RenameAll::CamelCase, + "PascalCase" => RenameAll::PascalCase, _ => fail!(meta, "unexpected value for rename_all"), }; diff --git a/sqlx-macros/src/derives/mod.rs b/sqlx-macros/src/derives/mod.rs index 994f826e93..238a2ff6ba 100644 --- a/sqlx-macros/src/derives/mod.rs +++ b/sqlx-macros/src/derives/mod.rs @@ -35,8 +35,8 @@ pub(crate) fn rename_all(s: &str, pattern: RenameAll) -> String { RenameAll::UpperCase => s.to_uppercase(), RenameAll::ScreamingSnakeCase => s.to_shouty_snake_case(), RenameAll::KebabCase => s.to_kebab_case(), - RenameAll::MixedCase => s.to_mixed_case(), - RenameAll::CamelCase => s.to_camel_case(), + RenameAll::CamelCase => s.to_mixed_case(), + RenameAll::PascalCase => s.to_camel_case(), } } diff --git a/tests/postgres/derives.rs b/tests/postgres/derives.rs index 199d89a9cf..1c69ab02df 100644 --- a/tests/postgres/derives.rs +++ b/tests/postgres/derives.rs @@ -76,16 +76,16 @@ enum ColorKebabCase { #[derive(PartialEq, Debug, sqlx::Type)] #[sqlx(rename = "color_mixed_case")] -#[sqlx(rename_all = "mixedCase")] -enum ColorMixedCase { +#[sqlx(rename_all = "camelCase")] +enum ColorCamelCase { RedGreen, BlueBlack, } #[derive(PartialEq, Debug, sqlx::Type)] #[sqlx(rename = "color_camel_case")] -#[sqlx(rename_all = "CamelCase")] -enum ColorCamelCase { +#[sqlx(rename_all = "PascalCase")] +enum ColorPascalCase { RedGreen, BlueBlack, } @@ -308,29 +308,29 @@ SELECT id, mood FROM people WHERE id = $1 assert!(rec.0); assert_eq!(rec.1, ColorKebabCase::RedGreen); - let rec: (bool, ColorMixedCase) = sqlx::query_as( + let rec: (bool, ColorCamelCase) = sqlx::query_as( " SELECT $1 = 'redGreen'::color_mixed_case, $1 ", ) - .bind(&ColorMixedCase::RedGreen) + .bind(&ColorCamelCase::RedGreen) .fetch_one(&mut conn) .await?; assert!(rec.0); - assert_eq!(rec.1, ColorMixedCase::RedGreen); + assert_eq!(rec.1, ColorCamelCase::RedGreen); - let rec: (bool, ColorCamelCase) = sqlx::query_as( + let rec: (bool, ColorPascalCase) = sqlx::query_as( " SELECT $1 = 'RedGreen'::color_camel_case, $1 ", ) - .bind(&ColorCamelCase::RedGreen) + .bind(&ColorPascalCase::RedGreen) .fetch_one(&mut conn) .await?; assert!(rec.0); - assert_eq!(rec.1, ColorCamelCase::RedGreen); + assert_eq!(rec.1, ColorPascalCase::RedGreen); Ok(()) } @@ -476,7 +476,7 @@ async fn test_from_row_with_rename() -> anyhow::Result<()> { #[sqlx_macros::test] async fn test_from_row_with_rename_all() -> anyhow::Result<()> { #[derive(Debug, sqlx::FromRow)] - #[sqlx(rename_all = "mixedCase")] + #[sqlx(rename_all = "camelCase")] struct AccountKeyword { user_id: i32, user_name: String, From 512b02ab08634be0cd7875c2431df6a808b39a46 Mon Sep 17 00:00:00 2001 From: Federico Rampazzo Date: Sat, 28 Nov 2020 01:09:18 +0000 Subject: [PATCH 4/7] Cargo fmt --- sqlx-macros/src/derives/mod.rs | 3 +-- sqlx-macros/src/derives/row.rs | 14 ++++++++------ tests/postgres/derives.rs | 3 +-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/sqlx-macros/src/derives/mod.rs b/sqlx-macros/src/derives/mod.rs index 238a2ff6ba..21eb88d6ec 100644 --- a/sqlx-macros/src/derives/mod.rs +++ b/sqlx-macros/src/derives/mod.rs @@ -10,7 +10,7 @@ pub(crate) use r#type::expand_derive_type; pub(crate) use row::expand_derive_from_row; use self::attributes::RenameAll; -use heck::{KebabCase, ShoutySnakeCase, SnakeCase, CamelCase, MixedCase}; +use heck::{CamelCase, KebabCase, MixedCase, ShoutySnakeCase, SnakeCase}; use std::iter::FromIterator; use syn::DeriveInput; @@ -37,6 +37,5 @@ pub(crate) fn rename_all(s: &str, pattern: RenameAll) -> String { RenameAll::KebabCase => s.to_kebab_case(), RenameAll::CamelCase => s.to_mixed_case(), RenameAll::PascalCase => s.to_camel_case(), - } } diff --git a/sqlx-macros/src/derives/row.rs b/sqlx-macros/src/derives/row.rs index 90d177858e..388dcc2d51 100644 --- a/sqlx-macros/src/derives/row.rs +++ b/sqlx-macros/src/derives/row.rs @@ -5,7 +5,10 @@ use syn::{ Fields, FieldsNamed, FieldsUnnamed, Lifetime, Stmt, }; -use super::{attributes::{parse_child_attributes, parse_container_attributes}, rename_all}; +use super::{ + attributes::{parse_child_attributes, parse_container_attributes}, + rename_all, +}; pub fn expand_derive_from_row(input: &DeriveInput) -> syn::Result { match &input.data { @@ -72,18 +75,17 @@ fn expand_derive_from_row_struct( let container_attributes = parse_container_attributes(&input.attrs)?; let reads = fields.iter().filter_map(|field| -> Option { - - let id = &field.ident.as_ref()?; let attributes = parse_child_attributes(&field.attrs).unwrap(); - let id_s = attributes.rename + let id_s = attributes + .rename .or_else(|| Some(id.to_string().trim_start_matches("r#").to_owned())) .map(|s| match container_attributes.rename_all { Some(pattern) => rename_all(&s, pattern), - None => s + None => s, }) .unwrap(); - + let ty = &field.ty; if attributes.default { diff --git a/tests/postgres/derives.rs b/tests/postgres/derives.rs index 1c69ab02df..ad798df2ec 100644 --- a/tests/postgres/derives.rs +++ b/tests/postgres/derives.rs @@ -486,7 +486,7 @@ async fn test_from_row_with_rename_all() -> anyhow::Result<()> { let mut conn = new::().await?; let account: AccountKeyword = sqlx::query_as( - r#"SELECT * from (VALUES (1, 'foo', 'bar')) accounts(userId, userName, userSurname)"# + r#"SELECT * from (VALUES (1, 'foo', 'bar')) accounts(userId, userName, userSurname)"#, ) .fetch_one(&mut conn) .await?; @@ -496,7 +496,6 @@ async fn test_from_row_with_rename_all() -> anyhow::Result<()> { assert_eq!("foo", account.user_name); assert_eq!("bar8", account.user_surname); - Ok(()) } From 81dbe001c1beea19e9ac2575dd8e1e1a37e92a24 Mon Sep 17 00:00:00 2001 From: Federico Rampazzo Date: Sat, 28 Nov 2020 02:11:46 +0000 Subject: [PATCH 5/7] Fix typo --- tests/postgres/derives.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/postgres/derives.rs b/tests/postgres/derives.rs index ad798df2ec..1bea0c96fa 100644 --- a/tests/postgres/derives.rs +++ b/tests/postgres/derives.rs @@ -166,7 +166,7 @@ CREATE TYPE color_lower AS ENUM ( 'red', 'green', 'blue' ); CREATE TYPE color_snake AS ENUM ( 'red_green', 'blue_black' ); CREATE TYPE color_upper AS ENUM ( 'RED', 'GREEN', 'BLUE' ); CREATE TYPE color_screaming_snake AS ENUM ( 'RED_GREEN', 'BLUE_BLACK' ); -CREATE TYPE color_kebab_case" AS ENUM ( 'red-green', 'blue-black' ); +CREATE TYPE color_kebab_case AS ENUM ( 'red-green', 'blue-black' ); CREATE TYPE color_mixed_case AS ENUM ( 'redGreen', 'blueBlack' ); CREATE TYPE color_camel_case AS ENUM ( 'RedGreen', 'BlueBlack' ); From 1137f81786c1d35577a4c4d00975866c2c46d301 Mon Sep 17 00:00:00 2001 From: Federico Rampazzo Date: Sat, 28 Nov 2020 02:32:04 +0000 Subject: [PATCH 6/7] Fix more typos --- tests/postgres/derives.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/postgres/derives.rs b/tests/postgres/derives.rs index 1bea0c96fa..dc57f2d391 100644 --- a/tests/postgres/derives.rs +++ b/tests/postgres/derives.rs @@ -486,7 +486,7 @@ async fn test_from_row_with_rename_all() -> anyhow::Result<()> { let mut conn = new::().await?; let account: AccountKeyword = sqlx::query_as( - r#"SELECT * from (VALUES (1, 'foo', 'bar')) accounts(userId, userName, userSurname)"#, + r#"SELECT * from (VALUES (1, 'foo', 'bar')) accounts(\"userId\", \"userName\", \"userSurname\")"#, ) .fetch_one(&mut conn) .await?; @@ -494,7 +494,7 @@ async fn test_from_row_with_rename_all() -> anyhow::Result<()> { assert_eq!(1, account.user_id); assert_eq!("foo", account.user_name); - assert_eq!("bar8", account.user_surname); + assert_eq!("bar", account.user_surname); Ok(()) } From b0f23fdc865176f547497740af1753891a91046c Mon Sep 17 00:00:00 2001 From: Federico Rampazzo Date: Sat, 28 Nov 2020 11:09:30 +0000 Subject: [PATCH 7/7] Fix escaping test query --- tests/postgres/derives.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/postgres/derives.rs b/tests/postgres/derives.rs index dc57f2d391..c85ced0e62 100644 --- a/tests/postgres/derives.rs +++ b/tests/postgres/derives.rs @@ -486,7 +486,7 @@ async fn test_from_row_with_rename_all() -> anyhow::Result<()> { let mut conn = new::().await?; let account: AccountKeyword = sqlx::query_as( - r#"SELECT * from (VALUES (1, 'foo', 'bar')) accounts(\"userId\", \"userName\", \"userSurname\")"#, + r#"SELECT * from (VALUES (1, 'foo', 'bar')) accounts("userId", "userName", "userSurname")"#, ) .fetch_one(&mut conn) .await?;