Skip to content

Commit da37a09

Browse files
author
Peng Ren
committed
Add date conversion functions in where clause
1 parent 119d626 commit da37a09

7 files changed

Lines changed: 1024 additions & 6 deletions

pymongosql/sql/handler.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,12 @@ def _parse_value(self, value_text: str) -> Any:
134134
"""Parse string value to appropriate Python type"""
135135
value_text = value_text.strip()
136136

137+
# Check if this is a function call (e.g., date('2025-01-01'))
138+
if "(" in value_text and ")" in value_text:
139+
func_result = self._try_parse_function_value(value_text)
140+
if func_result is not None:
141+
return func_result
142+
137143
# Remove parentheses from values
138144
value_text = value_text.strip("()")
139145

@@ -159,6 +165,41 @@ def _parse_value(self, value_text: str) -> Any:
159165

160166
return value_text
161167

168+
def _try_parse_function_value(self, value_text: str) -> Any:
169+
"""Try to parse a function call like date('2025-01-01') in WHERE condition
170+
171+
Uses WhereClauseFunctionRegistry to convert string values to MongoDB types.
172+
Supported functions: DATE, DATETIME, TIMESTAMP
173+
"""
174+
try:
175+
from .where_functions import WhereClauseFunctionRegistry
176+
177+
registry = WhereClauseFunctionRegistry()
178+
func = registry.find_function(value_text)
179+
180+
if func:
181+
# Extract the argument from the function call
182+
# For date('2025-01-01'), extract '2025-01-01'
183+
column, format_param = func.extract_column_and_format(value_text)
184+
185+
# Remove quotes from the argument if it's quoted
186+
if column and (
187+
(column.startswith("'") and column.endswith("'"))
188+
or (column.startswith('"') and column.endswith('"'))
189+
):
190+
column = column[1:-1]
191+
192+
# Convert the value using the WHERE clause function
193+
if column:
194+
result = func.convert_value(column, format_param)
195+
_logger.debug(f"WHERE function {func.function_name} converted '{column}' to {result}")
196+
return result
197+
198+
return None
199+
except Exception as e:
200+
_logger.debug(f"Failed to parse function value '{value_text}': {e}")
201+
return None
202+
162203

163204
class BaseHandler(ABC):
164205
"""Unified base class for all handlers (expression and visitor)"""

pymongosql/sql/projection_functions.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,16 @@ def convert_value(self, value: Any, format_param: Optional[str] = None) -> Any:
8282
pass
8383

8484
# Fallback: try common formats
85-
for fmt in ["%Y-%m-%dT%H:%M:%SZ", "%Y-%m-%d", "%d-%m-%Y", "%m/%d/%Y"]:
85+
# Order matters: try more specific patterns first
86+
for fmt in [
87+
"%Y-%m-%dT%H:%M:%SZ", # ISO with time
88+
"%Y-%m-%d", # ISO date
89+
"%d/%m/%Y", # EU format DD/MM/YYYY
90+
"%d-%m-%Y", # EU format DD-MM-YYYY
91+
"%d.%m.%Y", # EU format DD.MM.YYYY
92+
"%m/%d/%Y", # US format MM/DD/YYYY
93+
"%m-%d-%Y", # US format MM-DD-YYYY
94+
]:
8695
try:
8796
dt = datetime.strptime(value, fmt)
8897
return dt.date()
@@ -204,21 +213,24 @@ def convert_value(self, value: Any, format_param: Optional[str] = None) -> Any:
204213
if isinstance(value, str):
205214
# Try ISO format first
206215
try:
207-
return datetime.fromisoformat(value)
216+
dt = datetime.fromisoformat(value)
217+
return dt
208218
except (ValueError, TypeError):
209219
pass
210220

211221
# Try custom format if provided
212222
if format_param:
213223
try:
214-
return datetime.strptime(value, format_param)
224+
dt = datetime.strptime(value, format_param)
225+
return dt
215226
except (ValueError, TypeError):
216227
pass
217228

218229
# Try common formats
219230
for fmt in ["%Y-%m-%d %H:%M:%S", "%Y-%m-%dT%H:%M:%SZ", "%Y-%m-%d", "%d-%m-%Y", "%m/%d/%Y"]:
220231
try:
221-
return datetime.strptime(value, fmt)
232+
dt = datetime.strptime(value, fmt)
233+
return dt
222234
except ValueError:
223235
continue
224236

0 commit comments

Comments
 (0)