Skip to content

Commit

Permalink
Property selection for post spatial, search, iterate, get by IDs or s…
Browse files Browse the repository at this point in the history
…ingle ID (#185)

* implementation

* test not working yet

* selection tests

* clip tests, disable clipping for now due to technical limits

* PR comments

* implementation with tests

* MCPODS-6785 Search API selection

* MCPODS-6785 Search test fix

* MCPODS-6573 Get features by single or multiple IDs output JSON property selection

* MCPODS-6787 iterate features output JSON property selection

* PR comments

---------

Co-authored-by: Hiren Patel <[email protected]>
  • Loading branch information
gunplar and hirenkp2000 authored Feb 8, 2024
1 parent d31c449 commit aa7faaf
Show file tree
Hide file tree
Showing 32 changed files with 615 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ protected void init() {}
final String spaceId = ApiParams.extractMandatoryPathParam(routingContext, SPACE_ID);
final QueryParameterList queryParameters = queryParamsFromRequest(routingContext);
final List<String> featureIds = extractParamAsStringList(queryParameters, FEATURE_IDS);
final Set<String> propPaths = PropertySelectionUtil.buildPropPathSetFromQueryParams(queryParameters);

// Validate parameters
if (featureIds == null || featureIds.isEmpty()) {
Expand All @@ -127,22 +128,28 @@ protected void init() {}

// Forward request to NH Space Storage reader instance
try (Result result = executeReadRequestFromSpaceStorage(rdRequest)) {
final F1<XyzFeature, XyzFeature> preResponseProcessing =
standardReadFeaturesPreResponseProcessing(propPaths, false, null);
// transform Result to Http FeatureCollection response
return transformReadResultToXyzCollectionResponse(result, XyzFeature.class);
return transformReadResultToXyzCollectionResponse(result, XyzFeature.class, preResponseProcessing);
}
}

private @NotNull XyzResponse executeFeatureById() {
// Parse and validate Path parameters
final String spaceId = extractMandatoryPathParam(routingContext, SPACE_ID);
final String featureId = extractMandatoryPathParam(routingContext, FEATURE_ID);
final QueryParameterList queryParameters = queryParamsFromRequest(routingContext);
final Set<String> propPaths = PropertySelectionUtil.buildPropPathSetFromQueryParams(queryParameters);

final ReadFeatures rdRequest = RequestHelper.readFeaturesByIdRequest(spaceId, featureId);

// Forward request to NH Space Storage reader instance
try (Result result = executeReadRequestFromSpaceStorage(rdRequest)) {
final F1<XyzFeature, XyzFeature> preResponseProcessing =
standardReadFeaturesPreResponseProcessing(propPaths, false, null);
// transform Result to Http XyzFeature response
return transformReadResultToXyzFeatureResponse(result, XyzFeature.class);
return transformReadResultToXyzFeatureResponse(result, XyzFeature.class, preResponseProcessing);
}
}

Expand Down Expand Up @@ -227,6 +234,7 @@ protected void init() {}
routingContext, XyzError.ILLEGAL_ARGUMENT, "Missing mandatory query parameters");
}
long limit = ApiParams.extractQueryParamAsLong(queryParams, LIMIT, false, DEF_FEATURE_LIMIT);
final Set<String> propPaths = PropertySelectionUtil.buildPropPathSetFromQueryParams(queryParams);
// validate values
limit = (limit < 0 || limit > DEF_FEATURE_LIMIT) ? DEF_FEATURE_LIMIT : limit;

Expand All @@ -242,8 +250,11 @@ protected void init() {}

// Forward request to NH Space Storage reader instance
final Result result = executeReadRequestFromSpaceStorage(rdRequest);
final F1<XyzFeature, XyzFeature> preResponseProcessing =
standardReadFeaturesPreResponseProcessing(propPaths, false, null);
// transform Result to Http FeatureCollection response, restricted by given feature limit
return transformReadResultToXyzCollectionResponse(result, XyzFeature.class, limit);
return transformReadResultToXyzCollectionResponse(
result, XyzFeature.class, 0, limit, null, preResponseProcessing);
}

private @NotNull XyzResponse executeIterate() {
Expand All @@ -253,6 +264,9 @@ protected void init() {}
// Parse and validate Query parameters
final QueryParameterList queryParams = queryParamsFromRequest(routingContext);

// Parse property selection
final Set<String> propPaths = PropertySelectionUtil.buildPropPathSetFromQueryParams(queryParams);

// Note : subsequent steps need to support queryParams being null

// extract limit parameter
Expand All @@ -273,9 +287,12 @@ protected void init() {}

// Forward request to NH Space Storage reader instance
final Result result = executeReadRequestFromSpaceStorage(rdRequest);
final F1<XyzFeature, XyzFeature> preResponseProcessing =
standardReadFeaturesPreResponseProcessing(propPaths, false, null);
// transform Result to Http FeatureCollection response,
// restricted by given feature limit and by adding "handle" attribute to support subsequent iteration
return transformReadResultToXyzCollectionResponse(result, XyzFeature.class, offset, limit, handle);
return transformReadResultToXyzCollectionResponse(
result, XyzFeature.class, offset, limit, handle, preResponseProcessing);
}

