Skip to content

Commit 2a34f39

Browse files
authored
yolo: multiple collections (#13)
* deps: update * feat: bit of a yolo fix for multiple collections * fix: typing
1 parent 23b57ab commit 2a34f39

File tree

6 files changed

+100
-88
lines changed

6 files changed

+100
-88
lines changed

data/collections.json

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,39 @@
3232
"type": "application/vnd.apache.parquet"
3333
}
3434
}
35+
},
36+
{
37+
"type": "Collection",
38+
"stac_version": "1.1.0",
39+
"id": "openaerialmap",
40+
"description": "This collection was generated by rustac v0.12.0 from 17702 items",
41+
"license": "other",
42+
"extent": {
43+
"spatial": {
44+
"bbox": [
45+
[
46+
-175.25390625,
47+
-43.683527,
48+
177.537581,
49+
60.172121352329114
50+
]
51+
]
52+
},
53+
"temporal": {
54+
"interval": [
55+
[
56+
"1944-12-31T13:00:00Z",
57+
"2025-03-30T21:16:00Z"
58+
]
59+
]
60+
}
61+
},
62+
"links": [],
63+
"assets": {
64+
"data": {
65+
"href": "./openaerialmap.parquet",
66+
"type": "application/vnd.apache.parquet"
67+
}
68+
}
3569
}
3670
]

data/openaerialmap.parquet

1.43 MB
Binary file not shown.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ dependencies = [
99
"fastapi>=0.115.8",
1010
"geojson-pydantic>=1.2.0",
1111
"pydantic>=2.10.4",
12-
"rustac @ git+https://github.com/stac-utils/rustac-py",
12+
"rustac==0.7.0b2",
1313
"stac-fastapi-api>=5.0.2",
1414
"stac-fastapi-extensions>=5.0.2",
1515
"stac-fastapi-types>=5.0.2",

src/stac_fastapi/geoparquet/client.py

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -164,42 +164,38 @@ async def search(
164164
client = cast(DuckdbClient, request.state.client)
165165
hrefs = cast(dict[str, list[str]], request.state.hrefs)
166166

167-
hrefs_to_search = []
168167
if search.collections:
169-
for collection in search.collections:
170-
if collection_hrefs := hrefs.get(collection):
171-
hrefs_to_search.extend(collection_hrefs)
168+
collections = search.collections
172169
else:
173-
for collection_hrefs in hrefs.values():
174-
hrefs_to_search.extend(collection_hrefs)
175-
176-
if len(hrefs) > 1:
177-
raise ValidationError(
178-
"Cannot search multiple geoparquet files (don't know how to page)"
179-
)
180-
elif len(hrefs) == 0:
181-
return ItemCollection()
182-
else:
183-
href = hrefs_to_search.pop()
170+
collections = list(hrefs.keys())
184171

185172
search_dict = search.model_dump(exclude_none=True)
186-
search_dict.update(**kwargs)
187-
items = client.search(
188-
href,
189-
**search_dict,
190-
)
173+
search_dict["offset"] = kwargs.get("offset", 0)
174+
items: list[dict[str, Any]] = []
175+
while collections and not (search.limit and len(items) >= search.limit):
176+
collection = collections.pop(0)
177+
if collection_hrefs := hrefs.get(collection):
178+
collection_search_dict = copy.deepcopy(search_dict)
179+
collection_search_dict["collections"] = [collection]
180+
for href in collection_hrefs:
181+
items.extend(client.search(href, **collection_search_dict))
182+
if search.limit and len(items) >= search.limit:
183+
collections.insert(0, collection)
184+
break
185+
search_dict["offset"] = 0
186+
191187
item_collection = {
192188
"type": "FeatureCollection",
193189
"features": [self.item_with_links(item, request) for item in items],
194190
}
195191
num_items = len(item_collection["features"])
196-
limit = int(search_dict.get("limit", None) or num_items)
197192
offset = int(search_dict.get("offset", None) or 0)
198193

199-
if limit <= num_items:
194+
if search.limit and search.limit <= num_items:
200195
next_search = copy.deepcopy(search_dict)
201-
next_search["limit"] = limit
202-
next_search["offset"] = offset + limit
196+
next_search["limit"] = search.limit
197+
next_search["offset"] = offset + search.limit
198+
next_search["collections"] = collections
203199
else:
204200
next_search = None
205201

@@ -220,6 +216,8 @@ async def search(
220216
}
221217
)
222218
if next_search:
219+
if "collections" in next_search:
220+
next_search["collections"] = ",".join(collections)
223221
links.append(
224222
{
225223
"href": url + "?" + urllib.parse.urlencode(next_search),

tests/test_search.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@ async def test_paging(client: TestClient) -> None:
2222
(link for link in response.json()["links"] if link["rel"] == "next")
2323
)
2424
url = urllib.parse.urlparse(next_link["href"])
25-
assert urllib.parse.parse_qs(url.query) == {"limit": ["1"], "offset": ["1"]}
25+
assert urllib.parse.parse_qs(url.query) == {
26+
"limit": ["1"],
27+
"offset": ["1"],
28+
"collections": ["naip,openaerialmap"],
29+
}
2630
response = client.get("/search", params=url.query)
2731
assert response.status_code == 200
2832
assert response.json()["features"][0]["id"] == "ne_m_4110263_sw_13_060_20220820"

0 commit comments

Comments
 (0)