Skip to content

Commit 18a9649

Browse files
committed
Make item geometry and bbox nullable for sqlalchemy backend
Closes #350
1 parent 526501b commit 18a9649

File tree

6 files changed

+246
-5
lines changed

6 files changed

+246
-5
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
* Bulk Transactions object Items iterator now returns the Item objects rather than the string IDs of the Item objects
1818
([#355](https://github.com/stac-utils/stac-fastapi/issues/355))
1919
* docker-compose now runs uvicorn with hot-reloading enabled
20+
* Make item geometry and bbox nullable in sqlalchemy backend. ([#](https://github.com/stac-utils/stac-fastapi/pull))
2021

2122
### Removed
2223

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
"""Make item geometry and bbox nullable
2+
3+
Revision ID: 7016c1bf3fbf
4+
Revises: 5909bd10f2e6
5+
Create Date: 2022-04-28 10:40:06.856826
6+
7+
"""
8+
from alembic import op
9+
10+
# revision identifiers, used by Alembic.
11+
revision = "7016c1bf3fbf"
12+
down_revision = "5909bd10f2e6"
13+
branch_labels = None
14+
depends_on = None
15+
16+
17+
def upgrade():
18+
op.alter_column(
19+
schema="data",
20+
table_name="items",
21+
column_name="geometry",
22+
nullable=True,
23+
)
24+
op.alter_column(
25+
schema="data",
26+
table_name="items",
27+
column_name="bbox",
28+
nullable=True,
29+
)
30+
31+
32+
def downgrade():
33+
# Downgrading will require the user to update or remove all null geometry
34+
# cases from the DB, otherwise the downgrade migration will fail.
35+
op.alter_column(
36+
schema="data",
37+
table_name="items",
38+
column_name="geometry",
39+
nullable=False,
40+
)
41+
op.alter_column(
42+
schema="data",
43+
table_name="items",
44+
column_name="bbox",
45+
nullable=False,
46+
)

stac_fastapi/sqlalchemy/stac_fastapi/sqlalchemy/models/database.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,10 @@ class Item(BaseModel): # type:ignore
6464
id = sa.Column(sa.VARCHAR(1024), nullable=False, primary_key=True)
6565
stac_version = sa.Column(sa.VARCHAR(300))
6666
stac_extensions = sa.Column(sa.ARRAY(sa.VARCHAR(300)), nullable=True)
67-
geometry = sa.Column(GeojsonGeometry("GEOMETRY", srid=4326, spatial_index=True))
68-
bbox = sa.Column(sa.ARRAY(sa.NUMERIC), nullable=False)
67+
geometry = sa.Column(
68+
GeojsonGeometry("GEOMETRY", srid=4326, spatial_index=True), nullable=True
69+
)
70+
bbox = sa.Column(sa.ARRAY(sa.NUMERIC), nullable=True)
6971
properties = sa.Column(JSONB)
7072
assets = sa.Column(JSONB)
7173
collection_id = sa.Column(

stac_fastapi/sqlalchemy/stac_fastapi/sqlalchemy/serializers.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,14 +78,18 @@ def db_to_stac(cls, db_model: database.Item, base_url: str) -> stac_types.Item:
7878
if isinstance(geometry, str):
7979
geometry = json.loads(geometry)
8080

81+
bbox = db_model.bbox
82+
if bbox is not None:
83+
bbox = [float(x) for x in db_model.bbox]
84+
8185
return stac_types.Item(
8286
type="Feature",
8387
stac_version=db_model.stac_version,
8488
stac_extensions=stac_extensions,
8589
id=db_model.id,
8690
collection=db_model.collection_id,
8791
geometry=geometry,
88-
bbox=[float(x) for x in db_model.bbox],
92+
bbox=bbox,
8993
properties=properties,
9094
links=item_links,
9195
assets=db_model.assets,
@@ -111,13 +115,17 @@ def stac_to_db(
111115
stac_data["properties"]["created"] = now
112116
stac_data["properties"]["updated"] = now
113117

118+
geometry = stac_data["geometry"]
119+
if geometry is not None:
120+
geometry = json.dumps(geometry)
121+
114122
return database.Item(
115123
id=stac_data["id"],
116124
collection_id=stac_data["collection"],
117125
stac_version=stac_data["stac_version"],
118126
stac_extensions=stac_data.get("stac_extensions"),
119-
geometry=json.dumps(stac_data["geometry"]),
120-
bbox=stac_data["bbox"],
127+
geometry=geometry,
128+
bbox=stac_data.get("bbox"),
121129
properties=stac_data["properties"],
122130
assets=stac_data["assets"],
123131
**indexed_fields,

stac_fastapi/sqlalchemy/tests/api/test_api.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,21 @@ def test_app_search_response_multipolygon(
9292
assert resp_json.get("features")[0]["geometry"]["type"] == "MultiPolygon"
9393

9494

95+
def test_app_search_response_geometry_null(
96+
load_test_data, app_client, postgres_transactions
97+
):
98+
item = load_test_data("test_item_geometry_null.json")
99+
postgres_transactions.create_item(item, request=MockStarletteRequest)
100+
101+
resp = app_client.get("/search", params={"collections": ["test-collection"]})
102+
assert resp.status_code == 200
103+
resp_json = resp.json()
104+
105+
assert resp_json.get("type") == "FeatureCollection"
106+
assert resp_json.get("features")[0]["geometry"] is None
107+
assert resp_json.get("features")[0]["bbox"] is None
108+
109+
95110
def test_app_context_extension(load_test_data, app_client, postgres_transactions):
96111
item = load_test_data("test_item.json")
97112
postgres_transactions.create_item(item, request=MockStarletteRequest)
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
{
2+
"type": "Feature",
3+
"stac_version": "1.0.0",
4+
"stac_extensions": [
5+
"https://landsat.usgs.gov/stac/landsat-ard-extension/v1.0.0/schema.json",
6+
"https://stac-extensions.github.io/projection/v1.0.0/schema.json",
7+
"https://stac-extensions.github.io/eo/v1.0.0/schema.json",
8+
"https://stac-extensions.github.io/alternate-assets/v1.1.0/schema.json",
9+
"https://stac-extensions.github.io/storage/v1.0.0/schema.json"
10+
],
11+
"id": "LE07_CU_002012_20150101_20210502_02_BA",
12+
"description": "Landsat Collection 2 Level-3 Burned Area Product",
13+
"geometry": null,
14+
"properties": {
15+
"datetime": "2015-01-01T18:39:12.4885358Z",
16+
"platform": "LANDSAT_7",
17+
"instruments": [
18+
"ETM"
19+
],
20+
"landsat:grid_horizontal": "02",
21+
"landsat:grid_vertical": "12",
22+
"landsat:grid_region": "CU",
23+
"landsat:scene_count": 1,
24+
"eo:cloud_cover": 0.0759,
25+
"landsat:cloud_shadow_cover": 0.1394,
26+
"landsat:snow_ice_cover": 0,
27+
"landsat:fill": 95.4286,
28+
"proj:epsg": null,
29+
"proj:shape": [
30+
5000,
31+
5000
32+
],
33+
"proj:transform": [
34+
30,
35+
0,
36+
-2265585,
37+
0,
38+
-30,
39+
1514805
40+
],
41+
"created": "2022-02-08T20:07:38.885Z",
42+
"updated": "2022-02-08T20:07:38.885Z"
43+
},
44+
"assets": {
45+
"index": {
46+
"title": "HTML index page",
47+
"type": "text/html",
48+
"roles": [
49+
"metadata"
50+
],
51+
"href": "https://landsatlook.usgs.gov/stac-browser/collection02/BA/2015/CU/002/012/LE07_CU_002012_20150101_20210502_02_BA/LE07_CU_002012_20150101_20210502_02"
52+
},
53+
"bp": {
54+
"title": "Burn Probability",
55+
"description": "Collection 2 Level-3 Albers Burn Probability Burned Area",
56+
"type": "image/vnd.stac.geotiff; cloud-optimized=true",
57+
"roles": [
58+
"data"
59+
],
60+
"href": "https://landsatlook.usgs.gov/level-3/collection02/BA/2015/CU/002/012/LE07_CU_002012_20150101_20210502_02_BA/LE07_CU_002012_20150101_20210502_02_BP.TIF",
61+
"alternate": {
62+
"s3": {
63+
"storage:platform": "AWS",
64+
"storage:requester_pays": true,
65+
"href": "s3://usgs-landsat-level-3/collection02/BA/2015/CU/002/012/LE07_CU_002012_20150101_20210502_02_BA/LE07_CU_002012_20150101_20210502_02_BP.TIF"
66+
}
67+
}
68+
},
69+
"bc": {
70+
"title": "Burn Classification",
71+
"description": "Collection 2 Level-3 Albers Burn Classification Burned Area",
72+
"type": "image/vnd.stac.geotiff; cloud-optimized=true",
73+
"roles": [
74+
"data"
75+
],
76+
"href": "https://landsatlook.usgs.gov/level-3/collection02/BA/2015/CU/002/012/LE07_CU_002012_20150101_20210502_02_BA/LE07_CU_002012_20150101_20210502_02_BC.TIF",
77+
"alternate": {
78+
"s3": {
79+
"storage:platform": "AWS",
80+
"storage:requester_pays": true,
81+
"href": "s3://usgs-landsat-level-3/collection02/BA/2015/CU/002/012/LE07_CU_002012_20150101_20210502_02_BA/LE07_CU_002012_20150101_20210502_02_BC.TIF"
82+
}
83+
}
84+
},
85+
"quick_look": {
86+
"title": "Quick Look File",
87+
"description": "Collection 2 Level-3 Albers Quick Look File Burned Area",
88+
"type": "image/png",
89+
"roles": [
90+
"data"
91+
],
92+
"href": "https://landsatlook.usgs.gov/level-3/collection02/BA/2015/CU/002/012/LE07_CU_002012_20150101_20210502_02_BA/LE07_CU_002012_20150101_20210502_02_QuickLook.png",
93+
"alternate": {
94+
"s3": {
95+
"storage:platform": "AWS",
96+
"storage:requester_pays": true,
97+
"href": "s3://usgs-landsat-level-3/collection02/BA/2015/CU/002/012/LE07_CU_002012_20150101_20210502_02_BA/LE07_CU_002012_20150101_20210502_02_QuickLook.png"
98+
}
99+
}
100+
},
101+
"xml": {
102+
"title": "Extensible Metadata File",
103+
"description": "Collection 2 Level-3 Albers Extensible Metadata File Burned Area",
104+
"type": "application/xml",
105+
"roles": [
106+
"metadata"
107+
],
108+
"href": "https://landsatlook.usgs.gov/level-3/collection02/BA/2015/CU/002/012/LE07_CU_002012_20150101_20210502_02_BA/LE07_CU_002012_20150101_20210502_02.xml",
109+
"alternate": {
110+
"s3": {
111+
"storage:platform": "AWS",
112+
"storage:requester_pays": true,
113+
"href": "s3://usgs-landsat-level-3/collection02/BA/2015/CU/002/012/LE07_CU_002012_20150101_20210502_02_BA/LE07_CU_002012_20150101_20210502_02.xml"
114+
}
115+
}
116+
},
117+
"json": {
118+
"title": "Extensible Metadata File (json)",
119+
"description": "Collection 2 Level-3 Albers Extensible Metadata File (json) Burned Area",
120+
"type": "application/json",
121+
"roles": [
122+
"metadata"
123+
],
124+
"href": "https://landsatlook.usgs.gov/level-3/collection02/BA/2015/CU/002/012/LE07_CU_002012_20150101_20210502_02_BA/LE07_CU_002012_20150101_20210502_02.json",
125+
"alternate": {
126+
"s3": {
127+
"storage:platform": "AWS",
128+
"storage:requester_pays": true,
129+
"href": "s3://usgs-landsat-level-3/collection02/BA/2015/CU/002/012/LE07_CU_002012_20150101_20210502_02_BA/LE07_CU_002012_20150101_20210502_02.json"
130+
}
131+
}
132+
}
133+
},
134+
"links": [
135+
{
136+
"rel": "self",
137+
"href": "https://landsatlook.usgs.gov/stac-server/collections/landsat-c2l3-ba/items/LE07_CU_002012_20150101_20210502_02_BA"
138+
},
139+
{
140+
"rel": "derived_from",
141+
"href": "https://landsatlook.usgs.gov/stac-server/collections/landsat-c2ard-sr/items/LE07_CU_002012_20150101_20210502_02_SR"
142+
},
143+
{
144+
"rel": "derived_from",
145+
"href": "https://landsatlook.usgs.gov/stac-server/collections/landsat-c2ard-st/items/LE07_CU_002012_20150101_20210502_02_ST"
146+
},
147+
{
148+
"rel": "derived_from",
149+
"href": "https://landsatlook.usgs.gov/stac-server/collections/landsat-c2ard-ta/items/LE07_CU_002012_20150101_20210502_02_TOA"
150+
},
151+
{
152+
"rel": "derived_from",
153+
"href": "https://landsatlook.usgs.gov/stac-server/collections/landsat-c2ard-bt/items/LE07_CU_002012_20150101_20210502_02_BT"
154+
},
155+
{
156+
"rel": "parent",
157+
"href": "https://landsatlook.usgs.gov/stac-server/collections/landsat-c2l3-ba"
158+
},
159+
{
160+
"rel": "collection",
161+
"href": "https://landsatlook.usgs.gov/stac-server/collections/landsat-c2l3-ba"
162+
},
163+
{
164+
"rel": "root",
165+
"href": "https://landsatlook.usgs.gov/stac-server/"
166+
}
167+
],
168+
"collection": "test-collection"
169+
}

0 commit comments

Comments
 (0)