Skip to content

Commit

Permalink
[feature] hyperledger-iroha#2553: Add sorting to asset queries
Browse files Browse the repository at this point in the history
Signed-off-by: Vladimir Pesterev <pesterev@pm.me>
  • Loading branch information
pesterev authored and mversic committed Sep 6, 2022
1 parent be9176e commit 09bec42
Show file tree
Hide file tree
Showing 11 changed files with 479 additions and 37 deletions.
45 changes: 39 additions & 6 deletions cli/src/torii/routing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,19 +119,22 @@ pub(crate) async fn handle_queries(
wsv: Arc<WorldStateView>,
query_judge: QueryJudgeArc,
pagination: Pagination,
sorting: Sorting,
request: VerifiedQueryRequest,
) -> Result<Scale<VersionedPaginatedQueryResult>> {
let (valid_request, filter) = request.validate(&wsv, query_judge.as_ref())?;
let original_result = valid_request.execute(&wsv)?;
let result = filter.filter(original_result);
let (total, result) = if let Value::Vec(value) = result {
(
value.len(),
Value::Vec(value.into_iter().paginate(pagination).collect()),
)

let (total, result) = if let Value::Vec(vec_of_val) = result {
let len = vec_of_val.len();
let vec_of_val = apply_sorting_and_pagination(vec_of_val, &sorting, pagination);

(len, Value::Vec(vec_of_val))
} else {
(1, result)
};

let total = total
.try_into()
.map_err(|e: TryFromIntError| QueryError::Conversion(e.to_string()))?;
Expand All @@ -145,6 +148,35 @@ pub(crate) async fn handle_queries(
Ok(Scale(paginated_result.into()))
}

fn apply_sorting_and_pagination(
mut vec_of_val: Vec<Value>,
sorting: &Sorting,
pagination: Pagination,
) -> Vec<Value> {
if let Some(ref key) = sorting.sort_by_metadata_key {
let f = |value1: &Value| {
if let Value::U128(num) = value1 {
*num
} else {
0
}
};

vec_of_val.sort_by_key(|value0| match value0 {
Value::Identifiable(IdentifiableBox::Asset(asset)) => match asset.value() {
AssetValue::Store(store) => store.get(key).map_or(0, f),
_ => 0,
},
Value::Identifiable(v) => TryInto::<&dyn HasMetadata>::try_into(v)
.map(|has_metadata| has_metadata.metadata().get(key).map_or(0, f))
.unwrap_or(0),
_ => 0,
});
}

vec_of_val.into_iter().paginate(pagination).collect()
}

#[derive(serde::Serialize)]
#[non_exhaustive]
enum Health {
Expand Down Expand Up @@ -482,11 +514,12 @@ impl Torii {
))
.and(body::versioned()),
)
.or(endpoint4(
.or(endpoint5(
handle_queries,
warp::path(uri::QUERY)
.and(add_state!(self.wsv, self.query_judge))
.and(paginate())
.and(sorting())
.and(body::query()),
))
.or(endpoint2(
Expand Down
3 changes: 2 additions & 1 deletion cli/src/torii/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,12 @@ async fn torii_pagination() {
.try_into()
.expect("Failed to verify");

let pagination = Pagination { start, limit };
let pagination = Pagination::new(start, limit);
handle_queries(
Arc::clone(&torii.wsv),
Arc::clone(&torii.query_judge),
pagination,
Sorting::default(),
query,
)
.map(|result| {
Expand Down
2 changes: 1 addition & 1 deletion cli/src/torii/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,4 @@ impl<O: Reply, E: Reply> Reply for WarpResult<O, E> {
}
}

generate_endpoints!(2, 3, 4);
generate_endpoints!(2, 3, 4, 5);
77 changes: 71 additions & 6 deletions client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,7 @@ impl Client {
&self,
request: R,
pagination: Pagination,
sorting: Sorting,
filter: PredicateBox,
) -> Result<(B, QueryResponseHandler<R>)>
where
Expand All @@ -619,6 +620,7 @@ impl Client {
B: RequestBuilder,
{
let pagination: Vec<_> = pagination.into();
let sorting: Vec<_> = sorting.into();
let request = QueryRequest::new(request.into(), self.account_id.clone(), filter);
let request: VersionedSignedQueryRequest = self.sign_query(request)?.into();

Expand All @@ -628,33 +630,80 @@ impl Client {
format!("{}/{}", &self.torii_url, uri::QUERY),
)
.params(pagination)
.params(sorting)
.headers(self.headers.clone())
.body(request.encode_versioned()),
QueryResponseHandler::default(),
))
}

/// Create a request with pagination and add the filter.
/// Create a request with pagination, sorting and add the filter.
///
/// # Errors
/// Forwards from [`Self::prepare_query_request`].
pub fn request_with_pagination_and_filter<R>(
/// Fails if sending request fails
pub fn request_with_pagination_and_filter_and_sorting<R>(
&self,
request: R,
pagination: Pagination,
sorting: Sorting,
filter: PredicateBox,
) -> QueryHandlerResult<ClientQueryOutput<R>>
where
R: Query + Into<QueryBox> + Debug,
<R::Output as TryFrom<Value>>::Error: Into<eyre::Error>, // Seems redundant
{
iroha_logger::trace!(?request, %pagination, ?filter);
let (req, resp_handler) =
self.prepare_query_request::<R, DefaultRequestBuilder>(request, pagination, filter)?;
iroha_logger::trace!(?request, %pagination, ?sorting, ?filter);
let (req, resp_handler) = self.prepare_query_request::<R, DefaultRequestBuilder>(
request, pagination, sorting, filter,
)?;
let response = req.build()?.send()?;
resp_handler.handle(response)
}

/// Create a request with pagination and sorting.
///
/// # Errors
/// Fails if sending request fails
pub fn request_with_pagination_and_sorting<R>(
&self,
request: R,
pagination: Pagination,
sorting: Sorting,
) -> QueryHandlerResult<ClientQueryOutput<R>>
where
R: Query + Into<QueryBox> + Debug,
<R::Output as TryFrom<Value>>::Error: Into<eyre::Error>,
{
self.request_with_pagination_and_filter_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_pagination_and_filter<R>(
&self,
request: R,
pagination: Pagination,
filter: PredicateBox,
) -> QueryHandlerResult<ClientQueryOutput<R>>
where
R: Query + Into<QueryBox> + Debug,
<R::Output as TryFrom<Value>>::Error: Into<eyre::Error>, // Seems redundant
{
self.request_with_pagination_and_filter_and_sorting(
request,
pagination,
Sorting::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
Expand All @@ -674,6 +723,22 @@ impl Client {
self.request_with_pagination_and_filter(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>(
&self,
request: R,
sorting: Sorting,
) -> QueryHandlerResult<ClientQueryOutput<R>>
where
R: Query + Into<QueryBox> + Debug,
<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
Expand Down
1 change: 1 addition & 0 deletions client/tests/integration/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ mod queries;
mod query_errors;
mod restart_peer;
mod roles;
mod sorting;
mod transfer_asset;
mod triggers;
mod tx_history;
Expand Down
8 changes: 1 addition & 7 deletions client/tests/integration/pagination.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,7 @@ fn client_add_asset_quantity_to_existing_asset_should_increase_asset_amount() {
//When

let vec = iroha_client
.request_with_pagination(
asset::all_definitions(),
Pagination {
start: Some(5),
limit: Some(5),
},
)
.request_with_pagination(asset::all_definitions(), Pagination::new(Some(5), Some(5)))
.expect("Failed to get assets")
.only_output();
assert_eq!(vec.len(), 5);
Expand Down
Loading

0 comments on commit 09bec42

Please sign in to comment.