Skip to content

Commit

Permalink
[refactor] hyperledger#3124: Introduced Query request builder into Cl…
Browse files Browse the repository at this point in the history
…ient API

Signed-off-by: Vladimir Pesterev <8786922+pesterev@users.noreply.github.com>
  • Loading branch information
pesterev committed Oct 27, 2023
1 parent 8018332 commit 845f04d
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 145 deletions.
132 changes: 3 additions & 129 deletions client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ use self::{blocks_api::AsyncBlockStream, events_api::AsyncEventStream};
use crate::{
http::{Method as HttpMethod, RequestBuilder, Response, StatusCode},
http_default::{self, DefaultRequestBuilder, WebSocketError, WebSocketMessage},
query_builder::QueryRequestBuilder,
};

const APPLICATION_JSON: &str = "application/json";
Expand Down Expand Up @@ -847,139 +848,12 @@ impl Client {
Ok(output)
}

/// Create a request with pagination and sorting.
///
/// # Errors
/// Fails if sending request fails
pub fn request_with_pagination_and_sorting<R: Query + Debug>(
&self,
request: R,
pagination: Pagination,
sorting: Sorting,
) -> QueryResult<<R::Output as QueryOutput>::Target>
where
R::Output: QueryOutput,
<R::Output as TryFrom<Value>>::Error: Into<eyre::Error>,
{
self.request_with_filter_and_pagination_and_sorting(
request,
pagination,
sorting,
PredicateBox::default(),
)
}

/// Create a request with pagination, sorting, and the given filter.
///
/// # Errors
/// Fails if sending request fails
pub fn request_with_filter_and_pagination<R: Query + Debug>(
&self,
request: R,
pagination: Pagination,
filter: PredicateBox,
) -> QueryResult<<R::Output as QueryOutput>::Target>
where
R::Output: QueryOutput,
<R::Output as TryFrom<Value>>::Error: Into<eyre::Error>,
{
self.request_with_filter_and_pagination_and_sorting(
request,
pagination,
Sorting::default(),
filter,
)
}

/// Create a request with sorting and the given filter.
///
/// # Errors
/// Fails if sending request fails
pub fn request_with_filter_and_sorting<R: Query + Debug>(
&self,
request: R,
sorting: Sorting,
filter: PredicateBox,
) -> QueryResult<<R::Output as QueryOutput>::Target>
where
R::Output: QueryOutput,
<R::Output as TryFrom<Value>>::Error: Into<eyre::Error>,
{
self.request_with_filter_and_pagination_and_sorting(
request,
Pagination::default(),
sorting,
filter,
)
}

/// Query API entry point. Requests quieries from `Iroha` peers with filter.
///
/// Uses default blocking http-client. If you need some custom integration, look at
/// [`Self::prepare_query_request`].
///
/// # Errors
/// Fails if sending request fails
pub fn request_with_filter<R: Query + Debug>(
&self,
request: R,
filter: PredicateBox,
) -> QueryResult<<R::Output as QueryOutput>::Target>
where
R::Output: QueryOutput,
<R::Output as TryFrom<Value>>::Error: Into<eyre::Error>,
{
self.request_with_filter_and_pagination(request, Pagination::default(), filter)
}

/// Query API entry point. Requests queries from `Iroha` peers with pagination.
///
/// Uses default blocking http-client. If you need some custom integration, look at
/// [`Self::prepare_query_request`].
///
/// # Errors
/// Fails if sending request fails
pub fn request_with_pagination<R: Query + Debug>(
&self,
request: R,
pagination: Pagination,
) -> QueryResult<<R::Output as QueryOutput>::Target>
where
R::Output: QueryOutput,
<R::Output as TryFrom<Value>>::Error: Into<eyre::Error>,
{
self.request_with_filter_and_pagination(request, pagination, PredicateBox::default())
}

/// Query API entry point. Requests queries from `Iroha` peers with sorting.
///
/// # Errors
/// Fails if sending request fails
pub fn request_with_sorting<R: Query + Debug>(
&self,
request: R,
sorting: Sorting,
) -> QueryResult<<R::Output as QueryOutput>::Target>
where
R::Output: QueryOutput,
<R::Output as TryFrom<Value>>::Error: Into<eyre::Error>,
{
self.request_with_pagination_and_sorting(request, Pagination::default(), sorting)
}

