Add #[sea_orm(skip)] for FromQueryResult macro (#1954)

* Add #[sea_orm(skip)] for FromQueryResult macro

* Update sea-orm-rocket

* Revert "Update sea-orm-rocket"

This reverts commit b7226bb44dbdbab9782524feb0303c4c166d3050.
This commit is contained in:
Wyatt Herkamp 2023-11-08 10:45:38 -05:00 committed by GitHub
parent c81f4d3705
commit b4010ecb64
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 71 additions and 17 deletions

View File

@ -1,6 +1,29 @@
use self::util::GetMeta;
use proc_macro2::{Ident, TokenStream}; use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote, quote_spanned}; use quote::{format_ident, quote, quote_spanned, ToTokens};
use syn::{ext::IdentExt, Data, DataStruct, Field, Fields, Generics}; use syn::{
ext::IdentExt, punctuated::Punctuated, token::Comma, Data, DataStruct, Fields, Generics, Meta,
};
pub struct FromQueryResultItem {
pub skip: bool,
pub ident: Ident,
}
impl ToTokens for FromQueryResultItem {
fn to_tokens(&self, tokens: &mut TokenStream) {
let Self { ident, skip } = self;
if *skip {
tokens.extend(quote! {
#ident: std::default::Default::default(),
});
} else {
let name = ident.unraw().to_string();
tokens.extend(quote! {
#ident: row.try_get(pre, #name)?,
});
}
}
}
/// Method to derive a [QueryResult](sea_orm::QueryResult) /// Method to derive a [QueryResult](sea_orm::QueryResult)
pub fn expand_derive_from_query_result( pub fn expand_derive_from_query_result(
@ -19,20 +42,23 @@ pub fn expand_derive_from_query_result(
}) })
} }
}; };
let mut field = Vec::with_capacity(fields.len());
let field: Vec<Ident> = fields for parsed_field in fields.into_iter() {
.into_iter() let mut skip = false;
.map(|Field { ident, .. }| format_ident!("{}", ident.unwrap().to_string())) for attr in parsed_field.attrs.iter() {
.collect(); if !attr.path().is_ident("sea_orm") {
continue;
let name: Vec<TokenStream> = field }
.iter() if let Ok(list) = attr.parse_args_with(Punctuated::<Meta, Comma>::parse_terminated) {
.map(|f| { for meta in list.iter() {
let s = f.unraw().to_string(); skip = meta.exists("skip");
quote! { #s } }
}) }
.collect(); }
let ident = format_ident!("{}", parsed_field.ident.unwrap().to_string());
field.push(FromQueryResultItem { skip, ident });
}
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
Ok(quote!( Ok(quote!(
@ -40,9 +66,25 @@ pub fn expand_derive_from_query_result(
impl #impl_generics sea_orm::FromQueryResult for #ident #ty_generics #where_clause { impl #impl_generics sea_orm::FromQueryResult for #ident #ty_generics #where_clause {
fn from_query_result(row: &sea_orm::QueryResult, pre: &str) -> std::result::Result<Self, sea_orm::DbErr> { fn from_query_result(row: &sea_orm::QueryResult, pre: &str) -> std::result::Result<Self, sea_orm::DbErr> {
Ok(Self { Ok(Self {
#(#field: row.try_get(pre, #name)?),* #(#field)*
}) })
} }
} }
)) ))
} }
mod util {
use syn::Meta;
pub(super) trait GetMeta {
fn exists(&self, k: &str) -> bool;
}
impl GetMeta for Meta {
fn exists(&self, k: &str) -> bool {
let Meta::Path(path) = self else {
return false;
};
path.is_ident(k)
}
}
}

View File

@ -579,6 +579,9 @@ pub fn derive_active_enum(input: TokenStream) -> TokenStream {
/// Convert a query result into the corresponding Model. /// Convert a query result into the corresponding Model.
/// ///
/// ### Attributes
/// - `skip`: Will not try to pull this field from the query result. And set it to the default value of the type.
///
/// ### Usage /// ### Usage
/// ///
/// ``` /// ```
@ -588,10 +591,12 @@ pub fn derive_active_enum(input: TokenStream) -> TokenStream {
/// struct SelectResult { /// struct SelectResult {
/// name: String, /// name: String,
/// num_of_fruits: i32, /// num_of_fruits: i32,
/// #[sea_orm(skip)]
/// skip_me: i32,
/// } /// }
/// ``` /// ```
#[cfg(feature = "derive")] #[cfg(feature = "derive")]
#[proc_macro_derive(FromQueryResult)] #[proc_macro_derive(FromQueryResult, attributes(sea_orm))]
pub fn derive_from_query_result(input: TokenStream) -> TokenStream { pub fn derive_from_query_result(input: TokenStream) -> TokenStream {
let DeriveInput { let DeriveInput {
ident, ident,

View File

@ -56,3 +56,10 @@ where
{ {
_foo: T::Item, _foo: T::Item,
} }
#[derive(FromQueryResult)]
struct FromQueryAttributeTests {
#[sea_orm(skip)]
_foo: i32,
_bar: String,
}