Skip to content

Commit b1e656c

Browse files
Yuri ZmytrakovYuri Zmytrakov
authored andcommitted
first commit
1 parent 375bb8d commit b1e656c

File tree

2 files changed

+76
-26
lines changed

2 files changed

+76
-26
lines changed

Dockerfile

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
FROM python:3.13-slim
2+
3+
RUN apt-get update && apt-get install -y \
4+
build-essential \
5+
&& apt-get clean \
6+
&& rm -rf /var/lib/apt/lists/*
7+
8+
WORKDIR /app
9+
10+
COPY README.md .
11+
COPY stac_fastapi/core/pyproject.toml stac_fastapi/core/
12+
COPY stac_fastapi/sfeos_helpers/pyproject.toml stac_fastapi/sfeos_helpers/
13+
COPY stac_fastapi/opensearch/pyproject.toml stac_fastapi/opensearch/
14+
15+
RUN pip install --no-cache-dir --upgrade pip setuptools wheel
16+
17+
COPY stac_fastapi/ stac_fastapi/
18+
19+
RUN pip install --no-cache-dir ./stac_fastapi/core
20+
RUN pip install --no-cache-dir ./stac_fastapi/sfeos_helpers
21+
RUN pip install --no-cache-dir ./stac_fastapi/opensearch[server]
22+
23+
EXPOSE 8080
24+
25+
CMD ["uvicorn", "stac_fastapi.opensearch.app:app", "--host", "0.0.0.0", "--port", "8080"]

stac_fastapi/opensearch/stac_fastapi/opensearch/database_logic.py

Lines changed: 51 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from base64 import urlsafe_b64decode, urlsafe_b64encode
66
from collections.abc import Iterable
77
from copy import deepcopy
8+
from dataclasses import dataclass
89
from typing import Any, Dict, List, Optional, Tuple, Type
910

1011
import attr
@@ -74,6 +75,49 @@
7475
logger = logging.getLogger(__name__)
7576

7677

78+
# AST-style node classes for bbox filtering
79+
@dataclass
80+
class GeoShapeNode:
81+
"""Represents a geo_shape query node in the AST."""
82+
83+
geometry: "GeometryNode"
84+
85+
86+
@dataclass
87+
class GeometryNode:
88+
"""Represents a geometry node with shape and relation."""
89+
90+
shape: "ShapeNode"
91+
relation: str
92+
93+
94+
@dataclass
95+
class ShapeNode:
96+
"""Represents a shape node with type and coordinates."""
97+
98+
type: str
99+
coordinates: List[List[List[float]]]
100+
101+
102+
def analyze_bbox_query(node) -> dict:
103+
"""Analyze and build bbox query from node tree.
104+
Args:
105+
node: The AST node to analyze.
106+
107+
Returns:
108+
The constructed geo_shape query.
109+
"""
110+
if isinstance(node, GeoShapeNode):
111+
return analyze_bbox_query(node.geometry)
112+
elif isinstance(node, GeometryNode):
113+
shape_filter = analyze_bbox_query(node.shape)
114+
return {"shape": shape_filter, "relation": node.relation}
115+
elif isinstance(node, ShapeNode):
116+
if node.type == "polygon":
117+
return {"type": node.type, "coordinates": node.coordinates}
118+
return {}
119+
120+
77121
async def create_index_templates() -> None:
78122
"""
79123
Create index templates for the Collection and Item indices.
@@ -595,34 +639,15 @@ def apply_datetime_filter(
595639

596640
@staticmethod
597641
def apply_bbox_filter(search: Search, bbox: List):
598-
"""Filter search results based on bounding box.
599-
600-
Args:
601-
search (Search): The search object to apply the filter to.
602-
bbox (List): The bounding box coordinates, represented as a list of four values [minx, miny, maxx, maxy].
642+
"""Filter search results based on bounding box using AST analysis pattern."""
643+
polygon_coordinates = bbox2polygon(*bbox)
603644

604-
Returns:
605-
search (Search): The search object with the bounding box filter applied.
645+
shape_node = ShapeNode(type="polygon", coordinates=polygon_coordinates)
646+
geometry_node = GeometryNode(shape=shape_node, relation="intersects")
647+
geo_shape_node = GeoShapeNode(geometry=geometry_node)
606648

607-
Notes:
608-
The bounding box is transformed into a polygon using the `bbox2polygon` function and
609-
a geo_shape filter is added to the search object, set to intersect with the specified polygon.
610-
"""
611-
return search.filter(
612-
Q(
613-
{
614-
"geo_shape": {
615-
"geometry": {
616-
"shape": {
617-
"type": "polygon",
618-
"coordinates": bbox2polygon(*bbox),
619-
},
620-
"relation": "intersects",
621-
}
622-
}
623-
}
624-
)
625-
)
649+
bbox_query_dict = analyze_bbox_query(geo_shape_node)
650+
return search.filter(Q("geo_shape", geometry=bbox_query_dict))
626651

627652
@staticmethod
628653
def apply_intersects_filter(

0 commit comments

Comments
 (0)