Merge pull request #209 from SeaQL/rename-col-name-n-variant

Rename column name & column enum variant
This commit is contained in:
Chris Tsang 2021-09-30 19:30:05 +08:00 committed by GitHub
commit d4d262584c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 469 additions and 20 deletions

View File

@ -2,7 +2,7 @@ use crate::util::field_not_ignored;
use heck::CamelCase;
use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote, quote_spanned};
use syn::{Data, DataStruct, Field, Fields, Type};
use syn::{punctuated::Punctuated, token::Comma, Data, DataStruct, Field, Fields, Lit, Meta, Type};
pub fn expand_derive_active_model(ident: Ident, data: Data) -> syn::Result<TokenStream> {
let fields = match data {
@ -28,7 +28,36 @@ pub fn expand_derive_active_model(ident: Ident, data: Data) -> syn::Result<Token
let name: Vec<Ident> = fields
.clone()
.into_iter()
.map(|Field { ident, .. }| format_ident!("{}", ident.unwrap().to_string().to_camel_case()))
.map(|field| {
let mut ident = format_ident!(
"{}",
field.ident.as_ref().unwrap().to_string().to_camel_case()
);
for attr in field.attrs.iter() {
if let Some(ident) = attr.path.get_ident() {
if ident != "sea_orm" {
continue;
}
} else {
continue;
}
if let Ok(list) = attr.parse_args_with(Punctuated::<Meta, Comma>::parse_terminated)
{
for meta in list.iter() {
if let Meta::NameValue(nv) = meta {
if let Some(name) = nv.path.get_ident() {
if name == "enum_name" {
if let Lit::Str(litstr) = &nv.lit {
ident = syn::parse_str(&litstr.value()).unwrap();
}
}
}
}
}
}
}
ident
})
.collect();
let ty: Vec<Type> = fields.into_iter().map(|Field { ty, .. }| ty).collect();

View File

@ -1,7 +1,7 @@
use heck::{MixedCase, SnakeCase};
use proc_macro2::{Ident, TokenStream};
use quote::{quote, quote_spanned};
use syn::{Data, DataEnum, Fields, Variant};
use syn::{punctuated::Punctuated, token::Comma, Data, DataEnum, Fields, Lit, Meta, Variant};
pub fn impl_default_as_str(ident: &Ident, data: &Data) -> syn::Result<TokenStream> {
let variants = match data {
@ -25,8 +25,31 @@ pub fn impl_default_as_str(ident: &Ident, data: &Data) -> syn::Result<TokenStrea
let name: Vec<TokenStream> = variants
.iter()
.map(|v| {
let ident = v.ident.to_string().to_snake_case();
quote! { #ident }
let mut column_name = v.ident.to_string().to_snake_case();
for attr in v.attrs.iter() {
if let Some(ident) = attr.path.get_ident() {
if ident != "sea_orm" {
continue;
}
} else {
continue;
}
if let Ok(list) = attr.parse_args_with(Punctuated::<Meta, Comma>::parse_terminated)
{
for meta in list.iter() {
if let Meta::NameValue(nv) = meta {
if let Some(name) = nv.path.get_ident() {
if name == "column_name" {
if let Lit::Str(litstr) = &nv.lit {
column_name = litstr.value();
}
}
}
}
}
}
}
quote! { #column_name }
})
.collect();

View File

@ -60,9 +60,8 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec<Attribute>) -> syn::Res
if let Fields::Named(fields) = item_struct.fields {
for field in fields.named {
if let Some(ident) = &field.ident {
let field_name =
let mut field_name =
Ident::new(&ident.to_string().to_case(Case::Pascal), Span::call_site());
columns_enum.push(quote! { #field_name });
let mut nullable = false;
let mut default_value = None;
@ -71,7 +70,10 @@ 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;
// search for #[sea_orm(primary_key, auto_increment = false, column_type = "String(Some(255))", default_value = "new user", default_expr = "gen_random_uuid()", nullable, indexed, unique)]
let mut column_name = 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)]
for attr in field.attrs.iter() {
if let Some(ident) = attr.path.get_ident() {
if ident != "sea_orm" {
@ -116,6 +118,26 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec<Attribute>) -> syn::Res
default_value = Some(nv.lit.to_owned());
} else if name == "default_expr" {
default_expr = Some(nv.lit.to_owned());
} else if name == "column_name" {
if let Lit::Str(litstr) = &nv.lit {
column_name = Some(litstr.value());
} else {
return Err(Error::new(
field.span(),
format!("Invalid column_name {:?}", nv.lit),
));
}
} else if name == "enum_name" {
if let Lit::Str(litstr) = &nv.lit {
let ty: Ident =
syn::parse_str(&litstr.value())?;
enum_name = Some(ty);
} else {
return Err(Error::new(
field.span(),
format!("Invalid enum_name {:?}", nv.lit),
));
}
}
}
}
@ -125,7 +147,7 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec<Attribute>) -> syn::Res
ignore = true;
break;
} else if name == "primary_key" {
primary_keys.push(quote! { #field_name });
is_primary_key = true;
primary_key_types.push(field.ty.clone());
} else if name == "nullable" {
nullable = true;
@ -142,9 +164,27 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec<Attribute>) -> syn::Res
}
}
if let Some(enum_name) = enum_name {
field_name = enum_name;
}
if ignore {
columns_enum.pop();
continue;
} else {
let variant_attrs = match &column_name {
Some(column_name) => quote! {
#[sea_orm(column_name = #column_name)]
},
None => quote! {},
};
columns_enum.push(quote! {
#variant_attrs
#field_name
});
}
if is_primary_key {
primary_keys.push(quote! { #field_name });
}
let field_type = match sql_type {

View File

@ -3,7 +3,7 @@ use heck::CamelCase;
use proc_macro2::TokenStream;
use quote::{format_ident, quote, quote_spanned};
use std::iter::FromIterator;
use syn::Ident;
use syn::{punctuated::Punctuated, token::Comma, Ident, Lit, Meta};
enum Error {
InputNotStruct,
@ -43,10 +43,35 @@ impl DeriveModel {
let column_idents = fields
.iter()
.map(|field| {
format_ident!(
let mut ident = format_ident!(
"{}",
field.ident.as_ref().unwrap().to_string().to_camel_case()
)
);
for attr in field.attrs.iter() {
if let Some(ident) = attr.path.get_ident() {
if ident != "sea_orm" {
continue;
}
} else {
continue;
}
if let Ok(list) =
attr.parse_args_with(Punctuated::<Meta, Comma>::parse_terminated)
{
for meta in list.iter() {
if let Meta::NameValue(nv) = meta {
if let Some(name) = nv.path.get_ident() {
if name == "enum_name" {
if let Lit::Str(litstr) = &nv.lit {
ident = syn::parse_str(&litstr.value()).unwrap();
}
}
}
}
}
}
}
ident
})
.collect();

View File

@ -46,7 +46,7 @@ pub fn derive_primary_key(input: TokenStream) -> TokenStream {
}
}
#[proc_macro_derive(DeriveColumn)]
#[proc_macro_derive(DeriveColumn, attributes(sea_orm))]
pub fn derive_column(input: TokenStream) -> TokenStream {
let DeriveInput { ident, data, .. } = parse_macro_input!(input);

View File

@ -453,4 +453,325 @@ mod tests {
ColumnType::Integer.def().unique().indexed().nullable()
);
}
#[test]
#[cfg(feature = "macros")]
fn column_name_1() {
use sea_query::Iden;
mod hello {
use crate as sea_orm;
use crate::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
#[sea_orm(table_name = "hello")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
#[sea_orm(column_name = "ONE")]
pub one: i32,
pub two: i32,
#[sea_orm(column_name = "3")]
pub three: i32,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}
impl ActiveModelBehavior for ActiveModel {}
}
assert_eq!(hello::Column::One.to_string().as_str(), "ONE");
assert_eq!(hello::Column::Two.to_string().as_str(), "two");
assert_eq!(hello::Column::Three.to_string().as_str(), "3");
}
#[test]
#[cfg(feature = "macros")]
fn column_name_2() {
use sea_query::Iden;
mod hello {
use crate as sea_orm;
use crate::entity::prelude::*;
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
pub struct Entity;
impl EntityName for Entity {
fn table_name(&self) -> &str {
"hello"
}
}
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
pub struct Model {
pub id: i32,
pub one: i32,
pub two: i32,
pub three: i32,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
pub enum Column {
Id,
#[sea_orm(column_name = "ONE")]
One,
Two,
#[sea_orm(column_name = "3")]
Three,
}
impl ColumnTrait for Column {
type EntityName = Entity;
fn def(&self) -> ColumnDef {
match self {
Column::Id => ColumnType::Integer.def(),
Column::One => ColumnType::Integer.def(),
Column::Two => ColumnType::Integer.def(),
Column::Three => ColumnType::Integer.def(),
}
}
}
#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
pub enum PrimaryKey {
Id,
}
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = i32;
fn auto_increment() -> bool {
true
}
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}
impl ActiveModelBehavior for ActiveModel {}
}
assert_eq!(hello::Column::One.to_string().as_str(), "ONE");
assert_eq!(hello::Column::Two.to_string().as_str(), "two");
assert_eq!(hello::Column::Three.to_string().as_str(), "3");
}
#[test]
#[cfg(feature = "macros")]
fn enum_name_1() {
use sea_query::Iden;
mod hello {
use crate as sea_orm;
use crate::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
#[sea_orm(table_name = "hello")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
#[sea_orm(enum_name = "One1")]
pub one: i32,
pub two: i32,
#[sea_orm(enum_name = "Three3")]
pub three: i32,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}
impl ActiveModelBehavior for ActiveModel {}
}
assert_eq!(hello::Column::One1.to_string().as_str(), "one1");
assert_eq!(hello::Column::Two.to_string().as_str(), "two");
assert_eq!(hello::Column::Three3.to_string().as_str(), "three3");
}
#[test]
#[cfg(feature = "macros")]
fn enum_name_2() {
use sea_query::Iden;
mod hello {
use crate as sea_orm;
use crate::entity::prelude::*;
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
pub struct Entity;
impl EntityName for Entity {
fn table_name(&self) -> &str {
"hello"
}
}
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
pub struct Model {
pub id: i32,
#[sea_orm(enum_name = "One1")]
pub one: i32,
pub two: i32,
#[sea_orm(enum_name = "Three3")]
pub three: i32,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
pub enum Column {
Id,
One1,
Two,
Three3,
}
impl ColumnTrait for Column {
type EntityName = Entity;
fn def(&self) -> ColumnDef {
match self {
Column::Id => ColumnType::Integer.def(),
Column::One1 => ColumnType::Integer.def(),
Column::Two => ColumnType::Integer.def(),
Column::Three3 => ColumnType::Integer.def(),
}
}
}
#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
pub enum PrimaryKey {
Id,
}
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = i32;
fn auto_increment() -> bool {
true
}
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}
impl ActiveModelBehavior for ActiveModel {}
}
assert_eq!(hello::Column::One1.to_string().as_str(), "one1");
assert_eq!(hello::Column::Two.to_string().as_str(), "two");
assert_eq!(hello::Column::Three3.to_string().as_str(), "three3");
}
#[test]
#[cfg(feature = "macros")]
fn column_name_enum_name_1() {
use sea_query::Iden;
mod hello {
use crate as sea_orm;
use crate::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
#[sea_orm(table_name = "hello")]
pub struct Model {
#[sea_orm(primary_key, column_name = "ID", enum_name = "IdentityColumn")]
pub id: i32,
#[sea_orm(column_name = "ONE", enum_name = "One1")]
pub one: i32,
pub two: i32,
#[sea_orm(column_name = "THREE", enum_name = "Three3")]
pub three: i32,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}
impl ActiveModelBehavior for ActiveModel {}
}
assert_eq!(hello::Column::IdentityColumn.to_string().as_str(), "ID");
assert_eq!(hello::Column::One1.to_string().as_str(), "ONE");
assert_eq!(hello::Column::Two.to_string().as_str(), "two");
assert_eq!(hello::Column::Three3.to_string().as_str(), "THREE");
}
#[test]
#[cfg(feature = "macros")]
fn column_name_enum_name_2() {
use sea_query::Iden;
mod hello {
use crate as sea_orm;
use crate::entity::prelude::*;
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
pub struct Entity;
impl EntityName for Entity {
fn table_name(&self) -> &str {
"hello"
}
}
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
pub struct Model {
#[sea_orm(enum_name = "IdentityCol")]
pub id: i32,
#[sea_orm(enum_name = "One1")]
pub one: i32,
pub two: i32,
#[sea_orm(enum_name = "Three3")]
pub three: i32,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
pub enum Column {
#[sea_orm(column_name = "ID")]
IdentityCol,
#[sea_orm(column_name = "ONE")]
One1,
Two,
#[sea_orm(column_name = "THREE")]
Three3,
}
impl ColumnTrait for Column {
type EntityName = Entity;
fn def(&self) -> ColumnDef {
match self {
Column::IdentityCol => ColumnType::Integer.def(),
Column::One1 => ColumnType::Integer.def(),
Column::Two => ColumnType::Integer.def(),
Column::Three3 => ColumnType::Integer.def(),
}
}
}
#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
pub enum PrimaryKey {
IdentityCol,
}
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = i32;
fn auto_increment() -> bool {
true
}
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}
impl ActiveModelBehavior for ActiveModel {}
}
assert_eq!(hello::Column::IdentityCol.to_string().as_str(), "ID");
assert_eq!(hello::Column::One1.to_string().as_str(), "ONE");
assert_eq!(hello::Column::Two.to_string().as_str(), "two");
assert_eq!(hello::Column::Three3.to_string().as_str(), "THREE");
}
}

View File

@ -1,6 +1,6 @@
use crate::{
error::*, ActiveModelTrait, DatabaseConnection, DbBackend, EntityTrait, Insert, PrimaryKeyTrait,
Statement, TryFromU64,
error::*, ActiveModelTrait, DatabaseConnection, DbBackend, EntityTrait, Insert,
PrimaryKeyTrait, Statement, TryFromU64,
};
use sea_query::InsertStatement;
use std::{future::Future, marker::PhantomData};

View File

@ -276,7 +276,9 @@ pub trait QueryFilter: Sized {
/// struct Input {
/// name: Option<String>,
/// }
/// let input = Input { name: Some("cheese".to_owned()) };
/// let input = Input {
/// name: Some("cheese".to_owned()),
/// };
///
/// let mut conditions = Condition::all();
/// if let Some(name) = input.name {
@ -298,13 +300,14 @@ pub trait QueryFilter: Sized {
/// struct Input {
/// name: Option<String>,
/// }
/// let input = Input { name: Some("cheese".to_owned()) };
/// let input = Input {
/// name: Some("cheese".to_owned()),
/// };
///
/// assert_eq!(
/// cake::Entity::find()
/// .filter(
/// Condition::all()
/// .add_option(input.name.map(|n| cake::Column::Name.contains(&n)))
/// Condition::all().add_option(input.name.map(|n| cake::Column::Name.contains(&n)))
/// )
/// .build(DbBackend::MySql)
/// .to_string(),

View File

@ -6,6 +6,7 @@ use crate::entity::prelude::*;
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
#[sea_orm(column_name = "name", enum_name = "Name")]
pub name: String,
}

View File

@ -5,6 +5,8 @@ use sea_orm::entity::prelude::*;
pub struct Model {
#[sea_orm(primary_key, auto_increment = false)]
pub uuid: Uuid,
#[sea_orm(column_name = "type", enum_name = "Type")]
pub ty: String,
pub key: String,
pub value: String,
pub bytes: Vec<u8>,

View File

@ -283,6 +283,7 @@ pub async fn create_metadata_table(db: &DbConn) -> Result<ExecResult, DbErr> {
.not_null()
.primary_key(),
)
.col(ColumnDef::new(metadata::Column::Type).string().not_null())
.col(ColumnDef::new(metadata::Column::Key).string().not_null())
.col(ColumnDef::new(metadata::Column::Value).string().not_null())
.col(ColumnDef::new(metadata::Column::Bytes).binary().not_null())

View File

@ -22,18 +22,21 @@ pub async fn crud_in_parallel(db: &DatabaseConnection) -> Result<(), DbErr> {
let metadata = vec![
metadata::Model {
uuid: Uuid::new_v4(),
ty: "Type".to_owned(),
key: "markup".to_owned(),
value: "1.18".to_owned(),
bytes: vec![1, 2, 3],
},
metadata::Model {
uuid: Uuid::new_v4(),
ty: "Type".to_owned(),
key: "exchange_rate".to_owned(),
value: "0.78".to_owned(),
bytes: vec![1, 2, 3],
},
metadata::Model {
uuid: Uuid::new_v4(),
ty: "Type".to_owned(),
key: "service_charge".to_owned(),
value: "1.1".to_owned(),
bytes: vec![1, 2, 3],

View File

@ -20,6 +20,7 @@ async fn main() -> Result<(), DbErr> {
pub async fn create_metadata(db: &DatabaseConnection) -> Result<(), DbErr> {
let metadata = metadata::Model {
uuid: Uuid::new_v4(),
ty: "Type".to_owned(),
key: "markup".to_owned(),
value: "1.18".to_owned(),
bytes: vec![1, 2, 3],