Skip to content

Commit 22a43d4

Browse files
committed
getField support overlay
1 parent 0c27833 commit 22a43d4

File tree

1 file changed

+46
-14
lines changed

1 file changed

+46
-14
lines changed

django_mongodb_backend/query_conversion/expression_converters.py

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,45 @@ class BaseConverter:
1010
def convert(cls, expr):
1111
raise NotImplementedError("Subclasses must implement this method.")
1212

13+
@classmethod
14+
def is_simple_field_name(cls, field_name):
15+
return (
16+
isinstance(field_name, str)
17+
and field_name != ""
18+
and field_name.startswith("$")
19+
# Special case for _ separated field names
20+
and field_name[1:].replace("_", "").isalnum()
21+
)
22+
23+
@classmethod
24+
def is_simple_get_field(cls, get_field_object):
25+
if not isinstance(get_field_object, dict):
26+
return False
27+
28+
get_field_expr = get_field_object.get("$getField")
29+
30+
if (
31+
isinstance(get_field_expr, dict)
32+
and "input" in get_field_expr
33+
and "field" in get_field_expr
34+
):
35+
input_expr = get_field_expr["input"]
36+
field_name = get_field_expr["field"]
37+
return cls.convert_field_name(input_expr) and (
38+
isinstance(field_name, str) and not field_name.startswith("$")
39+
)
40+
return False
41+
42+
@classmethod
43+
def convert_field_name(cls, field_name):
44+
if cls.is_simple_field_name(field_name):
45+
return field_name[1:]
46+
if cls.is_simple_get_field(field_name):
47+
get_field_input = field_name["$getField"]["input"]
48+
get_field_field = field_name["$getField"]["field"]
49+
return f"{cls.convert_field_name(get_field_input)}.{get_field_field}"
50+
return None
51+
1352
@classmethod
1453
def is_simple_value(cls, value):
1554
"""Is the value is a simple type (not a dict)?"""
@@ -19,7 +58,6 @@ def is_simple_value(cls, value):
1958
return False
2059
if isinstance(value, (list, tuple, set)):
2160
return all(cls.is_simple_value(v) for v in value)
22-
# TODO: Support `$getField` conversion.
2361
return not isinstance(value, dict)
2462

2563

@@ -35,12 +73,7 @@ def convert(cls, args):
3573
if isinstance(args, list) and len(args) == 2:
3674
field_expr, value = args
3775
# Check if first argument is a simple field reference.
38-
if (
39-
isinstance(field_expr, str)
40-
and field_expr.startswith("$")
41-
and cls.is_simple_value(value)
42-
):
43-
field_name = field_expr[1:] # Remove the $ prefix.
76+
if (field_name := cls.convert_field_name(field_expr)) and cls.is_simple_value(value):
4477
if cls.operator == "$eq":
4578
return {field_name: value}
4679
return {field_name: {cls.operator: value}}
@@ -135,13 +168,12 @@ def convert(cls, in_args):
135168
field_expr, values = in_args
136169

137170
# Check if first argument is a simple field reference
138-
if isinstance(field_expr, str) and field_expr.startswith("$"):
139-
field_name = field_expr[1:] # Remove the $ prefix
140-
if isinstance(values, (list, tuple, set)) and all(
141-
cls.is_simple_value(v) for v in values
142-
):
143-
return {field_name: {"$in": values}}
144-
171+
# Check if second argument is a list of simple values
172+
if (field_name := cls.convert_field_name(field_expr)) and (
173+
isinstance(values, list | tuple | set)
174+
and all(cls.is_simple_value(v) for v in values)
175+
):
176+
return {field_name: {"$in": values}}
145177
return None
146178

147179

0 commit comments

Comments
 (0)