Skip to content

add sort for item-search #330

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

Merged
merged 2 commits into from
Apr 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add parameter set `--validate-pagination/--no-validate-pagination` to conditionally run the pagination tests, which may take a while to run.
- Added support for Query Extension validation of Item Search
- Added support for Transaction Extension validation
- Added support for Sort Extension validation of Item Search

## [0.5.0] - 2023-02-21

Expand Down
1 change: 1 addition & 0 deletions COMPLIANCE_REPORT.md
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ poetry run stac-api-validator --root-url https://earth-search.aws.element84.com/
--conformance item-search \
--conformance item-search#fields \
--conformance item-search#query \
--conformance item-search#sort \
--collection sentinel-2-l2a \
--fields-nested-property properties.eo:cloud_cover \
--geometry '{"type": "Polygon", "coordinates": [[[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]]]}' \
Expand Down
131 changes: 130 additions & 1 deletion src/stac_api_validator/validations.py
Original file line number Diff line number Diff line change
Expand Up @@ -664,7 +664,15 @@ def validate_api(

if "item-search#sort" in ccs_to_validate:
logger.info("STAC API - Item Search - Sort extension conformance class found.")
logger.info("STAC API - Item Search - Sort extension is not yet supported.")
validate_sort(
context=Context.ITEM_SEARCH_SORT,
landing_page_body=landing_page_body,
collection=collection,
errors=errors,
warnings=warnings,
r_session=r_session,
query_config=query_config,
)

if "item-search#query" in ccs_to_validate:
logger.info("STAC API - Item Search - Query extension conformance class found.")
Expand Down Expand Up @@ -3532,3 +3540,124 @@ def validate_transaction(
context=context,
r_session=r_session,
)


def validate_sort(
landing_page_body: Dict[str, Any],
collection: str,
errors: Errors,
warnings: Warnings,
r_session: Session,
context: Context,
query_config: QueryConfig,
) -> None:
limit = 100

search_method_to_url: dict[Method, str] = {
Method[x.get("method", "GET")]: x.get("href")
for x in links_by_rel(landing_page_body.get("links"), "search")
}

# ascending
if Method.GET in search_method_to_url:
for sortby in ["properties.datetime", "+properties.datetime"]:
_, body, _ = retrieve(
Method.GET,
search_method_to_url[Method.GET],
params={
"sortby": sortby,
"limit": limit,
"collections": collection,
},
errors=errors,
context=context,
r_session=r_session,
)

if not len(body["features"]):
errors += (
f"[{context}] : GET search with Sort '{sortby}' had no results"
)

datetimes = [f["properties"]["datetime"] for f in body["features"]]
sorted_datetimes = copy.deepcopy(datetimes)
sorted_datetimes.sort()

if datetimes != sorted_datetimes:
errors += f"[{context}] : GET search with Sort '{sortby}' was not sorted in ascending order {datetimes} {sorted_datetimes}"

if Method.POST in search_method_to_url:
sortby_json = [{"field": "properties.datetime", "direction": "asc"}]
retrieve(
Method.POST,
search_method_to_url[Method.POST],
body={
"sortby": sortby_json,
"limit": limit,
"collections": collection,
},
errors=errors,
context=context,
r_session=r_session,
)

if not len(body["features"]):
errors += f"[{context}] : POST search with Sort '{json.dumps(sortby_json)}' had no results"

datetimes = [f["properties"]["datetime"] for f in body["features"]]
sorted_datetimes = copy.deepcopy(datetimes)
sorted_datetimes.sort()

if datetimes != sorted_datetimes:
errors += f"[{context}] : POST search with Sort '{json.dumps(sortby_json)}' was not sorted in ascending order"

# descending
if Method.GET in search_method_to_url:
sortby = "-properties.datetime"
_, body, _ = retrieve(
Method.GET,
search_method_to_url[Method.GET],
params={
"sortby": sortby,
"limit": limit,
"collections": collection,
},
errors=errors,
context=context,
r_session=r_session,
)

if not len(body["features"]):
errors += f"[{context}] : GET search with Sort '{sortby}' had no results"

datetimes = [f["properties"]["datetime"] for f in body["features"]]
sorted_datetimes = copy.deepcopy(datetimes)
sorted_datetimes.sort(reverse=True)

if datetimes != sorted_datetimes:
errors += f"[{context}] : GET search with Sort '{sortby}' was not sorted in descending order {datetimes} {sorted_datetimes}"

if Method.POST in search_method_to_url:
sortby_json = [{"field": "properties.datetime", "direction": "desc"}]
retrieve(
Method.POST,
search_method_to_url[Method.POST],
body={
"sortby": sortby_json,
"limit": limit,
"collections": collection,
},
errors=errors,
context=context,
r_session=r_session,
)

if not len(body["features"]):
errors += f"[{context}] : POST search with Sort '{json.dumps(sortby_json)}' had no results"

datetimes = [f["properties"]["datetime"] for f in body["features"]]
sorted_datetimes = copy.deepcopy(datetimes)
sorted_datetimes.sort(reverse=True)

if datetimes != sorted_datetimes:
errors += f"[{context}] : POST search with Sort '{json.dumps(sortby_json)}' was not sorted in descending order"