Skip to content

Commit

Permalink
WIP: Implement Case Styles Based Name Generation For Columns In A Model
Browse files Browse the repository at this point in the history
  • Loading branch information
anshap1719 committed Apr 26, 2024
1 parent f5ff5da commit 7381924
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 2 deletions.
26 changes: 24 additions & 2 deletions sea-orm-macros/src/derives/entity_model.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
use super::util::{escape_rust_keyword, trim_starting_raw_identifier};
use heck::{ToSnakeCase, ToUpperCamelCase};
use proc_macro2::{Ident, Span, TokenStream};
use quote::quote;
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<Attribute>) -> syn::Result<TokenStream> {
// if #[sea_orm(table_name = "foo", schema_name = "bar")] specified, create Entity struct
let mut table_name = None;
let mut comment = quote! {None};
let mut schema_name = quote! { None };
let mut table_iden = false;
let mut all_column_name_case: Option<CaseStyle> = None;

attrs
.iter()
.filter(|attr| attr.path().is_ident("sea_orm"))
Expand All @@ -28,6 +33,8 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec<Attribute>) -> 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,
Expand All @@ -38,6 +45,7 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec<Attribute>) -> syn::Res
Ok(())
})
})?;

let entity_def = table_name
.as_ref()
.map(|table_name| {
Expand Down Expand Up @@ -106,14 +114,19 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec<Attribute>) -> 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
Some(original_field_name.to_snake_case())
} 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)]
Expand Down Expand Up @@ -157,9 +170,14 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec<Attribute>) -> 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(
Expand Down Expand Up @@ -210,6 +228,10 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec<Attribute>) -> 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;
}
Expand Down
70 changes: 70 additions & 0 deletions sea-orm-macros/tests/derive_entity_model_column_name_test.rs
Original file line number Diff line number Diff line change
@@ -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<String> = 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",
]
);
}

0 comments on commit 7381924

Please sign in to comment.