Spaces:
Running
Running
File size: 6,707 Bytes
0a65f9d |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
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
|