/// Query API entry point. Requests queries from `Iroha` peers.
///
/// # Errors
/// Fails if sending request fails
pub fn request<R: Query + Debug>(
&self,
request: R,
) -> QueryResult<<R::Output as QueryOutput>::Target>
pub fn query<'a, R: Query + Debug>(&'a self, request: R) -> QueryRequestBuilder<'a, R>
where
R::Output: QueryOutput,
<R::Output as TryFrom<Value>>::Error: Into<eyre::Error>,
{
self.request_with_pagination(request, Pagination::default())
QueryRequestBuilder::new(self, request)
}

/// Connect (through `WebSocket`) to listen for `Iroha` `pipeline` and `data` events.
Expand Down
1 change: 1 addition & 0 deletions client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub mod client;
/// Module with general communication primitives like an HTTP request builder.
pub mod http;
mod http_default;
mod query_builder;

/// Module containing sample configurations for tests and benchmarks.
pub mod samples {
Expand Down
58 changes: 58 additions & 0 deletions client/src/query_builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
use std::fmt::Debug;

use iroha_data_model::{
predicate::PredicateBox,
query::{sorting::Sorting, Pagination, Query},
Value,
};

use crate::client::{Client, QueryOutput, QueryResult};

pub struct QueryRequestBuilder<'a, R> {
client: &'a Client,
request: R,
pagination: Pagination,
filter: PredicateBox,
sorting: Sorting,
}

