Upgrading to syn v2 (#1713)

* resetted and re-did the changes

* fmt

* upgraded to syn2 for sea-orm-codegen

* Rename `bae2`

* Drop the use of `#[sea_orm(table_name = "col_name")]` in `DeriveColumn`

* unified derived input metadata parsing filter

* Propagate errors

---------

Co-authored-by: Billy Chan <ccw.billy.123@gmail.com>
This commit is contained in:
darkmmon 2023-06-26 20:15:37 +08:00 committed by GitHub
parent 35c274818b
commit 64342b105c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 252 additions and 357 deletions

View File

@ -18,7 +18,7 @@ path = "src/lib.rs"
[dependencies] [dependencies]
sea-query = { version = "0.29.0-rc.2", default-features = false, features = ["thread-safe"] } sea-query = { version = "0.29.0-rc.2", default-features = false, features = ["thread-safe"] }
syn = { version = "1", default-features = false, features = ["parsing", "proc-macro", "derive", "printing"] } syn = { version = "2", default-features = false, features = ["parsing", "proc-macro", "derive", "printing"] }
quote = { version = "1", default-features = false } quote = { version = "1", default-features = false }
heck = { version = "0.4", default-features = false } heck = { version = "0.4", default-features = false }
proc-macro2 = { version = "1", default-features = false } proc-macro2 = { version = "1", default-features = false }

View File

@ -18,8 +18,8 @@ path = "src/lib.rs"
proc-macro = true proc-macro = true
[dependencies] [dependencies]
bae = { version = "0.1", default-features = false, optional = true } bae = { version = "1", package = "bae2", default-features = false, optional = true }
syn = { version = "1", default-features = false, features = ["parsing", "proc-macro", "derive", "printing"] } syn = { version = "2", default-features = false, features = ["parsing", "proc-macro", "derive", "printing"] }
quote = { version = "1", default-features = false } quote = { version = "1", default-features = false }
heck = { version = "0.4", default-features = false } heck = { version = "0.4", default-features = false }
proc-macro2 = { version = "1", default-features = false } proc-macro2 = { version = "1", default-features = false }

View File

@ -2,7 +2,7 @@ use super::util::camel_case_with_escaped_non_uax31;
use heck::ToUpperCamelCase; use heck::ToUpperCamelCase;
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::{format_ident, quote, quote_spanned}; use quote::{format_ident, quote, quote_spanned};
use syn::{parse, punctuated::Punctuated, token::Comma, Expr, Lit, LitInt, LitStr, Meta, UnOp}; use syn::{parse, Expr, Lit, LitInt, LitStr, UnOp};
enum Error { enum Error {
InputNotEnum, InputNotEnum,
@ -37,51 +37,46 @@ impl ActiveEnum {
let mut db_type = Err(Error::TT(quote_spanned! { let mut db_type = Err(Error::TT(quote_spanned! {
ident_span => compile_error!("Missing macro attribute `db_type`"); ident_span => compile_error!("Missing macro attribute `db_type`");
})); }));
for attr in input.attrs.iter() {
if let Some(ident) = attr.path.get_ident() { input
if ident != "sea_orm" { .attrs
continue; .iter()
} .filter(|attr| attr.path().is_ident("sea_orm"))
} else { .try_for_each(|attr| {
continue; attr.parse_nested_meta(|meta| {
} if meta.path.is_ident("rs_type") {
if let Ok(list) = attr.parse_args_with(Punctuated::<Meta, Comma>::parse_terminated) { let litstr: LitStr = meta.value()?.parse()?;
for meta in list.iter() { rs_type =
if let Meta::NameValue(nv) = meta { syn::parse_str::<TokenStream>(&litstr.value()).map_err(Error::Syn);
if let Some(name) = nv.path.get_ident() { } else if meta.path.is_ident("db_type") {
if name == "rs_type" { let litstr: LitStr = meta.value()?.parse()?;
if let Lit::Str(litstr) = &nv.lit { let s = litstr.value();
rs_type = syn::parse_str::<TokenStream>(&litstr.value()) match s.as_ref() {
.map_err(Error::Syn); "Enum" => {
} db_type = Ok(quote! {
} else if name == "db_type" { Enum {
if let Lit::Str(litstr) = &nv.lit { name: Self::name(),
let s = litstr.value(); variants: Self::iden_values(),
match s.as_ref() {
"Enum" => {
db_type = Ok(quote! {
Enum {
name: Self::name(),
variants: Self::iden_values(),
}
})
}
_ => {
db_type = syn::parse_str::<TokenStream>(&s)
.map_err(Error::Syn);
}
} }
} })
} else if name == "enum_name" { }
if let Lit::Str(litstr) = &nv.lit { _ => {
enum_name = litstr.value(); db_type = syn::parse_str::<TokenStream>(&s).map_err(Error::Syn);
}
} }
} }
} else if meta.path.is_ident("enum_name") {
let litstr: LitStr = meta.value()?.parse()?;
enum_name = litstr.value();
} else {
return Err(meta.error(format!(
"Unknown attribute parameter found: {:?}",
meta.path.get_ident()
)));
} }
} Ok(())
} })
} .map_err(Error::Syn)
})?;
let variant_vec = match input.data { let variant_vec = match input.data {
syn::Data::Enum(syn::DataEnum { variants, .. }) => variants, syn::Data::Enum(syn::DataEnum { variants, .. }) => variants,
@ -96,33 +91,26 @@ impl ActiveEnum {
let mut string_value = None; let mut string_value = None;
let mut num_value = None; let mut num_value = None;
for attr in variant.attrs.iter() { for attr in variant.attrs.iter() {
if let Some(ident) = attr.path.get_ident() { if !attr.path().is_ident("sea_orm") {
if ident != "sea_orm" {
continue;
}
} else {
continue; continue;
} }
if let Ok(list) = attr.parse_args_with(Punctuated::<Meta, Comma>::parse_terminated) attr.parse_nested_meta(|meta| {
{ if meta.path.is_ident("string_value") {
for meta in list { is_string = true;
if let Meta::NameValue(nv) = meta { string_value = Some(meta.value()?.parse::<LitStr>()?);
if let Some(name) = nv.path.get_ident() { } else if meta.path.is_ident("num_value") {
if name == "string_value" { is_int = true;
if let Lit::Str(lit) = nv.lit { num_value = Some(meta.value()?.parse::<LitInt>()?);
is_string = true; } else {
string_value = Some(lit); return Err(meta.error(format!(
} "Unknown attribute parameter found: {:?}",
} else if name == "num_value" { meta.path.get_ident()
if let Lit::Int(lit) = nv.lit { )));
is_int = true;
num_value = Some(lit);
}
}
}
}
} }
}
Ok(())
})
.map_err(Error::Syn)?;
} }
if is_string && is_int { if is_string && is_int {

View File

@ -4,11 +4,7 @@ use super::util::{
use heck::ToUpperCamelCase; use heck::ToUpperCamelCase;
use proc_macro2::{Ident, TokenStream}; use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote, quote_spanned}; use quote::{format_ident, quote, quote_spanned};
use syn::{ use syn::{punctuated::IntoIter, Data, DataStruct, Expr, Field, Fields, LitStr, Type};
punctuated::{IntoIter, Punctuated},
token::Comma,
Data, DataStruct, Field, Fields, Lit, Meta, Type,
};
/// Method to derive an [ActiveModel](sea_orm::ActiveModel) /// Method to derive an [ActiveModel](sea_orm::ActiveModel)
pub fn expand_derive_active_model(ident: Ident, data: Data) -> syn::Result<TokenStream> { pub fn expand_derive_active_model(ident: Ident, data: Data) -> syn::Result<TokenStream> {
@ -47,32 +43,28 @@ fn derive_active_model(all_fields: IntoIter<Field>) -> syn::Result<TokenStream>
let ident = trim_starting_raw_identifier(ident).to_upper_camel_case(); let ident = trim_starting_raw_identifier(ident).to_upper_camel_case();
let ident = escape_rust_keyword(ident); let ident = escape_rust_keyword(ident);
let mut ident = format_ident!("{}", &ident); let mut ident = format_ident!("{}", &ident);
for attr in field.attrs.iter() { field
if let Some(ident) = attr.path.get_ident() { .attrs
if ident != "sea_orm" { .iter()
continue; .filter(|attr| attr.path().is_ident("sea_orm"))
} .try_for_each(|attr| {
} else { attr.parse_nested_meta(|meta| {
continue; if meta.path.is_ident("enum_name") {
} let litstr: LitStr = meta.value()?.parse()?;
if let Ok(list) = attr.parse_args_with(Punctuated::<Meta, Comma>::parse_terminated) ident = syn::parse_str(&litstr.value()).unwrap();
{ } else {
for meta in list.iter() { // Reads the value expression to advance the parse stream.
if let Meta::NameValue(nv) = meta { // Some parameters, such as `primary_key`, do not have any value,
if let Some(name) = nv.path.get_ident() { // so ignoring an error occurred here.
if name == "enum_name" { let _: Option<Expr> = meta.value().and_then(|v| v.parse()).ok();
if let Lit::Str(litstr) = &nv.lit {
ident = syn::parse_str(&litstr.value()).unwrap();
}
}
}
} }
}
} Ok(())
} })
ident })?;
Ok::<Ident, syn::Error>(ident)
}) })
.collect(); .collect::<Result<_, _>>()?;
let ty: Vec<Type> = fields.into_iter().map(|Field { ty, .. }| ty).collect(); let ty: Vec<Type> = fields.into_iter().map(|Field { ty, .. }| ty).collect();

View File

@ -1,7 +1,7 @@
use heck::{ToLowerCamelCase, ToSnakeCase}; use heck::{ToLowerCamelCase, ToSnakeCase};
use proc_macro2::{Ident, TokenStream}; use proc_macro2::{Ident, TokenStream};
use quote::{quote, quote_spanned}; use quote::{quote, quote_spanned};
use syn::{punctuated::Punctuated, token::Comma, Data, DataEnum, Fields, Lit, Meta, Variant}; use syn::{Data, DataEnum, Expr, Fields, LitStr, Variant};
/// Derive a Column name for an enum type /// Derive a Column name for an enum type
pub fn impl_default_as_str(ident: &Ident, data: &Data) -> syn::Result<TokenStream> { pub fn impl_default_as_str(ident: &Ident, data: &Data) -> syn::Result<TokenStream> {
@ -28,36 +28,24 @@ pub fn impl_default_as_str(ident: &Ident, data: &Data) -> syn::Result<TokenStrea
.map(|v| { .map(|v| {
let mut column_name = v.ident.to_string().to_snake_case(); let mut column_name = v.ident.to_string().to_snake_case();
for attr in v.attrs.iter() { for attr in v.attrs.iter() {
if let Some(ident) = attr.path.get_ident() { if !attr.path().is_ident("sea_orm") {
if ident != "sea_orm" {
continue;
}
} else {
continue; continue;
} }
if let Ok(list) = attr.parse_args_with(Punctuated::<Meta, Comma>::parse_terminated) attr.parse_nested_meta(|meta| {
{ if meta.path.is_ident("column_name") {
for meta in list.iter() { column_name = meta.value()?.parse::<LitStr>()?.value();
if let Meta::NameValue(nv) = meta { } else {
if let Some(name) = nv.path.get_ident() { // Reads the value expression to advance the parse stream.
if name == "column_name" { // Some parameters, such as `primary_key`, do not have any value,
if let Lit::Str(litstr) = &nv.lit { // so ignoring an error occurred here.
column_name = litstr.value(); let _: Option<Expr> = meta.value().and_then(|v| v.parse()).ok();
}
}
if name == "table_name" {
if let Lit::Str(litstr) = &nv.lit {
column_name = litstr.value();
}
}
}
}
} }
} Ok(())
})?;
} }
quote! { #column_name } Ok::<TokenStream, syn::Error>(quote! { #column_name })
}) })
.collect(); .collect::<Result<_, _>>()?;
Ok(quote!( Ok(quote!(
#[automatically_derived] #[automatically_derived]

View File

@ -3,8 +3,8 @@ use heck::{ToSnakeCase, ToUpperCamelCase};
use proc_macro2::{Ident, Span, TokenStream}; use proc_macro2::{Ident, Span, TokenStream};
use quote::{quote, quote_spanned}; use quote::{quote, quote_spanned};
use syn::{ use syn::{
parse::Error, punctuated::Punctuated, spanned::Spanned, token::Comma, Attribute, Data, Fields, punctuated::Punctuated, spanned::Spanned, token::Comma, Attribute, Data, Expr, Fields, Lit,
Lit, LitStr, Meta, Type, LitStr, Type,
}; };
/// Method to derive an Model /// Method to derive an Model
@ -13,32 +13,28 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec<Attribute>) -> syn::Res
let mut table_name = None; let mut table_name = None;
let mut schema_name = quote! { None }; let mut schema_name = quote! { None };
let mut table_iden = false; let mut table_iden = false;
attrs.iter().for_each(|attr| { attrs
if attr.path.get_ident().map(|i| i == "sea_orm") != Some(true) { .iter()
return; .filter(|attr| attr.path().is_ident("sea_orm"))
} .try_for_each(|attr| {
attr.parse_nested_meta(|meta| {
if let Ok(list) = attr.parse_args_with(Punctuated::<Meta, Comma>::parse_terminated) { if meta.path.is_ident("table_name") {
for meta in list.iter() { table_name = Some(meta.value()?.parse::<Lit>()?);
if let Meta::NameValue(nv) = meta { } else if meta.path.is_ident("schema_name") {
if let Some(ident) = nv.path.get_ident() { let name: Lit = meta.value()?.parse()?;
if ident == "table_name" { schema_name = quote! { Some(#name) };
table_name = Some(nv.lit.clone()); } else if meta.path.is_ident("table_iden") {
} else if ident == "schema_name" { table_iden = true;
let name = &nv.lit; } else {
schema_name = quote! { Some(#name) }; // Reads the value expression to advance the parse stream.
} // Some parameters, such as `primary_key`, do not have any value,
} // so ignoring an error occurred here.
} else if let Meta::Path(path) = meta { let _: Option<Expr> = meta.value().and_then(|v| v.parse()).ok();
if let Some(ident) = path.get_ident() {
if ident == "table_iden" {
table_iden = true;
}
}
} }
}
} Ok(())
}); })
})?;
let entity_def = table_name let entity_def = table_name
.as_ref() .as_ref()
.map(|table_name| { .map(|table_name| {
@ -114,111 +110,86 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec<Attribute>) -> syn::Res
let mut is_primary_key = false; 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)] // 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() { for attr in field.attrs.iter() {
if let Some(ident) = attr.path.get_ident() { if !attr.path().is_ident("sea_orm") {
if ident != "sea_orm" {
continue;
}
} else {
continue; continue;
} }
// single param // single param
if let Ok(list) = attr.parse_nested_meta(|meta| {
attr.parse_args_with(Punctuated::<Meta, Comma>::parse_terminated) if meta.path.is_ident("column_type") {
{ let lit = meta.value()?.parse()?;
for meta in list.iter() { if let Lit::Str(litstr) = lit {
match meta { let ty: TokenStream = syn::parse_str(&litstr.value())?;
Meta::NameValue(nv) => { sql_type = Some(ty);
if let Some(name) = nv.path.get_ident() { } else {
if name == "column_type" { return Err(
if let Lit::Str(litstr) = &nv.lit { meta.error(format!("Invalid column_type {:?}", lit))
let ty: TokenStream = );
syn::parse_str(&litstr.value())?;
sql_type = Some(ty);
} else {
return Err(Error::new(
field.span(),
format!("Invalid column_type {:?}", nv.lit),
));
}
} else if name == "auto_increment" {
if let Lit::Bool(litbool) = &nv.lit {
auto_increment = litbool.value();
} else {
return Err(Error::new(
field.span(),
format!(
"Invalid auto_increment = {:?}",
nv.lit
),
));
}
} else if name == "default_value" {
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),
));
}
} else if name == "select_as" {
if let Lit::Str(litstr) = &nv.lit {
select_as = Some(litstr.value());
} else {
return Err(Error::new(
field.span(),
format!("Invalid select_as {:?}", nv.lit),
));
}
} else if name == "save_as" {
if let Lit::Str(litstr) = &nv.lit {
save_as = Some(litstr.value());
} else {
return Err(Error::new(
field.span(),
format!("Invalid save_as {:?}", nv.lit),
));
}
}
}
}
Meta::Path(p) => {
if let Some(name) = p.get_ident() {
if name == "ignore" {
ignore = true;
break;
} else if name == "primary_key" {
is_primary_key = true;
primary_key_types.push(field.ty.clone());
} else if name == "nullable" {
nullable = true;
} else if name == "indexed" {
indexed = true;
} else if name == "unique" {
unique = true;
}
}
}
_ => {}
} }
} else if meta.path.is_ident("auto_increment") {
let lit = meta.value()?.parse()?;
if let Lit::Bool(litbool) = lit {
auto_increment = litbool.value();
} else {
return Err(
meta.error(format!("Invalid auto_increment = {:?}", lit))
);
}
} else if meta.path.is_ident("default_value") {
default_value = Some(meta.value()?.parse::<Lit>()?);
} else if meta.path.is_ident("default_expr") {
default_expr = Some(meta.value()?.parse::<Lit>()?);
} else if meta.path.is_ident("column_name") {
let lit = meta.value()?.parse()?;
if let Lit::Str(litstr) = lit {
column_name = Some(litstr.value());
} else {
return Err(
meta.error(format!("Invalid column_name {:?}", lit))
);
}
} else if meta.path.is_ident("enum_name") {
let lit = meta.value()?.parse()?;
if let Lit::Str(litstr) = lit {
let ty: Ident = syn::parse_str(&litstr.value())?;
enum_name = Some(ty);
} else {
return Err(meta.error(format!("Invalid enum_name {:?}", lit)));
}
} else if meta.path.is_ident("select_as") {
let lit = meta.value()?.parse()?;
if let Lit::Str(litstr) = lit {
select_as = Some(litstr.value());
} else {
return Err(meta.error(format!("Invalid select_as {:?}", lit)));
}
} else if meta.path.is_ident("save_as") {
let lit = meta.value()?.parse()?;
if let Lit::Str(litstr) = lit {
save_as = Some(litstr.value());
} else {
return Err(meta.error(format!("Invalid save_as {:?}", lit)));
}
} else if meta.path.is_ident("ignore") {
ignore = true;
} else if meta.path.is_ident("primary_key") {
is_primary_key = true;
primary_key_types.push(field.ty.clone());
} else if meta.path.is_ident("nullable") {
nullable = true;
} else if meta.path.is_ident("indexed") {
indexed = true;
} else if meta.path.is_ident("unique") {
unique = true;
} else {
// Reads the value expression to advance the parse stream.
// Some parameters, such as `primary_key`, do not have any value,
// so ignoring an error occurred here.
let _: Option<Expr> = meta.value().and_then(|v| v.parse()).ok();
} }
}
Ok(())
})?;
} }
if let Some(enum_name) = enum_name { if let Some(enum_name) = enum_name {

View File

@ -6,7 +6,7 @@ use heck::ToUpperCamelCase;
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::{format_ident, quote, quote_spanned}; use quote::{format_ident, quote, quote_spanned};
use std::iter::FromIterator; use std::iter::FromIterator;
use syn::{punctuated::Punctuated, token::Comma, Ident, Lit, Meta}; use syn::{Expr, Ident, LitStr};
enum Error { enum Error {
InputNotStruct, InputNotStruct,
@ -50,33 +50,29 @@ impl DeriveModel {
let ident = trim_starting_raw_identifier(ident).to_upper_camel_case(); let ident = trim_starting_raw_identifier(ident).to_upper_camel_case();
let ident = escape_rust_keyword(ident); let ident = escape_rust_keyword(ident);
let mut ident = format_ident!("{}", &ident); let mut ident = format_ident!("{}", &ident);
for attr in field.attrs.iter() { field
if let Some(ident) = attr.path.get_ident() { .attrs
if ident != "sea_orm" { .iter()
continue; .filter(|attr| attr.path().is_ident("sea_orm"))
} .try_for_each(|attr| {
} else { attr.parse_nested_meta(|meta| {
continue; if meta.path.is_ident("enum_name") {
} ident = syn::parse_str(&meta.value()?.parse::<LitStr>()?.value())
if let Ok(list) = .unwrap();
attr.parse_args_with(Punctuated::<Meta, Comma>::parse_terminated) } else {
{ // Reads the value expression to advance the parse stream.
for meta in list.iter() { // Some parameters, such as `primary_key`, do not have any value,
if let Meta::NameValue(nv) = meta { // so ignoring an error occurred here.
if let Some(name) = nv.path.get_ident() { let _: Option<Expr> = meta.value().and_then(|v| v.parse()).ok();
if name == "enum_name" {
if let Lit::Str(litstr) = &nv.lit {
ident = syn::parse_str(&litstr.value()).unwrap();
}
}
}
} }
}
} Ok(())
} })
ident .map_err(Error::Syn)
})?;
Ok(ident)
}) })
.collect(); .collect::<Result<_, _>>()?;
let ignore_attrs = fields let ignore_attrs = fields
.iter() .iter()

View File

@ -50,11 +50,7 @@ impl DerivePartialModel {
let mut entity_ident = None; let mut entity_ident = None;
for attr in input.attrs.iter() { for attr in input.attrs.iter() {
if let Some(ident) = attr.path.get_ident() { if !attr.path().is_ident("sea_orm") {
if ident != "sea_orm" {
continue;
}
} else {
continue; continue;
} }
@ -77,7 +73,7 @@ impl DerivePartialModel {
let mut from_expr = None; let mut from_expr = None;
for attr in field.attrs.iter() { for attr in field.attrs.iter() {
if !attr.path.is_ident("sea_orm") { if !attr.path().is_ident("sea_orm") {
continue; continue;
} }
@ -192,7 +188,7 @@ pub fn expand_derive_partial_model(input: syn::DeriveInput) -> syn::Result<Token
} }
mod util { mod util {
use syn::{Lit, Meta, MetaNameValue}; use syn::{Meta, MetaNameValue};
pub(super) trait GetAsKVMeta { pub(super) trait GetAsKVMeta {
fn get_as_kv(&self, k: &str) -> Option<String>; fn get_as_kv(&self, k: &str) -> Option<String>;
@ -200,12 +196,14 @@ mod util {
impl GetAsKVMeta for Meta { impl GetAsKVMeta for Meta {
fn get_as_kv(&self, k: &str) -> Option<String> { fn get_as_kv(&self, k: &str) -> Option<String> {
let Meta::NameValue(MetaNameValue{path, lit:Lit::Str(lit), ..}) = self else { let Meta::NameValue(MetaNameValue{path, value: syn::Expr::Lit(exprlit), ..}) = self else {
return None; return None;
}; };
let syn::Lit::Str(litstr) = &exprlit.lit else { return None; };
if path.is_ident(k) { if path.is_ident(k) {
Some(lit.value()) Some(litstr.value())
} else { } else {
None None
} }

View File

@ -1,7 +1,7 @@
use heck::ToSnakeCase; use heck::ToSnakeCase;
use proc_macro2::{Ident, TokenStream}; use proc_macro2::{Ident, TokenStream};
use quote::{quote, quote_spanned}; use quote::{quote, quote_spanned};
use syn::{punctuated::Punctuated, token::Comma, Data, DataEnum, Fields, Lit, Meta, Variant}; use syn::{Data, DataEnum, Expr, Fields, LitStr, Variant};
/// Method to derive a Primary Key for a Model using the [PrimaryKeyTrait](sea_orm::PrimaryKeyTrait) /// Method to derive a Primary Key for a Model using the [PrimaryKeyTrait](sea_orm::PrimaryKeyTrait)
pub fn expand_derive_primary_key(ident: Ident, data: Data) -> syn::Result<TokenStream> { pub fn expand_derive_primary_key(ident: Ident, data: Data) -> syn::Result<TokenStream> {
@ -34,31 +34,26 @@ pub fn expand_derive_primary_key(ident: Ident, data: Data) -> syn::Result<TokenS
.map(|v| { .map(|v| {
let mut column_name = v.ident.to_string().to_snake_case(); let mut column_name = v.ident.to_string().to_snake_case();
for attr in v.attrs.iter() { for attr in v.attrs.iter() {
if let Some(ident) = attr.path.get_ident() { if !attr.path().is_ident("sea_orm") {
if ident != "sea_orm" {
continue;
}
} else {
continue; continue;
} }
if let Ok(list) = attr.parse_args_with(Punctuated::<Meta, Comma>::parse_terminated)
{ attr.parse_nested_meta(|meta| {
for meta in list.iter() { if meta.path.is_ident("column_name") {
if let Meta::NameValue(nv) = meta { column_name = meta.value()?.parse::<LitStr>()?.value();
if let Some(name) = nv.path.get_ident() { } else {
if name == "column_name" { // Reads the value expression to advance the parse stream.
if let Lit::Str(litstr) = &nv.lit { // Some parameters, such as `primary_key`, do not have any value,
column_name = litstr.value(); // so ignoring an error occurred here.
} let _: Option<Expr> = meta.value().and_then(|v| v.parse()).ok();
}
}
}
} }
}
Ok(())
})?;
} }
quote! { #column_name } Ok::<TokenStream, syn::Error>(quote! { #column_name })
}) })
.collect(); .collect::<Result<_, _>>()?;
Ok(quote!( Ok(quote!(
#[automatically_derived] #[automatically_derived]

View File

@ -4,7 +4,7 @@ use syn::{punctuated::Punctuated, token::Comma, Field, Ident, Meta};
pub(crate) fn field_not_ignored(field: &Field) -> bool { pub(crate) fn field_not_ignored(field: &Field) -> bool {
for attr in field.attrs.iter() { for attr in field.attrs.iter() {
if let Some(ident) = attr.path.get_ident() { if let Some(ident) = attr.path().get_ident() {
if ident != "sea_orm" { if ident != "sea_orm" {
continue; continue;
} }

View File

@ -1,12 +1,11 @@
use proc_macro2::{Span, TokenStream}; use proc_macro2::TokenStream;
use syn::{ use syn::{
parenthesized, parenthesized,
parse::{Parse, ParseStream}, parse::{Parse, ParseStream},
parse2, parse_str, parse2, parse_str,
punctuated::Punctuated, punctuated::Punctuated,
spanned::Spanned, Attribute, DeriveInput, Expr, ExprLit, Ident, Lit, LitBool, LitStr, Meta, MetaNameValue, Path,
Attribute, DeriveInput, Ident, Lit, LitBool, LitStr, Meta, MetaNameValue, Path, Token, Variant, Token, Variant, Visibility,
Visibility,
}; };
use super::case_style::CaseStyle; use super::case_style::CaseStyle;
@ -76,17 +75,6 @@ impl Parse for EnumMeta {
} }
} }
impl Spanned for EnumMeta {
fn span(&self) -> Span {
match self {
EnumMeta::SerializeAll { kw, .. } => kw.span(),
EnumMeta::AsciiCaseInsensitive(kw) => kw.span(),
EnumMeta::Crate { kw, .. } => kw.span(),
EnumMeta::UsePhf(use_phf) => use_phf.span(),
}
}
}
pub enum EnumDiscriminantsMeta { pub enum EnumDiscriminantsMeta {
Derive { kw: kw::derive, paths: Vec<Path> }, Derive { kw: kw::derive, paths: Vec<Path> },
Name { kw: kw::name, name: Ident }, Name { kw: kw::name, name: Ident },
@ -100,7 +88,7 @@ impl Parse for EnumDiscriminantsMeta {
let kw = input.parse()?; let kw = input.parse()?;
let content; let content;
parenthesized!(content in input); parenthesized!(content in input);
let paths = content.parse_terminated::<_, Token![,]>(Path::parse)?; let paths = content.parse_terminated(Path::parse, Token![,])?;
Ok(EnumDiscriminantsMeta::Derive { Ok(EnumDiscriminantsMeta::Derive {
kw, kw,
paths: paths.into_iter().collect(), paths: paths.into_iter().collect(),
@ -127,17 +115,6 @@ impl Parse for EnumDiscriminantsMeta {
} }
} }
impl Spanned for EnumDiscriminantsMeta {
fn span(&self) -> Span {
match self {
EnumDiscriminantsMeta::Derive { kw, .. } => kw.span,
EnumDiscriminantsMeta::Name { kw, .. } => kw.span,
EnumDiscriminantsMeta::Vis { kw, .. } => kw.span,
EnumDiscriminantsMeta::Other { path, .. } => path.span(),
}
}
}
pub trait DeriveInputExt { pub trait DeriveInputExt {
/// Get all the strum metadata associated with an enum. /// Get all the strum metadata associated with an enum.
fn get_metadata(&self) -> syn::Result<Vec<EnumMeta>>; fn get_metadata(&self) -> syn::Result<Vec<EnumMeta>>;
@ -228,7 +205,7 @@ impl Parse for VariantMeta {
let kw = input.parse()?; let kw = input.parse()?;
let content; let content;
parenthesized!(content in input); parenthesized!(content in input);
let props = content.parse_terminated::<_, Token![,]>(Prop::parse)?; let props = content.parse_terminated(Prop::parse, Token![,])?;
Ok(VariantMeta::Props { Ok(VariantMeta::Props {
kw, kw,
props: props props: props
@ -256,22 +233,6 @@ impl Parse for Prop {
} }
} }
impl Spanned for VariantMeta {
fn span(&self) -> Span {
match self {
VariantMeta::Message { kw, .. } => kw.span,
VariantMeta::DetailedMessage { kw, .. } => kw.span,
VariantMeta::Documentation { value } => value.span(),
VariantMeta::Serialize { kw, .. } => kw.span,
VariantMeta::ToString { kw, .. } => kw.span,
VariantMeta::Disabled(kw) => kw.span,
VariantMeta::Default(kw) => kw.span,
VariantMeta::AsciiCaseInsensitive { kw, .. } => kw.span,
VariantMeta::Props { kw, .. } => kw.span,
}
}
}
pub trait VariantExt { pub trait VariantExt {
/// Get all the metadata associated with an enum variant. /// Get all the metadata associated with an enum variant.
fn get_metadata(&self) -> syn::Result<Vec<VariantMeta>>; fn get_metadata(&self) -> syn::Result<Vec<VariantMeta>>;
@ -282,26 +243,32 @@ impl VariantExt for Variant {
let result = get_metadata_inner("strum", &self.attrs)?; let result = get_metadata_inner("strum", &self.attrs)?;
self.attrs self.attrs
.iter() .iter()
.filter(|attr| attr.path.is_ident("doc")) .filter(|attr| attr.path().is_ident("doc"))
.try_fold(result, |mut vec, attr| { .try_fold(result, |mut vec, attr| {
if let Meta::NameValue(MetaNameValue { if let Meta::NameValue(MetaNameValue {
lit: Lit::Str(value), value:
Expr::Lit(ExprLit {
lit: Lit::Str(value),
..
}),
.. ..
}) = attr.parse_meta()? }) = &attr.meta
{ {
vec.push(VariantMeta::Documentation { value }) vec.push(VariantMeta::Documentation {
value: value.clone(),
})
} }
Ok(vec) Ok(vec)
}) })
} }
} }
fn get_metadata_inner<'a, T: Parse + Spanned>( fn get_metadata_inner<'a, T: Parse>(
ident: &str, ident: &str,
it: impl IntoIterator<Item = &'a Attribute>, it: impl IntoIterator<Item = &'a Attribute>,
) -> syn::Result<Vec<T>> { ) -> syn::Result<Vec<T>> {
it.into_iter() it.into_iter()
.filter(|attr| attr.path.is_ident(ident)) .filter(|attr| attr.path().is_ident(ident))
.try_fold(Vec::new(), |mut vec, attr| { .try_fold(Vec::new(), |mut vec, attr| {
vec.extend(attr.parse_args_with(Punctuated::<T, Token![,]>::parse_terminated)?); vec.extend(attr.parse_args_with(Punctuated::<T, Token![,]>::parse_terminated)?);
Ok(vec) Ok(vec)