Skip to content

Commit

Permalink
Add KeyIter.
Browse files Browse the repository at this point in the history
  • Loading branch information
dvc94ch committed Aug 4, 2020
1 parent 1f3fab1 commit 694a396
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 21 deletions.
9 changes: 5 additions & 4 deletions examples/fetch_all_accounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ use substrate_subxt::{
async fn main() -> Result<(), Box<dyn std::error::Error>> {
env_logger::init();

let _client = ClientBuilder::<DefaultNodeRuntime>::new().build().await?;
// for (key, account) in client.accounts_iter() {
// println!("{}: {}", key, account)
// }
let client = ClientBuilder::<DefaultNodeRuntime>::new().build().await?;
let mut iter = client.accounts_iter();
while let Some((key, account)) = iter.next().await? {
println!("{}: {}", key, account);
}
Ok(())
}
2 changes: 1 addition & 1 deletion proc-macro/src/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ pub fn store(s: Structure) -> TokenStream {
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, hash))
Box::pin(async move { self.#fetch(&#build_struct, hash).await })
}
}
}
Expand Down
87 changes: 72 additions & 15 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ pub struct ClientBuilder<T: Runtime> {
_marker: std::marker::PhantomData<T>,
url: Option<String>,
client: Option<jsonrpsee::Client>,
page_size: Option<u32>,
}

impl<T: Runtime> ClientBuilder<T> {
Expand All @@ -124,6 +125,7 @@ impl<T: Runtime> ClientBuilder<T> {
_marker: std::marker::PhantomData,
url: None,
client: None,
page_size: None,
}
}

Expand All @@ -139,6 +141,12 @@ impl<T: Runtime> ClientBuilder<T> {
self
}

/// Set the page size.
pub fn set_page_size(mut self, size: u32) -> Self {
self.page_size = Some(size);
self
}

/// Creates a new Client.
pub async fn build(self) -> Result<Client<T>, Error> {
let client = if let Some(client) = self.client {
Expand All @@ -164,6 +172,7 @@ impl<T: Runtime> ClientBuilder<T> {
metadata: metadata?,
runtime_version: runtime_version?,
_marker: PhantomData,
page_size: self.page_size.unwrap_or(10),
})
}
}
Expand All @@ -175,6 +184,7 @@ pub struct Client<T: Runtime> {
metadata: Metadata,
runtime_version: RuntimeVersion,
_marker: PhantomData<(fn() -> T::Signature, T::Extra)>,
page_size: u32,
}

impl<T: Runtime> Clone for Client<T> {
Expand All @@ -185,6 +195,42 @@ impl<T: Runtime> Clone for Client<T> {
metadata: self.metadata.clone(),
runtime_version: self.runtime_version.clone(),
_marker: PhantomData,
page_size: self.page_size,
}
}
}

/// Iterates over key value pairs in a map.
pub struct KeyIter<T: Runtime, F: Store<T>> {
client: Client<T>,
_marker: PhantomData<F>,
count: u32,
hash: Option<T::Hash>,
start_key: Option<StorageKey>,
keys: Vec<StorageKey>,
}

impl<T: Runtime, F: Store<T>> KeyIter<T, F> {
/// Returns the next key value pair from a map.
pub async fn next(&mut self) -> Result<Option<(StorageKey, F::Returns)>, Error> {
loop {
if let Some(key) = self.keys.pop() {
if let Some(value) = self.client.rpc.storage(&key, self.hash).await? {
return Ok(Some((key, Decode::decode(&mut &value.0[..])?)))
}
} else {
self.keys = self
.client
.fetch_keys::<F>(self.count, self.start_key.take(), self.hash)
.await?
.into_iter()
.rev()
.collect();
if self.keys.is_empty() {
return Ok(None)
}
self.start_key = self.keys.first().cloned();
}
}
}
}
Expand All @@ -200,31 +246,42 @@ impl<T: Runtime> Client<T> {
&self.metadata
}

/// Fetch a StorageKey with default value.
pub async fn fetch_or_default<F: Store<T>>(
/// Fetch a StorageKey an optional storage key.
pub async fn fetch<F: Store<T>>(
&self,
store: F,
store: &F,
hash: Option<T::Hash>,
) -> Result<F::Returns, Error> {
) -> Result<Option<F::Returns>, Error> {
let key = store.key(&self.metadata)?;
if let Some(data) = self.rpc.storage(key, hash).await? {
Ok(Decode::decode(&mut &data.0[..])?)
if let Some(data) = self.rpc.storage(&key, hash).await? {
Ok(Some(Decode::decode(&mut &data.0[..])?))
} else {
Ok(store.default(&self.metadata)?)
Ok(None)
}
}

/// Fetch a StorageKey an optional storage key.
pub async fn fetch<F: Store<T>>(
/// Fetch a StorageKey with default value.
pub async fn fetch_or_default<F: Store<T>>(
&self,
store: F,
store: &F,
hash: Option<T::Hash>,
) -> Result<Option<F::Returns>, Error> {
let key = store.key(&self.metadata)?;
if let Some(data) = self.rpc.storage(key, hash).await? {
Ok(Some(Decode::decode(&mut &data.0[..])?))
) -> Result<F::Returns, Error> {
if let Some(data) = self.fetch(store, hash).await? {
Ok(data)
} else {
Ok(None)
Ok(store.default(&self.metadata)?)
}
}

/// Returns an iterator of key value pairs.
pub fn iter<F: Store<T>>(&self, hash: Option<T::Hash>) -> KeyIter<T, F> {
KeyIter {
client: self.clone(),
hash,
count: self.page_size,
start_key: None,
keys: Default::default(),
_marker: PhantomData,
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ impl<T: Runtime> Rpc<T> {
/// Fetch a storage key
pub async fn storage(
&self,
key: StorageKey,
key: &StorageKey,
hash: Option<T::Hash>,
) -> Result<Option<StorageData>, Error> {
let params = Params::Array(vec![to_json_value(key)?, to_json_value(hash)?]);
Expand Down

0 comments on commit 694a396

Please sign in to comment.