private @NotNull XyzResponse executeFeaturesByRadius() {
Expand Down Expand Up @@ -373,6 +390,8 @@ protected void init() {}
// NOTE : queryParams can be null. Subsequent steps should respect the same.
final long radius = ApiParams.extractQueryParamAsLong(queryParams, RADIUS, false, 0);
long limit = ApiParams.extractQueryParamAsLong(queryParams, LIMIT, false, DEF_FEATURE_LIMIT);
final Set<String> propPaths = PropertySelectionUtil.buildPropPathSetFromQueryParams(queryParams);
final boolean clip = ApiParams.extractQueryParamAsBoolean(queryParams, CLIP_GEO, false);
// validate values
limit = (limit < 0 || limit > DEF_FEATURE_LIMIT) ? DEF_FEATURE_LIMIT : limit;
ApiParams.validateParamRange(RADIUS, radius, 0, Long.MAX_VALUE);
Expand All @@ -390,7 +409,11 @@ protected void init() {}

// Forward request to NH Space Storage reader instance
final Result result = executeReadRequestFromSpaceStorage(rdRequest);
// TODO pass the correct transformed geometry into this method call, also use the boolean clip
final F1<XyzFeature, XyzFeature> preResponseProcessing =
standardReadFeaturesPreResponseProcessing(propPaths, false, radiusOp.getGeometry());
// transform Result to Http FeatureCollection response, restricted by given feature limit
return transformReadResultToXyzCollectionResponse(result, XyzFeature.class, limit);
return transformReadResultToXyzCollectionResponse(
result, XyzFeature.class, 0, limit, null, preResponseProcessing);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,7 @@ paths:
parameters:
- $ref: '#/components/parameters/SpaceId'
- $ref: '#/components/parameters/RequiredIds'
- $ref: '#/components/parameters/PropertiesSelection'
responses:
'200':
$ref: '#/components/responses/FeatureCollectionResponse'
Expand Down Expand Up @@ -627,6 +628,8 @@ paths:
summary: Get a feature by ID
description: Retrieves the feature with the provided identifier.
operationId: getFeature
parameters:
- $ref: '#/components/parameters/PropertiesSelection'
responses:
'200':
$ref: '#/components/responses/FeatureResponse'
Expand Down Expand Up @@ -880,6 +883,8 @@ paths:
- $ref: '#/components/parameters/TagList'
- $ref: '#/components/parameters/Limit'
- $ref: '#/components/parameters/PropertiesQuery'
- $ref: '#/components/parameters/PropertiesSelection'
# - $ref: '#/components/parameters/Clip'
requestBody:
$ref: '#/components/requestBodies/GeometryRequest'
responses:
Expand Down Expand Up @@ -917,6 +922,7 @@ paths:
- $ref: '#/components/parameters/TagList'
- $ref: '#/components/parameters/Limit'
- $ref: '#/components/parameters/PropertiesQuery'
- $ref: '#/components/parameters/PropertiesSelection'
responses:
'200':
$ref: '#/components/responses/FeatureCollectionResponse'
Expand Down Expand Up @@ -951,6 +957,7 @@ paths:
- $ref: '#/components/parameters/SpaceId'
- $ref: '#/components/parameters/Limit'
- $ref: '#/components/parameters/Handle'
- $ref: '#/components/parameters/PropertiesSelection'
responses:
'200':
$ref: '#/components/responses/IterateResponse'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,4 +170,41 @@ void tc1103_testIterateWithInvalidHandle() throws URISyntaxException, Interrupte
.hasJsonBody(expectedBodyPart, "Iterate Feature Error response body doesn't match");
}

@Test
void tc1104_testIterateInTwoPagesWithPropSelection() throws URISyntaxException, InterruptedException, IOException {
// Test API : GET /hub/spaces/{spaceId}/iterate
// Validate all features getting returned in two iterations, with:
// - first iteration returning features and nextPageToken, selecting: 1 normal prop, 1 URI encoded prop, 1 prop not existing
// - second iteration accepting handle but use the wrong selection delimiter (should return 400)

// Given: iterate parameters for first request
final String limitQueryParam = "limit=3";
final String firstStreamId = UUID.randomUUID().toString();
final String firstExpectedBodyPart = loadFileOrFail("ReadFeatures/Iterate/TC1104_testIterateInTwoPagesWithPropSelection/iterate_response_1.json")
.replaceAll("\\{\\{streamId}}",firstStreamId);
final String selectionParams = "selection=p.speedLimit,p.unknown_prop,%s".formatted(urlEncoded("p.@ns:com:here:xyz.tags"));

// When: First iterate Features request is submitted to NakshaHub
HttpResponse<String> response = nakshaClient.get("hub/spaces/" + SPACE_ID + "/iterate" + "?" + limitQueryParam + "&" + selectionParams, firstStreamId);
// Then: Perform assertions
ResponseAssertions.assertThat(response)
.hasStatus(200)
.hasStreamIdHeader(firstStreamId)
.hasJsonBody(firstExpectedBodyPart, "First Iterate response body doesn't match", true);

// Given: iterate parameters for second request
final String handleQueryParam = "handle=" + urlEncoded(parseJson(response.body(), XyzFeatureCollection.class).getNextPageToken());
final String secondExpectedBodyPart = loadFileOrFail("ReadFeatures/Iterate/TC1104_testIterateInTwoPagesWithPropSelection/iterate_response_2.json");
final String secondStreamId = UUID.randomUUID().toString();
final String selectionWrongDelimiterParams = "selection=p.speedLimit+p.unknown_prop";

// When: Second iterate Features request is submitted to NakshaHub
response = nakshaClient.get("hub/spaces/" + SPACE_ID + "/iterate" + "?" + handleQueryParam + "&" + selectionWrongDelimiterParams, secondStreamId);
// Then: Perform assertions
ResponseAssertions.assertThat(response)
.hasStatus(400)
.hasStreamIdHeader(secondStreamId)
.hasJsonBody(secondExpectedBodyPart, "Final Iterate response body doesn't match");
}

}
Loading

0 comments on commit aa7faaf

Please sign in to comment.