Skip to content

Commit b3b3f14

Browse files
Yuri ZmytrakovYuri Zmytrakov
authored andcommitted
test: Add cql2-json datetime operator tests
- Added tests for CQL2-JSON datetime filter operators - Tested datetime field operators: =, <=, >=, AND combinations - Tested start_datetime and end_datetime field operators - Verified range queries work correctly with date fields - Ensured AST parsing correctly handles datetime comparisons
1 parent c215ae4 commit b3b3f14

File tree

1 file changed

+202
-0
lines changed

1 file changed

+202
-0
lines changed

stac_fastapi/tests/resources/test_item.py

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,3 +1163,205 @@ async def test_search_datetime_with_null_datetime(
11631163
await txn_client.delete_collection(test_collection["id"])
11641164
except Exception as e:
11651165
logger.warning(f"Failed to delete collection: {e}")
1166+
1167+
1168+
@pytest.mark.asyncio
1169+
async def test_search_cql2_json_datetime_operators(app_client, ctx):
1170+
"""Test POST search with CQL2-JSON datetime filter operators"""
1171+
1172+
test_item = ctx.item
1173+
item_datetime = test_item["properties"]["datetime"]
1174+
1175+
cql2_equal = {
1176+
"filter-lang": "cql2-json",
1177+
"filter": {"op": "=", "args": [{"property": "datetime"}, item_datetime]},
1178+
}
1179+
resp = await app_client.post("/search", json=cql2_equal)
1180+
assert resp.status_code == 200
1181+
resp_json = resp.json()
1182+
assert resp_json["features"][0]["id"] == test_item["id"]
1183+
1184+
later_datetime = "2020-02-13T12:30:22Z"
1185+
cql2_lte = {
1186+
"filter-lang": "cql2-json",
1187+
"filter": {"op": "<=", "args": [{"property": "datetime"}, later_datetime]},
1188+
}
1189+
resp = await app_client.post("/search", json=cql2_lte)
1190+
assert resp.status_code == 200
1191+
resp_json = resp.json()
1192+
assert resp_json["features"][0]["id"] == test_item["id"]
1193+
1194+
earlier_datetime = "2020-02-11T12:30:22Z"
1195+
cql2_gte = {
1196+
"filter-lang": "cql2-json",
1197+
"filter": {"op": ">=", "args": [{"property": "datetime"}, earlier_datetime]},
1198+
}
1199+
resp = await app_client.post("/search", json=cql2_gte)
1200+
assert resp.status_code == 200
1201+
resp_json = resp.json()
1202+
assert resp_json["features"][0]["id"] == test_item["id"]
1203+
1204+
range_start = "2020-02-12T00:00:00Z"
1205+
range_end = "2020-02-13T00:00:00Z"
1206+
cql2_between = {
1207+
"filter-lang": "cql2-json",
1208+
"filter": {
1209+
"op": "and",
1210+
"args": [
1211+
{"op": ">=", "args": [{"property": "datetime"}, range_start]},
1212+
{"op": "<=", "args": [{"property": "datetime"}, range_end]},
1213+
],
1214+
},
1215+
}
1216+
resp = await app_client.post("/search", json=cql2_between)
1217+
assert resp.status_code == 200
1218+
resp_json = resp.json()
1219+
assert resp_json["features"][0]["id"] == test_item["id"]
1220+
1221+
1222+
@pytest.mark.asyncio
1223+
async def test_search_cql2_json_start_end_datetime_operators(app_client, ctx):
1224+
"""Test POST search with CQL2-JSON start_datetime and end_datetime filter operators"""
1225+
1226+
test_item = ctx.item
1227+
start_datetime = test_item["properties"]["start_datetime"] # "2020-02-08T12:30:22Z"
1228+
end_datetime = test_item["properties"]["end_datetime"] # "2020-02-16T12:30:22Z"
1229+
1230+
cql2_start_equal = {
1231+
"filter-lang": "cql2-json",
1232+
"filter": {"op": "=", "args": [{"property": "start_datetime"}, start_datetime]},
1233+
}
1234+
resp = await app_client.post("/search", json=cql2_start_equal)
1235+
assert resp.status_code == 200
1236+
resp_json = resp.json()
1237+
assert resp_json["features"][0]["id"] == test_item["id"]
1238+
1239+
later_start = "2020-02-09T12:30:22Z"
1240+
cql2_start_lte = {
1241+
"filter-lang": "cql2-json",
1242+
"filter": {"op": "<=", "args": [{"property": "start_datetime"}, later_start]},
1243+
}
1244+
resp = await app_client.post("/search", json=cql2_start_lte)
1245+
assert resp.status_code == 200
1246+
resp_json = resp.json()
1247+
assert resp_json["features"][0]["id"] == test_item["id"]
1248+
1249+
earlier_start = "2020-02-07T12:30:22Z"
1250+
cql2_start_gte = {
1251+
"filter-lang": "cql2-json",
1252+
"filter": {"op": ">=", "args": [{"property": "start_datetime"}, earlier_start]},
1253+
}
1254+
resp = await app_client.post("/search", json=cql2_start_gte)
1255+
assert resp.status_code == 200
1256+
resp_json = resp.json()
1257+
assert resp_json["features"][0]["id"] == test_item["id"]
1258+
1259+
start_range_start = "2020-02-08T00:00:00Z"
1260+
start_range_end = "2020-02-09T00:00:00Z"
1261+
cql2_start_between = {
1262+
"filter-lang": "cql2-json",
1263+
"filter": {
1264+
"op": "and",
1265+
"args": [
1266+
{
1267+
"op": ">=",
1268+
"args": [{"property": "start_datetime"}, start_range_start],
1269+
},
1270+
{"op": "<=", "args": [{"property": "start_datetime"}, start_range_end]},
1271+
],
1272+
},
1273+
}
1274+
resp = await app_client.post("/search", json=cql2_start_between)
1275+
assert resp.status_code == 200
1276+
resp_json = resp.json()
1277+
assert resp_json["features"][0]["id"] == test_item["id"]
1278+
1279+
cql2_end_equal = {
1280+
"filter-lang": "cql2-json",
1281+
"filter": {"op": "=", "args": [{"property": "end_datetime"}, end_datetime]},
1282+
}
1283+
resp = await app_client.post("/search", json=cql2_end_equal)
1284+
assert resp.status_code == 200
1285+
resp_json = resp.json()
1286+
assert resp_json["features"][0]["id"] == test_item["id"]
1287+
1288+
later_end = "2020-02-17T12:30:22Z"
1289+
cql2_end_lte = {
1290+
"filter-lang": "cql2-json",
1291+
"filter": {"op": "<=", "args": [{"property": "end_datetime"}, later_end]},
1292+
}
1293+
resp = await app_client.post("/search", json=cql2_end_lte)
1294+
assert resp.status_code == 200
1295+
resp_json = resp.json()
1296+
assert resp_json["features"][0]["id"] == test_item["id"]
1297+
1298+
earlier_end = "2020-02-15T12:30:22Z"
1299+
cql2_end_gte = {
1300+
"filter-lang": "cql2-json",
1301+
"filter": {"op": ">=", "args": [{"property": "end_datetime"}, earlier_end]},
1302+
}
1303+
resp = await app_client.post("/search", json=cql2_end_gte)
1304+
assert resp.status_code == 200
1305+
resp_json = resp.json()
1306+
assert resp_json["features"][0]["id"] == test_item["id"]
1307+
1308+
end_range_start = "2020-02-16T00:00:00Z"
1309+
end_range_end = "2020-02-17T00:00:00Z"
1310+
cql2_end_between = {
1311+
"filter-lang": "cql2-json",
1312+
"filter": {
1313+
"op": "and",
1314+
"args": [
1315+
{"op": ">=", "args": [{"property": "end_datetime"}, end_range_start]},
1316+
{"op": "<=", "args": [{"property": "end_datetime"}, end_range_end]},
1317+
],
1318+
},
1319+
}
1320+
resp = await app_client.post("/search", json=cql2_end_between)
1321+
assert resp.status_code == 200
1322+
resp_json = resp.json()
1323+
assert resp_json["features"][0]["id"] == test_item["id"]
1324+
1325+
cql2_start_end_range = {
1326+
"filter-lang": "cql2-json",
1327+
"filter": {
1328+
"op": "and",
1329+
"args": [
1330+
{
1331+
"op": ">=",
1332+
"args": [{"property": "start_datetime"}, "2020-02-07T12:30:22Z"],
1333+
},
1334+
{
1335+
"op": "<=",
1336+
"args": [{"property": "end_datetime"}, "2020-02-17T12:30:22Z"],
1337+
},
1338+
],
1339+
},
1340+
}
1341+
resp = await app_client.post("/search", json=cql2_start_end_range)
1342+
assert resp.status_code == 200
1343+
resp_json = resp.json()
1344+
assert resp_json["features"][0]["id"] == test_item["id"]
1345+
1346+
1347+
@pytest.mark.asyncio
1348+
async def test_select_indexes(txn_client, load_test_data):
1349+
"""Run select_indexes test."""
1350+
1351+
database = txn_client.database
1352+
index_selector = database.async_index_selector
1353+
1354+
collection = load_test_data("test_collection.json")
1355+
collection_id = "test-collection-1"
1356+
collection["id"] = collection_id
1357+
1358+
test_item = load_test_data("test_item.json")
1359+
test_item["id"] = "test-item-1"
1360+
1361+
result = await index_selector.select_indexes(
1362+
["test-collection-1"],
1363+
{"gte": "2024-01-01T00:00:00Z", "lte": "2024-12-31T23:59:59Z"},
1364+
)
1365+
1366+
assert result is not None
1367+
assert result == "items_test-collection-1"

0 commit comments

Comments
 (0)