|
2 | 2 | import base64
|
3 | 3 | import logging
|
4 | 4 | import os
|
| 5 | +import re |
5 | 6 | from typing import Any, Dict, Iterable, List, Optional, Protocol, Tuple, Type, Union
|
6 | 7 |
|
7 | 8 | import attr
|
@@ -229,14 +230,12 @@ async def get_one_item(self, collection_id: str, item_id: str) -> Dict:
|
229 | 230 | @staticmethod
|
230 | 231 | def make_search():
|
231 | 232 | """Database logic to create a Search instance."""
|
232 |
| - # return Search().sort(*DEFAULT_SORT) |
233 |
| - print("make_search hello") |
234 | 233 | return MongoSearchAdapter()
|
235 | 234 |
|
236 | 235 | @staticmethod
|
237 | 236 | def apply_ids_filter(search: MongoSearchAdapter, item_ids: List[str]):
|
238 | 237 | """Database logic to search a list of STAC item ids."""
|
239 |
| - search.add_filter({"_id": {"$in": item_ids}}) |
| 238 | + search.add_filter({"id": {"$in": item_ids}}) |
240 | 239 | return search
|
241 | 240 |
|
242 | 241 | @staticmethod
|
@@ -405,7 +404,19 @@ def translate_cql2_to_mongo(cql2_filter: Dict[str, Any]) -> Dict[str, Any]:
|
405 | 404 | return {"geometry": {"$geoIntersects": {"$geometry": geometry}}}
|
406 | 405 |
|
407 | 406 | elif cql2_filter["op"] == "between":
|
408 |
| - property_path = "properties." + cql2_filter["args"][0]["property"] |
| 407 | + property_name = cql2_filter["args"][0]["property"] |
| 408 | + |
| 409 | + # Use the special mapping directly if available, or construct the path appropriately |
| 410 | + if property_name in filter.queryables_mapping: |
| 411 | + property_path = filter.queryables_mapping[property_name] |
| 412 | + elif property_name not in [ |
| 413 | + "id", |
| 414 | + "collection", |
| 415 | + ] and not property_name.startswith("properties."): |
| 416 | + property_path = f"properties.{property_name}" |
| 417 | + else: |
| 418 | + property_path = property_name |
| 419 | + |
409 | 420 | lower_bound = cql2_filter["args"][1]
|
410 | 421 | upper_bound = cql2_filter["args"][2]
|
411 | 422 | return {property_path: {"$gte": lower_bound, "$lte": upper_bound}}
|
@@ -442,9 +453,22 @@ def translate_cql2_to_mongo(cql2_filter: Dict[str, Any]) -> Dict[str, Any]:
|
442 | 453 | )
|
443 | 454 |
|
444 | 455 | if mongo_op == "$regex":
|
445 |
| - return { |
446 |
| - property_path: {mongo_op: value.replace("%", ".*"), "$options": "i"} |
447 |
| - } |
| 456 | + # Replace SQL LIKE wildcards with regex equivalents, handling escaped characters |
| 457 | + regex_pattern = re.sub( |
| 458 | + r"(?<!\\)%", ".*", value |
| 459 | + ) # Replace '%' with '.*', ignoring escaped '\%' |
| 460 | + regex_pattern = re.sub( |
| 461 | + r"(?<!\\)_", ".", regex_pattern |
| 462 | + ) # Replace '_' with '.', ignoring escaped '\_' |
| 463 | + |
| 464 | + # Handle escaped wildcards by reverting them to their literal form |
| 465 | + regex_pattern = regex_pattern.replace("\\%", "%").replace("\\_", "_") |
| 466 | + |
| 467 | + # Ensure backslashes are properly escaped for MongoDB regex |
| 468 | + regex_pattern = regex_pattern.replace("\\", "\\\\") |
| 469 | + |
| 470 | + return {property_path: {"$regex": regex_pattern, "$options": "i"}} |
| 471 | + |
448 | 472 | elif mongo_op == "$in":
|
449 | 473 | if not isinstance(value, list):
|
450 | 474 | raise ValueError(f"Arg {value} is not a list")
|
|
0 commit comments