impl<'a, R> QueryRequestBuilder<'a, R>
where
R: Query + Debug,
R::Output: QueryOutput,
<R::Output as TryFrom<Value>>::Error: Into<eyre::Error>,
{
pub(crate) fn new(client: &'a Client, request: R) -> Self {
Self {
client,
request,
pagination: Pagination::default(),
sorting: Sorting::default(),
filter: PredicateBox::default(),
}
}

pub fn filter(mut self, filter: PredicateBox) -> Self {
self.filter = filter;
self
}

pub fn sort(mut self, sorting: Sorting) -> Self {
self.sorting = sorting;
self
}

pub fn paginate(mut self, pagination: Pagination) -> Self {
self.pagination = pagination;
self
}

pub fn request(self) -> QueryResult<<R::Output as QueryOutput>::Target> {
self.client.request_with_filter_and_pagination_and_sorting(
self.request,
self.pagination,
self.sorting,
self.filter,
)
}
}
8 changes: 6 additions & 2 deletions client/tests/integration/tx_rollback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,16 @@ fn client_sends_transaction_with_invalid_instruction_should_not_see_any_changes(

//Then
let request = client::asset::by_account_id(account_id);
let query_result = client.request(request)?.collect::<QueryResult<Vec<_>>>()?;
let query_result = client
.query(request)
.request()?
.collect::<QueryResult<Vec<_>>>()?;
assert!(query_result
.iter()
.all(|asset| asset.id().definition_id != wrong_asset_definition_id));
let definition_query_result = client
.request(client::asset::all_definitions())?
.query(client::asset::all_definitions())
.request()?
.collect::<QueryResult<Vec<_>>>()?;
assert!(definition_query_result
.iter()
Expand Down
13 changes: 8 additions & 5 deletions client/tests/integration/upgrade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ fn executor_upgrade_should_run_migration() -> Result<()> {
let can_unregister_domain_token_id = "CanUnregisterDomain".parse().unwrap();

// Check that `CanUnregisterDomain` exists
let definitions = client.request(FindPermissionTokenSchema)?;
let definitions = client.query(FindPermissionTokenSchema).request()?;
assert!(definitions
.token_ids()
.iter()
Expand All @@ -69,7 +69,8 @@ fn executor_upgrade_should_run_migration() -> Result<()> {
// Check that Alice has permission to unregister Wonderland
let alice_id: AccountId = "alice@wonderland".parse().unwrap();
let alice_tokens = client
.request(FindPermissionTokensByAccountId::new(alice_id.clone()))?
.query(FindPermissionTokensByAccountId::new(alice_id.clone()))
.request()?
.collect::<QueryResult<Vec<_>>>()
.expect("Valid");
assert!(alice_tokens.contains(&PermissionToken::new(
Expand All @@ -83,7 +84,7 @@ fn executor_upgrade_should_run_migration() -> Result<()> {
)?;

// Check that `CanUnregisterDomain` doesn't exist
let definitions = client.request(FindPermissionTokenSchema)?;
let definitions = client.query(FindPermissionTokenSchema).request()?;
assert!(!definitions
.token_ids()
.iter()
Expand All @@ -98,7 +99,8 @@ fn executor_upgrade_should_run_migration() -> Result<()> {

// Check that Alice has `can_control_domain_lives` permission
let alice_tokens = client
.request(FindPermissionTokensByAccountId::new(alice_id))?
.query(FindPermissionTokensByAccountId::new(alice_id))
.request()?
.collect::<QueryResult<Vec<_>>>()
.expect("Valid");
assert!(alice_tokens.contains(&PermissionToken::new(
Expand All @@ -116,7 +118,8 @@ fn migration_fail_should_not_cause_any_effects() {

let assert_domain_does_not_exist = |client: &Client, domain_id: &DomainId| {
client
.request(client::domain::by_id(domain_id.clone()))
.query(client::domain::by_id(domain_id.clone()))
.request()
.expect_err(&format!("There should be no `{domain_id}` domain"));
};

Expand Down
27 changes: 19 additions & 8 deletions client_cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -408,10 +408,13 @@ mod domain {

let vec = match self {
Self::All => client
.request(client::domain::all())
.query(client::domain::all())
.request()
.wrap_err("Failed to get all domains"),
Self::Filter(filter) => client
.request_with_filter(client::domain::all(), filter.predicate)
.query(client::domain::all())
.filter(filter.predicate)
.request()
.wrap_err("Failed to get filtered domains"),
}?;
context.print_data(&vec.collect::<QueryResult<Vec<_>>>()?)?;
Expand Down Expand Up @@ -548,10 +551,13 @@ mod account {

let vec = match self {
Self::All => client
.request(client::account::all())
.query(client::account::all())
.request()
.wrap_err("Failed to get all accounts"),
Self::Filter(filter) => client
.request_with_filter(client::account::all(), filter.predicate)
.query(client::account::all())
.filter(filter.predicate)
.request()
.wrap_err("Failed to get filtered accounts"),
}?;
context.print_data(&vec.collect::<QueryResult<Vec<_>>>()?)?;
Expand Down Expand Up @@ -616,7 +622,8 @@ mod account {
let client = Client::new(context.configuration())?;
let find_all_permissions = FindPermissionTokensByAccountId::new(self.id);
let permissions = client
.request(find_all_permissions)
.query(find_all_permissions)
.request()
.wrap_err("Failed to get all account permissions")?;
context.print_data(&permissions.collect::<QueryResult<Vec<_>>>()?)?;
Ok(())
Expand Down Expand Up @@ -819,7 +826,8 @@ mod asset {
let iroha_client = Client::new(context.configuration())?;
let asset_id = AssetId::new(asset, account);
let asset = iroha_client
.request(asset::by_id(asset_id))
.query(asset::by_id(asset_id))
.request()
.wrap_err("Failed to get asset.")?;
context.print_data(&asset)?;
Ok(())
Expand All @@ -841,10 +849,13 @@ mod asset {

let vec = match self {
Self::All => client
.request(client::asset::all())
.query(client::asset::all())
.request()
.wrap_err("Failed to get all assets"),
Self::Filter(filter) => client
.request_with_filter(client::asset::all(), filter.predicate)
.query(client::asset::all())
.filter(filter.predicate)
.request()
.wrap_err("Failed to get filtered assets"),
}?;
context.print_data(&vec.collect::<QueryResult<Vec<_>>>()?)?;
Expand Down
2 changes: 1 addition & 1 deletion core/test_network/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -868,7 +868,7 @@ impl TestClient for Client {
{
let mut query_result = None;
for _ in 0..max_attempts {
query_result = match self.request(request.clone()) {
query_result = match self.query(request.clone()).request() {
Ok(result) if f(result.clone()) => return Ok(()),
result => Some(result),
};
Expand Down

0 comments on commit 845f04d

Please sign in to comment.