From 98e5335fdb332205f0e13aa4abcc931106a040b5 Mon Sep 17 00:00:00 2001 From: Anshul Sanghi Date: Sat, 23 Mar 2024 00:50:54 +0530 Subject: [PATCH] WIP: Implement Case Styles Based Name Generation For Columns In A Model #2160 --- sea-orm-macros/src/derives/entity_model.rs | 26 ++++++- .../derive_entity_model_column_name_test.rs | 70 +++++++++++++++++++ 2 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 sea-orm-macros/tests/derive_entity_model_column_name_test.rs diff --git a/sea-orm-macros/src/derives/entity_model.rs b/sea-orm-macros/src/derives/entity_model.rs index 6c4f8f2725..3c2a80a4c6 100644 --- a/sea-orm-macros/src/derives/entity_model.rs +++ b/sea-orm-macros/src/derives/entity_model.rs @@ -1,4 +1,3 @@ -use super::util::{escape_rust_keyword, trim_starting_raw_identifier}; use heck::{ToSnakeCase, ToUpperCamelCase}; use proc_macro2::{Ident, Span, TokenStream}; use quote::quote; @@ -6,6 +5,10 @@ use syn::{ punctuated::Punctuated, spanned::Spanned, token::Comma, Attribute, Data, Expr, Fields, Lit, }; +use crate::strum::helpers::case_style::{CaseStyle, CaseStyleHelpers}; + +use super::util::{escape_rust_keyword, trim_starting_raw_identifier}; + /// Method to derive an Model pub fn expand_derive_entity_model(data: Data, attrs: Vec) -> syn::Result { // if #[sea_orm(table_name = "foo", schema_name = "bar")] specified, create Entity struct @@ -13,6 +16,8 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec) -> syn::Res let mut comment = quote! {None}; let mut schema_name = quote! { None }; let mut table_iden = false; + let mut all_column_name_case: Option = None; + attrs .iter() .filter(|attr| attr.path().is_ident("sea_orm")) @@ -28,6 +33,8 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec) -> syn::Res schema_name = quote! { Some(#name) }; } else if meta.path.is_ident("table_iden") { table_iden = true; + } else if meta.path.is_ident("column_name_case") { + all_column_name_case = Some((&meta).try_into()?); } else { // Reads the value expression to advance the parse stream. // Some parameters, such as `primary_key`, do not have any value, @@ -38,6 +45,7 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec) -> syn::Res Ok(()) }) })?; + let entity_def = table_name .as_ref() .map(|table_name| { @@ -106,7 +114,11 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec) -> syn::Res let mut ignore = false; let mut unique = false; let mut sql_type = None; - let mut column_name = if original_field_name + let mut column_name_case_present = false; + let mut column_name_attr_present = false; + let mut column_name = if let Some(case_style) = all_column_name_case { + Some(field_name.convert_case(Some(case_style))) + } else if original_field_name != original_field_name.to_upper_camel_case().to_snake_case() { // `to_snake_case` was used to trim prefix and tailing underscore @@ -114,6 +126,7 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec) -> syn::Res } else { None }; + let mut enum_name = None; let mut is_primary_key = false; // search for #[sea_orm(primary_key, auto_increment = false, column_type = "String(Some(255))", default_value = "new user", default_expr = "gen_random_uuid()", column_name = "name", enum_name = "Name", nullable, indexed, unique)] @@ -157,9 +170,14 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec) -> syn::Res meta.error(format!("Invalid column_type {:?}", lit)) ); } + } else if meta.path.is_ident("column_name_case") { + let case_style: CaseStyle = (&meta).try_into()?; + column_name_case_present = true; + column_name = Some(field_name.convert_case(Some(case_style))); } else if meta.path.is_ident("column_name") { let lit = meta.value()?.parse()?; if let Lit::Str(litstr) = lit { + column_name_attr_present = true; column_name = Some(litstr.value()); } else { return Err( @@ -210,6 +228,10 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec) -> syn::Res })?; } + if column_name_attr_present && column_name_case_present { + return Err(syn::Error::new_spanned(field_name, "Either `column_name_case` or `column_name` can be provided, but not both")); + } + if let Some(enum_name) = enum_name { field_name = enum_name; } diff --git a/sea-orm-macros/tests/derive_entity_model_column_name_test.rs b/sea-orm-macros/tests/derive_entity_model_column_name_test.rs new file mode 100644 index 0000000000..3f40a4d436 --- /dev/null +++ b/sea-orm-macros/tests/derive_entity_model_column_name_test.rs @@ -0,0 +1,70 @@ +use sea_orm::prelude::*; +use sea_orm::Iden; +use sea_orm::Iterable; +use sea_orm_macros::DeriveEntityModel; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "user")] +#[sea_orm(column_name_case = "camelCase")] +pub struct Model { + #[sea_orm(primary_key)] + id: i32, + username: String, + first_name: String, + middle_name: String, + #[sea_orm(column_name = "lAsTnAmE")] + last_name: String, + orders_count: i32, + #[sea_orm(column_name_case = "camelCase")] + camel_case: String, + #[sea_orm(column_name_case = "kebab-case")] + kebab_case: String, + #[sea_orm(column_name_case = "mixed_case")] + mixed_case: String, + #[sea_orm(column_name_case = "SCREAMING_SNAKE_CASE")] + screaming_snake_case: String, + #[sea_orm(column_name_case = "snake_case")] + snake_case: String, + #[sea_orm(column_name_case = "title_case")] + title_case: String, + #[sea_orm(column_name_case = "UPPERCASE")] + upper_case: String, + #[sea_orm(column_name_case = "lowercase")] + lowercase: String, + #[sea_orm(column_name_case = "SCREAMING-KEBAB-CASE")] + screaming_kebab_case: String, + #[sea_orm(column_name_case = "PascalCase")] + pascal_case: String, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation {} + +impl ActiveModelBehavior for ActiveModel {} + +#[test] +fn test_column_names() { + let columns: Vec = Column::iter().map(|item| item.to_string()).collect(); + + assert_eq!( + columns, + vec![ + "id", + "username", + "firstName", + "middleName", + "lAsTnAmE", + "ordersCount", + "camelCase", + "kebab-case", + "mixedCase", + "SCREAMING_SNAKE_CASE", + "snake_case", + "Title Case", + "UPPERCASE", + "lowercase", + "SCREAMING-KEBAB-CASE", + "PascalCase", + ] + ); +}