Skip to content

Commit 610d800

Browse files
authored
Merge pull request #191 from nkleinbaer/collection-extensions
Support extensions defining top-level properties on collections
2 parents 223a927 + 3c7b581 commit 610d800

File tree

3 files changed

+63
-26
lines changed

3 files changed

+63
-26
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
2828

2929
### Fixed
3030

31+
- Allow additional top-level properties on collections [#191](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/pull/191)
3132
- Exclude unset fields in search response [#166](https://github.com/stac-utils/stac-fastapi-elasticsearch/issues/166)
3233
- Upgrade stac-fastapi to v2.4.9 [#172](https://github.com/stac-utils/stac-fastapi-elasticsearch/pull/172)
3334
- Set correct default filter-lang for GET /search requests [#179](https://github.com/stac-utils/stac-fastapi-elasticsearch/issues/179)

stac_fastapi/elasticsearch/stac_fastapi/elasticsearch/serializers.py

Lines changed: 20 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""Serializers."""
22
import abc
3+
from copy import deepcopy
34
from typing import Any
45

56
import attr
@@ -121,18 +122,24 @@ def db_to_stac(cls, collection: dict, base_url: str) -> stac_types.Collection:
121122
Returns:
122123
stac_types.Collection: The STAC collection object.
123124
"""
124-
# Use dictionary unpacking to extract values from the collection dictionary
125+
# Avoid modifying the input dict in-place ... doing so breaks some tests
126+
collection = deepcopy(collection)
127+
128+
# Set defaults
125129
collection_id = collection.get("id")
126-
stac_extensions = collection.get("stac_extensions", [])
127-
stac_version = collection.get("stac_version", "")
128-
title = collection.get("title", "")
129-
description = collection.get("description", "")
130-
keywords = collection.get("keywords", [])
131-
license = collection.get("license", "")
132-
providers = collection.get("providers", {})
133-
summaries = collection.get("summaries", {})
134-
extent = collection.get("extent", {})
135-
collection_assets = collection.get("assets", {})
130+
collection.setdefault("type", "Collection")
131+
collection.setdefault("stac_extensions", [])
132+
collection.setdefault("stac_version", "")
133+
collection.setdefault("title", "")
134+
collection.setdefault("description", "")
135+
collection.setdefault("keywords", [])
136+
collection.setdefault("license", "")
137+
collection.setdefault("providers", [])
138+
collection.setdefault("summaries", {})
139+
collection.setdefault(
140+
"extent", {"spatial": {"bbox": []}, "temporal": {"interval": []}}
141+
)
142+
collection.setdefault("assets", {})
136143

137144
# Create the collection links using CollectionLinks
138145
collection_links = CollectionLinks(
@@ -143,20 +150,7 @@ def db_to_stac(cls, collection: dict, base_url: str) -> stac_types.Collection:
143150
original_links = collection.get("links")
144151
if original_links:
145152
collection_links += resolve_links(original_links, base_url)
153+
collection["links"] = collection_links
146154

147155
# Return the stac_types.Collection object
148-
return stac_types.Collection(
149-
type="Collection",
150-
id=collection_id,
151-
stac_extensions=stac_extensions,
152-
stac_version=stac_version,
153-
title=title,
154-
description=description,
155-
keywords=keywords,
156-
license=license,
157-
providers=providers,
158-
summaries=summaries,
159-
extent=extent,
160-
links=collection_links,
161-
assets=collection_assets,
162-
)
156+
return stac_types.Collection(**collection)

stac_fastapi/elasticsearch/tests/resources/test_collection.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,22 @@
55

66
from ..conftest import create_collection, delete_collections_and_items, refresh_indices
77

8+
CORE_COLLECTION_PROPS = [
9+
"id",
10+
"type",
11+
"stac_extensions",
12+
"stac_version",
13+
"title",
14+
"description",
15+
"keywords",
16+
"license",
17+
"providers",
18+
"summaries",
19+
"extent",
20+
"links",
21+
"assets",
22+
]
23+
824

925
@pytest.mark.asyncio
1026
async def test_create_and_delete_collection(app_client, load_test_data):
@@ -84,6 +100,32 @@ async def test_returns_valid_collection(ctx, app_client):
84100
collection.validate()
85101

86102

103+
@pytest.mark.asyncio
104+
async def test_collection_extensions(ctx, app_client):
105+
"""Test that extensions can be used to define additional top-level properties"""
106+
ctx.collection.get("stac_extensions", []).append(
107+
"https://stac-extensions.github.io/item-assets/v1.0.0/schema.json"
108+
)
109+
test_asset = {"title": "test", "description": "test", "type": "test"}
110+
ctx.collection["item_assets"] = {"test": test_asset}
111+
resp = await app_client.put("/collections", json=ctx.collection)
112+
113+
assert resp.status_code == 200
114+
assert resp.json().get("item_assets", {}).get("test") == test_asset
115+
116+
117+
@pytest.mark.asyncio
118+
async def test_collection_defaults(app_client):
119+
"""Test that properties omitted by client are populated w/ default values"""
120+
minimal_coll = {"id": str(uuid.uuid4())}
121+
resp = await app_client.post("/collections", json=minimal_coll)
122+
123+
assert resp.status_code == 200
124+
resp_json = resp.json()
125+
for prop in CORE_COLLECTION_PROPS:
126+
assert prop in resp_json.keys()
127+
128+
87129
@pytest.mark.asyncio
88130
async def test_pagination_collection(app_client, ctx, txn_client):
89131
"""Test collection pagination links"""

0 commit comments

Comments
 (0)