Skip to content

Commit 1cc4804

Browse files
authored
add sort for item-search (#330)
* add sort for item-search * rename sorted datetimes
1 parent 004ee97 commit 1cc4804

File tree

3 files changed

+132
-1
lines changed

3 files changed

+132
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313
- Add parameter set `--validate-pagination/--no-validate-pagination` to conditionally run the pagination tests, which may take a while to run.
1414
- Added support for Query Extension validation of Item Search
1515
- Added support for Transaction Extension validation
16+
- Added support for Sort Extension validation of Item Search
1617

1718
## [0.5.0] - 2023-02-21
1819

COMPLIANCE_REPORT.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ poetry run stac-api-validator --root-url https://earth-search.aws.element84.com/
313313
--conformance item-search \
314314
--conformance item-search#fields \
315315
--conformance item-search#query \
316+
--conformance item-search#sort \
316317
--collection sentinel-2-l2a \
317318
--fields-nested-property properties.eo:cloud_cover \
318319
--geometry '{"type": "Polygon", "coordinates": [[[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]]]}' \

src/stac_api_validator/validations.py

Lines changed: 130 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -664,7 +664,15 @@ def validate_api(
664664

665665
if "item-search#sort" in ccs_to_validate:
666666
logger.info("STAC API - Item Search - Sort extension conformance class found.")
667-
logger.info("STAC API - Item Search - Sort extension is not yet supported.")
667+
validate_sort(
668+
context=Context.ITEM_SEARCH_SORT,
669+
landing_page_body=landing_page_body,
670+
collection=collection,
671+
errors=errors,
672+
warnings=warnings,
673+
r_session=r_session,
674+
query_config=query_config,
675+
)
668676

669677
if "item-search#query" in ccs_to_validate:
670678
logger.info("STAC API - Item Search - Query extension conformance class found.")
@@ -3532,3 +3540,124 @@ def validate_transaction(
35323540
context=context,
35333541
r_session=r_session,
35343542
)
3543+
3544+
3545+
def validate_sort(
3546+
landing_page_body: Dict[str, Any],
3547+
collection: str,
3548+
errors: Errors,
3549+
warnings: Warnings,
3550+
r_session: Session,
3551+
context: Context,
3552+
query_config: QueryConfig,
3553+
) -> None:
3554+
limit = 100
3555+
3556+
search_method_to_url: dict[Method, str] = {
3557+
Method[x.get("method", "GET")]: x.get("href")
3558+
for x in links_by_rel(landing_page_body.get("links"), "search")
3559+
}
3560+
3561+
# ascending
3562+
if Method.GET in search_method_to_url:
3563+
for sortby in ["properties.datetime", "+properties.datetime"]:
3564+
_, body, _ = retrieve(
3565+
Method.GET,
3566+
search_method_to_url[Method.GET],
3567+
params={
3568+
"sortby": sortby,
3569+
"limit": limit,
3570+
"collections": collection,
3571+
},
3572+
errors=errors,
3573+
context=context,
3574+
r_session=r_session,
3575+
)
3576+
3577+
if not len(body["features"]):
3578+
errors += (
3579+
f"[{context}] : GET search with Sort '{sortby}' had no results"
3580+
)
3581+
3582+
datetimes = [f["properties"]["datetime"] for f in body["features"]]
3583+
sorted_datetimes = copy.deepcopy(datetimes)
3584+
sorted_datetimes.sort()
3585+
3586+
if datetimes != sorted_datetimes:
3587+
errors += f"[{context}] : GET search with Sort '{sortby}' was not sorted in ascending order {datetimes} {sorted_datetimes}"
3588+
3589+
if Method.POST in search_method_to_url:
3590+
sortby_json = [{"field": "properties.datetime", "direction": "asc"}]
3591+
retrieve(
3592+
Method.POST,
3593+
search_method_to_url[Method.POST],
3594+
body={
3595+
"sortby": sortby_json,
3596+
"limit": limit,
3597+
"collections": collection,
3598+
},
3599+
errors=errors,
3600+
context=context,
3601+
r_session=r_session,
3602+
)
3603+
3604+
if not len(body["features"]):
3605+
errors += f"[{context}] : POST search with Sort '{json.dumps(sortby_json)}' had no results"
3606+
3607+
datetimes = [f["properties"]["datetime"] for f in body["features"]]
3608+
sorted_datetimes = copy.deepcopy(datetimes)
3609+
sorted_datetimes.sort()
3610+
3611+
if datetimes != sorted_datetimes:
3612+
errors += f"[{context}] : POST search with Sort '{json.dumps(sortby_json)}' was not sorted in ascending order"
3613+
3614+
# descending
3615+
if Method.GET in search_method_to_url:
3616+
sortby = "-properties.datetime"
3617+
_, body, _ = retrieve(
3618+
Method.GET,
3619+
search_method_to_url[Method.GET],
3620+
params={
3621+
"sortby": sortby,
3622+
"limit": limit,
3623+
"collections": collection,
3624+
},
3625+
errors=errors,
3626+
context=context,
3627+
r_session=r_session,
3628+
)
3629+
3630+
if not len(body["features"]):
3631+
errors += f"[{context}] : GET search with Sort '{sortby}' had no results"
3632+
3633+
datetimes = [f["properties"]["datetime"] for f in body["features"]]
3634+
sorted_datetimes = copy.deepcopy(datetimes)
3635+
sorted_datetimes.sort(reverse=True)
3636+
3637+
if datetimes != sorted_datetimes:
3638+
errors += f"[{context}] : GET search with Sort '{sortby}' was not sorted in descending order {datetimes} {sorted_datetimes}"
3639+
3640+
if Method.POST in search_method_to_url:
3641+
sortby_json = [{"field": "properties.datetime", "direction": "desc"}]
3642+
retrieve(
3643+
Method.POST,
3644+
search_method_to_url[Method.POST],
3645+
body={
3646+
"sortby": sortby_json,
3647+
"limit": limit,
3648+
"collections": collection,
3649+
},
3650+
errors=errors,
3651+
context=context,
3652+
r_session=r_session,
3653+
)
3654+
3655+
if not len(body["features"]):
3656+
errors += f"[{context}] : POST search with Sort '{json.dumps(sortby_json)}' had no results"
3657+
3658+
datetimes = [f["properties"]["datetime"] for f in body["features"]]
3659+
sorted_datetimes = copy.deepcopy(datetimes)
3660+
sorted_datetimes.sort(reverse=True)
3661+
3662+
if datetimes != sorted_datetimes:
3663+
errors += f"[{context}] : POST search with Sort '{json.dumps(sortby_json)}' was not sorted in descending order"

0 commit comments

Comments
 (0)