Skip to content

Commit 935dcdb

Browse files
author
Chris Arderne
committed
Add bbox and datetime to SQLAlchemy item_collection
Copy the bbox and datetime filtering from the search routes
1 parent 35ed1c2 commit 935dcdb

File tree

1 file changed

+43
-5
lines changed
  • stac_fastapi/sqlalchemy/stac_fastapi/sqlalchemy

1 file changed

+43
-5
lines changed

stac_fastapi/sqlalchemy/stac_fastapi/sqlalchemy/core.py

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,25 +99,63 @@ def get_collection(self, collection_id: str, **kwargs) -> Collection:
9999
return self.collection_serializer.db_to_stac(collection, base_url)
100100

101101
def item_collection(
102-
self, collection_id: str, limit: int = 10, token: str = None, **kwargs
102+
self,
103+
collection_id: str,
104+
bbox: Optional[List[NumType]] = None,
105+
datetime: Optional[str] = None,
106+
limit: int = 10,
107+
token: str = None,
108+
**kwargs,
103109
) -> ItemCollection:
104110
"""Read an item collection from the database."""
105111
base_url = str(kwargs["request"].base_url)
106112
with self.session.reader.context_session() as session:
107-
collection_children = (
113+
query = (
108114
session.query(self.item_table)
109115
.join(self.collection_table)
110116
.filter(self.collection_table.id == collection_id)
111117
.order_by(self.item_table.datetime.desc(), self.item_table.id)
112118
)
119+
# Spatial query
120+
geom = None
121+
if bbox:
122+
if len(bbox) == 4:
123+
geom = ShapelyPolygon.from_bounds(*bbox)
124+
elif len(bbox) == 6:
125+
"""Shapely doesn't support 3d bounding boxes so use the 2d portion"""
126+
bbox_2d = [bbox[0], bbox[1], bbox[3], bbox[4]]
127+
geom = ShapelyPolygon.from_bounds(*bbox_2d)
128+
if geom:
129+
filter_geom = ga.shape.from_shape(geom, srid=4326)
130+
query = query.filter(
131+
ga.func.ST_Intersects(self.item_table.geometry, filter_geom)
132+
)
133+
134+
# Temporal query
135+
if datetime:
136+
# Two tailed query (between)
137+
dts = datetime.split("/")
138+
# Non-interval date ex. "2000-02-02T00:00:00.00Z"
139+
if len(dts) == 1:
140+
query = query.filter(self.item_table.datetime == dts[0])
141+
# is there a benefit to between instead of >= and <= ?
142+
elif dts[0] not in ["", ".."] and dts[1] not in ["", ".."]:
143+
query = query.filter(self.item_table.datetime.between(*dts))
144+
# All items after the start date
145+
elif dts[0] not in ["", ".."]:
146+
query = query.filter(self.item_table.datetime >= dts[0])
147+
# All items before the end date
148+
elif dts[1] not in ["", ".."]:
149+
query = query.filter(self.item_table.datetime <= dts[1])
150+
113151
count = None
114152
if self.extension_is_enabled("ContextExtension"):
115-
count_query = collection_children.statement.with_only_columns(
153+
count_query = query.statement.with_only_columns(
116154
[func.count()]
117155
).order_by(None)
118-
count = collection_children.session.execute(count_query).scalar()
156+
count = query.session.execute(count_query).scalar()
119157
token = self.get_token(token) if token else token
120-
page = get_page(collection_children, per_page=limit, page=(token or False))
158+
page = get_page(query, per_page=limit, page=(token or False))
121159
# Create dynamic attributes for each page
122160
page.next = (
123161
self.insert_token(keyset=page.paging.bookmark_next)

0 commit comments

Comments
 (0)