Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: added map method to query builders #45

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
27 changes: 6 additions & 21 deletions src/chain.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use near_primitives::{
types::{BlockHeight, BlockReference},
views::BlockView,
};
use near_primitives::types::{BlockHeight, BlockReference};

use crate::{
common::query::{BlockQueryBuilder, PostprocessHandler, RpcBlockHandler, SimpleBlockRpc},
Expand Down Expand Up @@ -53,14 +50,8 @@ impl Chain {
/// # }
/// ```
pub fn block_number() -> BlockQueryBuilder<PostprocessHandler<BlockHeight, RpcBlockHandler>> {
BlockQueryBuilder::new(
SimpleBlockRpc,
BlockReference::latest(),
PostprocessHandler::new(
RpcBlockHandler,
Box::new(|data: BlockView| data.header.height),
),
)
BlockQueryBuilder::new(SimpleBlockRpc, BlockReference::latest(), RpcBlockHandler)
.map(|data| data.header.height)
}

/// Set ups a query to fetch the [CryptoHash] of the block
Expand Down Expand Up @@ -89,17 +80,11 @@ impl Chain {
/// # }
/// ```
pub fn block_hash() -> BlockQueryBuilder<PostprocessHandler<CryptoHash, RpcBlockHandler>> {
BlockQueryBuilder::new(
SimpleBlockRpc,
BlockReference::latest(),
PostprocessHandler::new(
RpcBlockHandler,
Box::new(|data: BlockView| data.header.hash.into()),
),
)
BlockQueryBuilder::new(SimpleBlockRpc, BlockReference::latest(), RpcBlockHandler)
.map(|data| data.header.hash.into())
}

/// Set ups a query to fetch the [BlockView]
/// Set ups a query to fetch the [BlockView][near_primitives::views::BlockView]
///
/// ## Fetching the latest block
///
Expand Down
54 changes: 54 additions & 0 deletions src/common/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,14 @@ pub type MultiQueryBuilder<T> = MultiRpcBuilder<T, RpcQueryRequest, BlockReferen
pub type ValidatorQueryBuilder<T> = RpcBuilder<T, RpcValidatorRequest, EpochReference>;
pub type BlockQueryBuilder<T> = RpcBuilder<T, RpcBlockRequest, BlockReference>;

/// A builder for querying multiple items at once.
///
/// Sometimes to construct some complex type, you would need to query multiple items at once, and combine them into one.
/// This is where this builder comes in handy. Almost every time, you would want to use [Self::map] method to combine the responses into your desired type.
///
/// Here is a list of examples on how to use this:
/// - [Tokens::ft_balance](crate::tokens::Tokens::ft_balance)
/// - [StakingPool::staking_pool_info](crate::stake::Staking::staking_pool_info)
pub struct MultiRpcBuilder<Handler, Method, Reference>
where
Reference: Send + Sync,
Expand All @@ -173,6 +181,22 @@ where
}
}

/// Map response of the queries to another type. The `map` function is executed after the queries are fetched.
///
/// The response is a tuple of the responses of the queries.
///
/// See [Tokens::ft_balance](crate::tokens::Tokens::ft_balance) implementation for an example on how to use this.
pub fn map<MappedType>(
self,
map: impl Fn(Handler::Response) -> MappedType + Send + Sync + 'static,
) -> MultiRpcBuilder<PostprocessHandler<MappedType, Handler>, Method, Reference> {
MultiRpcBuilder {
handler: PostprocessHandler::new(self.handler, map),
requests: self.requests,
reference: self.reference,
}
}

/// Add a query to the queried items. Sometimes you might need to query multiple items at once.
/// To combine the result of multiple queries into one.
pub fn add_query(
Expand Down Expand Up @@ -298,6 +322,36 @@ where
}
}

/// Post-process the response of the query.
///
/// This is useful if you want to convert one type to another.
///
/// ## Example
/// ```rust,no_run
/// use near_api::*;
///
/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
/// let balance: NearToken = Contract("some_contract.testnet".parse()?)
/// .call_function("get_balance", ())?
/// .read_only()
/// .map(|balance: Data<u128>| NearToken::from_yoctonear(balance.data))
/// .fetch_from_testnet()
/// .await?;
/// println!("Balance: {}", balance);
/// # Ok(())
/// # }
/// ```
pub fn map<MappedType>(
self,
map: impl Fn(Handler::Response) -> MappedType + Send + Sync + 'static,
) -> RpcBuilder<PostprocessHandler<MappedType, Handler>, Method, Reference> {
RpcBuilder {
handler: PostprocessHandler::new(self.handler, map),
request: self.request,
reference: self.reference,
}
}

/// Fetch the query from the provided network.
#[instrument(skip(self, network))]
pub async fn fetch_from(
Expand Down
23 changes: 6 additions & 17 deletions src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,23 +157,12 @@ impl Contract {
&self,
) -> QueryBuilder<PostprocessHandler<Option<near_abi::AbiRoot>, CallResultHandler<Vec<u8>>>>
{
let request = near_primitives::views::QueryRequest::CallFunction {
account_id: self.0.clone(),
method_name: "__contract_abi".to_owned(),
args: near_primitives::types::FunctionArgs::from(vec![]),
};

QueryBuilder::new(
SimpleQuery { request },
BlockReference::latest(),
PostprocessHandler::new(
CallResultHandler::default(),
Box::new(|data: Data<Vec<u8>>| {
serde_json::from_slice(zstd::decode_all(data.data.as_slice()).ok()?.as_slice())
.ok()
}),
),
)
self.call_function("__contract_abi", ())
.expect("arguments are always serializable")
.read_only()
.map(|data: Data<Vec<u8>>| {
serde_json::from_slice(zstd::decode_all(data.data.as_slice()).ok()?.as_slice()).ok()
})
}

/// Prepares a query to fetch the wasm code ([Data]<[ContractCodeView](near_primitives::views::ContractCodeView)>) of the contract.
Expand Down
4 changes: 2 additions & 2 deletions src/fastnear.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ impl<T, PostProcessed> FastNearBuilder<T, PostProcessed>
where
T: DeserializeOwned + Send + Sync,
{
pub fn with_postprocess<F>(query: String, func: F) -> Self
pub fn map<F>(query: String, func: F) -> Self
where
F: Fn(T) -> PostProcessed + Send + Sync + 'static,
{
Expand Down Expand Up @@ -67,7 +67,7 @@ impl FastNear {
&self,
account_id: &AccountId,
) -> Result<FastNearBuilder<StakingResponse, BTreeSet<AccountId>>, FastNearError> {
let query_builder = FastNearBuilder::with_postprocess(
let query_builder = FastNearBuilder::map(
format!("v1/account/{}/staking", account_id),
|response: StakingResponse| {
response
Expand Down
Loading
Loading