Merge pull request #99 from SeaQL/impl-col-from-str

Implement `FromStr` for `DeriveColumn`
This commit is contained in:
Chris Tsang 2021-08-23 01:43:19 +08:00 committed by GitHub
commit a15ec27a0e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 76 additions and 2 deletions

View File

@ -1,4 +1,4 @@
use heck::SnakeCase; use heck::{MixedCase, SnakeCase};
use proc_macro2::{Ident, TokenStream}; use proc_macro2::{Ident, TokenStream};
use quote::{quote, quote_spanned}; use quote::{quote, quote_spanned};
use syn::{Data, DataEnum, Fields, Variant}; use syn::{Data, DataEnum, Fields, Variant};
@ -41,6 +41,39 @@ pub fn impl_default_as_str(ident: &Ident, data: &Data) -> syn::Result<TokenStrea
)) ))
} }
pub fn impl_col_from_str(ident: &Ident, data: &Data) -> syn::Result<TokenStream> {
let data_enum = match data {
Data::Enum(data_enum) => data_enum,
_ => {
return Ok(quote_spanned! {
ident.span() => compile_error!("you can only derive DeriveColumn on enums");
})
}
};
let columns = data_enum.variants.iter().map(|column| {
let column_iden = column.ident.clone();
let column_str_snake = column_iden.to_string().to_snake_case();
let column_str_mixed = column_iden.to_string().to_mixed_case();
quote!(
#column_str_snake | #column_str_mixed => Ok(#ident::#column_iden)
)
});
Ok(quote!(
impl std::str::FromStr for #ident {
type Err = sea_orm::ColumnFromStrErr;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
#(#columns),*,
_ => Err(sea_orm::ColumnFromStrErr(format!("Failed to parse '{}' as `{}`", s, stringify!(#ident)))),
}
}
}
))
}
pub fn expand_derive_column(ident: &Ident, data: &Data) -> syn::Result<TokenStream> { pub fn expand_derive_column(ident: &Ident, data: &Data) -> syn::Result<TokenStream> {
let impl_iden = expand_derive_custom_column(ident, data)?; let impl_iden = expand_derive_custom_column(ident, data)?;
@ -57,10 +90,13 @@ pub fn expand_derive_column(ident: &Ident, data: &Data) -> syn::Result<TokenStre
pub fn expand_derive_custom_column(ident: &Ident, data: &Data) -> syn::Result<TokenStream> { pub fn expand_derive_custom_column(ident: &Ident, data: &Data) -> syn::Result<TokenStream> {
let impl_default_as_str = impl_default_as_str(ident, data)?; let impl_default_as_str = impl_default_as_str(ident, data)?;
let impl_col_from_str = impl_col_from_str(ident, data)?;
Ok(quote!( Ok(quote!(
#impl_default_as_str #impl_default_as_str
#impl_col_from_str
impl sea_orm::Iden for #ident { impl sea_orm::Iden for #ident {
fn unquoted(&self, s: &mut dyn std::fmt::Write) { fn unquoted(&self, s: &mut dyn std::fmt::Write) {
write!(s, "{}", self.as_str()).unwrap(); write!(s, "{}", self.as_str()).unwrap();

View File

@ -1,3 +1,4 @@
use std::str::FromStr;
use crate::{EntityName, IdenStatic, Iterable}; use crate::{EntityName, IdenStatic, Iterable};
use sea_query::{DynIden, Expr, SeaRc, SelectStatement, SimpleExpr, Value}; use sea_query::{DynIden, Expr, SeaRc, SelectStatement, SimpleExpr, Value};
@ -77,7 +78,7 @@ macro_rules! bind_subquery_func {
// LINT: when the operand value does not match column type // LINT: when the operand value does not match column type
/// Wrapper of the identically named method in [`sea_query::Expr`] /// Wrapper of the identically named method in [`sea_query::Expr`]
pub trait ColumnTrait: IdenStatic + Iterable { pub trait ColumnTrait: IdenStatic + Iterable + FromStr {
type EntityName: EntityName; type EntityName: EntityName;
fn def(&self) -> ColumnDef; fn def(&self) -> ColumnDef;
@ -348,4 +349,30 @@ mod tests {
.join(" ") .join(" ")
); );
} }
#[test]
fn test_col_from_str() {
use std::str::FromStr;
assert!(matches!(
fruit::Column::from_str("id"),
Ok(fruit::Column::Id)
));
assert!(matches!(
fruit::Column::from_str("name"),
Ok(fruit::Column::Name)
));
assert!(matches!(
fruit::Column::from_str("cake_id"),
Ok(fruit::Column::CakeId)
));
assert!(matches!(
fruit::Column::from_str("cakeId"),
Ok(fruit::Column::CakeId)
));
assert!(matches!(
fruit::Column::from_str("does_not_exist"),
Err(crate::ColumnFromStrErr(_))
));
}
} }

View File

@ -16,3 +16,14 @@ impl std::fmt::Display for DbErr {
} }
} }
} }
#[derive(Debug, Clone)]
pub struct ColumnFromStrErr(pub String);
impl std::error::Error for ColumnFromStrErr {}
impl std::fmt::Display for ColumnFromStrErr {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.0.as_str())
}
}