Skip to content

Commit 6b58c81

Browse files
authored
Merge branch 'main' into sort-item-collection
2 parents 3b3b087 + 5723bba commit 6b58c81

File tree

8 files changed

+52
-9
lines changed

8 files changed

+52
-9
lines changed

CHANGELOG.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
1010

1111
### Added
1212

13-
- Sort extension and sortby functionality to the item collection route. [#437](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/pull/437)
14-
- Query extension and query functionality to the item collection route. [#437](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/pull/437)
15-
- Filter extension and filter functionality to the item collection route. [#437](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/pull/437)
13+
- Added the `ENV_MAX_LIMIT` environment variable to SFEOS, allowing overriding of the `MAX_LIMIT`, which controls the `?limit` parameter for returned items and STAC collections. [#434](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/pull/434)
14+
- Sort, Query, and Filter extension and functionality to the item collection route. [#437](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/pull/437)
1615

1716
### Changed
1817

1918
- Changed assets serialization to prevent mapping explosion while allowing asset information to be indexed. [#341](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/pull/341)
2019
- Simplified the item_collection function in core.py, moving the request to the get_search function. [#437](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/pull/437)
20+
- Updated the `format_datetime_range` function to support milliseconds. [#423](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/pull/423)
21+
- Blocked the /collections/{collection_id}/bulk_items endpoint when environmental variable ENABLE_DATETIME_INDEX_FILTERING is set to true. [#438](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/pull/438)
2122

2223
### Fixed
2324

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ You can customize additional settings in your `.env` file:
228228
| `DATABASE_REFRESH` | Controls whether database operations refresh the index immediately after changes. If set to `true`, changes will be immediately searchable. If set to `false`, changes may not be immediately visible but can improve performance for bulk operations. If set to `wait_for`, changes will wait for the next refresh cycle to become visible. | `false` | Optional |
229229
| `ENABLE_TRANSACTIONS_EXTENSIONS` | Enables or disables the Transactions and Bulk Transactions API extensions. If set to `false`, the POST `/collections` route and related transaction endpoints (including bulk transaction operations) will be unavailable in the API. This is useful for deployments where mutating the catalog via the API should be prevented. | `true` | Optional |
230230
| `STAC_ITEM_LIMIT` | Sets the environment variable for result limiting to SFEOS for the number of returned items and STAC collections. | `10` | Optional |
231+
| `ENV_MAX_LIMIT` | Configures the environment variable in SFEOS to override the default `MAX_LIMIT`, which controls the limit parameter for returned items and STAC collections. | `10,000` | Optional |
231232

232233
> [!NOTE]
233234
> The variables `ES_HOST`, `ES_PORT`, `ES_USE_SSL`, `ES_VERIFY_CERTS` and `ES_TIMEOUT` apply to both Elasticsearch and OpenSearch backends, so there is no need to rename the key names to `OS_` even if you're using OpenSearch.

stac_fastapi/core/stac_fastapi/core/core.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -959,6 +959,13 @@ def bulk_item_insert(
959959
A string indicating the number of items successfully added.
960960
"""
961961
request = kwargs.get("request")
962+
963+
if os.getenv("ENABLE_DATETIME_INDEX_FILTERING"):
964+
raise HTTPException(
965+
status_code=400,
966+
detail="The /collections/{collection_id}/bulk_items endpoint is invalid when ENABLE_DATETIME_INDEX_FILTERING is set to true. Try using the /collections/{collection_id}/items endpoint.",
967+
)
968+
962969
if request:
963970
base_url = str(request.base_url)
964971
else:

stac_fastapi/core/stac_fastapi/core/datetime_utils.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,20 @@ def format_datetime_range(date_str: str) -> str:
1717
"""
1818

1919
def normalize(dt):
20+
"""Normalize datetime string and preserve millisecond precision."""
2021
dt = dt.strip()
2122
if not dt or dt == "..":
2223
return ".."
2324
dt_obj = rfc3339_str_to_datetime(dt)
2425
dt_utc = dt_obj.astimezone(timezone.utc)
25-
return dt_utc.strftime("%Y-%m-%dT%H:%M:%SZ")
26+
return dt_utc.isoformat(timespec="milliseconds").replace("+00:00", "Z")
2627

2728
if not isinstance(date_str, str):
2829
return "../.."
30+
2931
if "/" not in date_str:
3032
return f"{normalize(date_str)}/{normalize(date_str)}"
33+
3134
try:
3235
start, end = date_str.split("/", 1)
3336
except Exception:

stac_fastapi/core/stac_fastapi/core/utilities.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,15 @@
1010

1111
from stac_fastapi.types.stac import Item
1212

13-
MAX_LIMIT = 10000
13+
14+
def get_max_limit():
15+
"""
16+
Retrieve a MAX_LIMIT value from an environment variable.
17+
18+
Returns:
19+
int: The int value parsed from the environment variable.
20+
"""
21+
return int(os.getenv("ENV_MAX_LIMIT", 10000))
1422

1523

1624
def get_bool_env(name: str, default: Union[bool, str] = False) -> bool:

stac_fastapi/elasticsearch/stac_fastapi/elasticsearch/database_logic.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
from stac_fastapi.core.base_database_logic import BaseDatabaseLogic
1919
from stac_fastapi.core.serializers import CollectionSerializer, ItemSerializer
20-
from stac_fastapi.core.utilities import MAX_LIMIT, bbox2polygon
20+
from stac_fastapi.core.utilities import bbox2polygon, get_max_limit
2121
from stac_fastapi.elasticsearch.config import AsyncElasticsearchSettings
2222
from stac_fastapi.elasticsearch.config import (
2323
ElasticsearchSettings as SyncElasticsearchSettings,
@@ -543,7 +543,7 @@ async def execute_search(
543543
index_param = ITEM_INDICES
544544
query = add_collections_to_body(collection_ids, query)
545545

546-
max_result_window = MAX_LIMIT
546+
max_result_window = get_max_limit()
547547

548548
size_limit = min(limit + 1, max_result_window)
549549

stac_fastapi/opensearch/stac_fastapi/opensearch/database_logic.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
from stac_fastapi.core.base_database_logic import BaseDatabaseLogic
1818
from stac_fastapi.core.serializers import CollectionSerializer, ItemSerializer
19-
from stac_fastapi.core.utilities import MAX_LIMIT, bbox2polygon
19+
from stac_fastapi.core.utilities import bbox2polygon, get_max_limit
2020
from stac_fastapi.extensions.core.transaction.request import (
2121
PartialCollection,
2222
PartialItem,
@@ -540,7 +540,7 @@ async def execute_search(
540540

541541
search_body["sort"] = sort if sort else DEFAULT_SORT
542542

543-
max_result_window = MAX_LIMIT
543+
max_result_window = get_max_limit()
544544

545545
size_limit = min(limit + 1, max_result_window)
546546

stac_fastapi/tests/api/test_api.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1698,3 +1698,26 @@ async def test_filter_by_nonexistent_id(app_client, ctx, txn_client):
16981698
assert (
16991699
len(resp_json["features"]) == 0
17001700
), f"Expected no items with ID {non_existent_id}, but found {len(resp_json['features'])} matches"
1701+
1702+
1703+
async def test_search_max_item_limit(
1704+
app_client, load_test_data, txn_client, monkeypatch
1705+
):
1706+
limit = "10"
1707+
monkeypatch.setenv("ENV_MAX_LIMIT", limit)
1708+
1709+
test_collection = load_test_data("test_collection.json")
1710+
await create_collection(txn_client, test_collection)
1711+
1712+
item = load_test_data("test_item.json")
1713+
1714+
for i in range(20):
1715+
test_item = item.copy()
1716+
test_item["id"] = f"test-item-collection-{i}"
1717+
await create_item(txn_client, test_item)
1718+
1719+
resp = await app_client.get("/search", params={"limit": 20})
1720+
1721+
assert resp.status_code == 200
1722+
resp_json = resp.json()
1723+
assert int(limit) == len(resp_json["features"])

0 commit comments

Comments
 (0)