Fix optional store items. (#120)

* Fix optional store items.

* Support querying a block hash.
This commit is contained in:
David Craven
2020-06-01 13:24:56 +02:00
committed by GitHub
parent a2eead0c3d
commit 26ada75dec
8 changed files with 94 additions and 38 deletions
+20 -6
View File
@@ -49,11 +49,16 @@ impl Parse for StoreAttr {
type StoreAttrs = utils::Attrs<StoreAttr>;
fn parse_returns_attr(attr: &syn::Attribute) -> Option<syn::Type> {
fn parse_returns_attr(attr: &syn::Attribute) -> Option<(syn::Type, syn::Type, bool)> {
let attrs: StoreAttrs = syn::parse2(attr.tokens.clone()).unwrap();
attrs.attrs.into_iter().next().map(|attr| {
let StoreAttr::Returns(attr) = attr;
attr.value
let ty = attr.value;
if let Some(inner) = utils::parse_option(&ty) {
(ty, inner, false)
} else {
(ty.clone(), ty, true)
}
})
}
@@ -72,11 +77,16 @@ pub fn store(s: Structure) -> TokenStream {
let filtered_fields = utils::filter_fields(&fields, &marker);
let args = utils::fields_to_args(&filtered_fields);
let build_struct = utils::build_struct(ident, &fields);
let ret = bindings
let (ret, store_ret, uses_default) = bindings
.iter()
.filter_map(|bi| bi.ast().attrs.iter().filter_map(parse_returns_attr).next())
.next()
.expect("#[store(returns = ..)] needs to be specified.");
let fetch = if uses_default {
quote!(fetch_or_default)
} else {
quote!(fetch)
};
let store_ty = format_ident!(
"{}",
match filtered_fields.len() {
@@ -94,7 +104,7 @@ pub fn store(s: Structure) -> TokenStream {
impl#generics #subxt::Store<T> for #ident<#(#params),*> {
const MODULE: &'static str = MODULE;
const FIELD: &'static str = #store_name;
type Returns = #ret;
type Returns = #store_ret;
fn key(
&self,
metadata: &#subxt::Metadata,
@@ -113,6 +123,7 @@ pub fn store(s: Structure) -> TokenStream {
fn #store<'a>(
&'a self,
#args
hash: Option<T::Hash>,
) -> core::pin::Pin<Box<dyn core::future::Future<Output = Result<#ret, #subxt::Error>> + Send + 'a>>;
}
@@ -125,9 +136,10 @@ pub fn store(s: Structure) -> TokenStream {
fn #store<'a>(
&'a self,
#args
hash: Option<T::Hash>,
) -> core::pin::Pin<Box<dyn core::future::Future<Output = Result<#ret, #subxt::Error>> + Send + 'a>> {
let #marker = core::marker::PhantomData::<T>;
Box::pin(self.fetch(#build_struct, None))
Box::pin(self.#fetch(#build_struct, hash))
}
}
}
@@ -169,6 +181,7 @@ mod tests {
fn account<'a>(
&'a self,
account_id: &'a <T as System>::AccountId,
hash: Option<T::Hash>,
) -> core::pin::Pin<Box<dyn core::future::Future<Output = Result<AccountData<T::Balance>, substrate_subxt::Error>> + Send + 'a>>;
}
@@ -181,10 +194,11 @@ mod tests {
fn account<'a>(
&'a self,
account_id: &'a <T as System>::AccountId,
hash: Option<T::Hash>,
) -> core::pin::Pin<Box<dyn core::future::Future<Output = Result<AccountData<T::Balance>, substrate_subxt::Error>> + Send + 'a>>
{
let _ = core::marker::PhantomData::<T>;
Box::pin(self.fetch(AccountStore { account_id, }, None))
Box::pin(self.fetch_or_default(AccountStore { account_id, }, hash))
}
}
};
+5 -5
View File
@@ -330,7 +330,7 @@ impl Step {
};
let build_struct = quote! {
#(
let #state_name = client.fetch(#state, None).await.unwrap();
let #state_name = client.fetch_or_default(#state, None).await.unwrap();
)*
State { #(#state_name),* }
};
@@ -477,11 +477,11 @@ mod tests {
let pre = {
let alice = client
.fetch(AccountStore { account_id: &alice }, None)
.fetch_or_default(AccountStore { account_id: &alice }, None)
.await
.unwrap();
let bob = client
.fetch(AccountStore { account_id: &bob }, None)
.fetch_or_default(AccountStore { account_id: &bob }, None)
.await
.unwrap();
State { alice, bob }
@@ -510,11 +510,11 @@ mod tests {
let post = {
let alice = client
.fetch(AccountStore { account_id: &alice }, None)
.fetch_or_default(AccountStore { account_id: &alice }, None)
.await
.unwrap();
let bob = client
.fetch(AccountStore { account_id: &bob }, None)
.fetch_or_default(AccountStore { account_id: &bob }, None)
.await
.unwrap();
State { alice, bob }
+28
View File
@@ -167,6 +167,21 @@ pub fn type_params(generics: &syn::Generics) -> Vec<TokenStream> {
.collect()
}
pub fn parse_option(ty: &syn::Type) -> Option<syn::Type> {
if let syn::Type::Path(ty_path) = ty {
if let Some(seg) = ty_path.path.segments.first() {
if seg.ident.to_string() == "Option" {
if let syn::PathArguments::AngleBracketed(args) = &seg.arguments {
if let Some(syn::GenericArgument::Type(ty)) = args.args.first() {
return Some(ty.clone())
}
}
}
}
}
None
}
#[derive(Debug)]
pub struct Attrs<A> {
pub paren: syn::token::Paren,
@@ -209,3 +224,16 @@ pub(crate) fn assert_proc_macro(
let expected = expected.to_string();
pretty_assertions::assert_eq!(result, expected);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_option() {
let option_t: syn::Type = syn::parse2(quote!(Option<T>)).unwrap();
let t: syn::Type = syn::parse2(quote!(T)).unwrap();
assert_eq!(parse_option(&option_t), Some(t.clone()));
assert_eq!(parse_option(&t), None);
}
}