Spaces:
Running
Running
from typing import Dict, Any | |
import ast | |
from typing import Any, Dict | |
def clean_modified_dict(modified_dict: Dict[str, Any]) -> Dict[str, Any]: | |
""" | |
Cleans the modified dictionary by removing only values that are: | |
- None | |
- empty list [] | |
- empty dict {} | |
- empty string '' | |
But keeps values like 0, False, etc. | |
""" | |
def is_meaningfully_empty(value): | |
return value in (None, '', []) or (isinstance(value, dict) and not value) | |
return {k: v for k, v in modified_dict.items() if not is_meaningfully_empty(v)} | |
def convert_to_lines(query_dict): | |
lines = [] | |
for field, condition in query_dict.items(): | |
if isinstance(condition, dict): | |
for operator, value in condition.items(): | |
# Special handling for $ne with '' or [] | |
if operator in ['$ne', 'ne']: | |
if value == '': | |
value_str = "''" | |
elif value == []: | |
value_str = '[]' | |
elif isinstance(value, list): | |
value_str = ','.join(map(str, value)) | |
elif isinstance(value, str): | |
value_str = f"'{value}'" | |
else: | |
value_str = str(int(value) if isinstance(value, float) and value.is_integer() else value) | |
elif isinstance(value, list): | |
# Output lists as valid Python lists for complex cases | |
value_str = repr(value) | |
elif isinstance(value, str): | |
value_str = f"'{value}'" | |
else: | |
value_str = str(int(value) if isinstance(value, float) and value.is_integer() else value) | |
lines.append(f"{field} {operator} {value_str}") | |
else: | |
if isinstance(condition, str): | |
condition_str = f"'{condition}'" | |
else: | |
condition_str = str(condition) | |
lines.append(f"{field} = {condition_str}") | |
return '\n'.join(lines) | |
def parse_line_based_query(lines): | |
query = {} | |
for line in lines.strip().split('\n'): | |
if not line.strip(): | |
continue | |
parts = line.split(maxsplit=2) | |
if len(parts) < 3: | |
# If operator is present but value is empty, set value to empty string | |
if len(parts) == 2: | |
field, operator = parts | |
value = '' | |
else: | |
continue # Skip invalid lines | |
else: | |
field, operator, value = parts | |
# Special handling for sort, limit, skip, etc. | |
if field in {"sort", "order_by"}: | |
# Handle both 'sort field value' and 'sort = {field: value}' | |
if operator == "=": | |
query[field] = _convert_value(value) | |
else: | |
if field not in query: | |
query[field] = {} | |
query[field][operator] = _convert_value(value) | |
continue | |
if field in {"limit", "skip", "offset"}: | |
query[field] = _convert_value(value) | |
continue | |
# Special handling for _original_numbers (parse value as string if quoted, else as number) | |
if field == "_original_numbers": | |
if field not in query: | |
query[field] = {} | |
v = value.strip() | |
if (v.startswith("'") and v.endswith("'")) or (v.startswith('"') and v.endswith('"')): | |
query[field][operator] = v[1:-1] | |
else: | |
try: | |
# Try to parse as int or float | |
query[field][operator] = int(v) | |
except ValueError: | |
try: | |
query[field][operator] = float(v) | |
except ValueError: | |
query[field][operator] = v | |
continue | |
# Handle equality operator | |
if operator == "=": | |
query[field] = _convert_value(value) | |
continue | |
# Handle other operators | |
# If operator is $in, $nin, $all and value is empty, use [] | |
empty_list_ops = {'in', '$in', 'nin', '$nin', 'all', '$all'} | |
op_key = operator if operator.startswith('$') else f'${operator}' | |
if operator in empty_list_ops and value == '': | |
value_obj = [] | |
elif operator in {'ne', '$ne'}: | |
if value.strip() == '[]': | |
value_obj = [] | |
elif value.strip() == "''" or value.strip() == '""': | |
value_obj = '' | |
elif value == '': | |
value_obj = [] | |
else: | |
value_obj = _convert_value(value, operator) | |
else: | |
value_obj = _convert_value(value, operator) | |
if field in query: | |
if isinstance(query[field], dict): | |
query[field][op_key] = value_obj | |
else: | |
raise ValueError(f"Conflict in {field}: direct value and operator") | |
else: | |
query[field] = {op_key: value_obj} | |
return query | |
def _convert_value(value_str, operator=None): | |
"""Convert string values to appropriate types""" | |
# Handle lists for $in and $all operators | |
if operator in ('in', '$in', 'all', '$all'): | |
s = value_str.strip() | |
if s.startswith('[') and s.endswith(']'): | |
try: | |
return ast.literal_eval(s) | |
except Exception: | |
pass | |
if ',' in value_str: | |
return [_parse_single_value(v) for v in value_str.split(',')] | |
# Handle regex flags (e.g., "pattern i" → "pattern" with $options: 'i') | |
if operator == 'regex' and ' ' in value_str: | |
pattern, *flags = value_str.split() | |
return {'$regex': pattern, '$options': ''.join(flags)} | |
return _parse_single_value(value_str) | |
def _parse_single_value(s): | |
"""Convert individual values to int/float/string/dict/bool""" | |
s = s.strip() | |
# Remove surrounding quotes if present | |
if (s.startswith("'") and s.endswith("'")) or (s.startswith('"') and s.endswith('"')): | |
return s[1:-1].strip() # Always return as string if quoted | |
# Handle None | |
if s == 'None': | |
return None | |
# Try to parse as dict if it looks like one | |
if (s.startswith('{') and s.endswith('}')) or (s.startswith('[') and s.endswith(']')): | |
try: | |
return ast.literal_eval(s) | |
except Exception: | |
pass | |
# Handle booleans | |
if s.lower() == 'true': | |
return True | |
if s.lower() == 'false': | |
return False | |
try: | |
return int(s) | |
except ValueError: | |
try: | |
return float(s) | |
except ValueError: | |
return s | |