Skip to content

Commit 97eb697

Browse files
committed
WIP.
1 parent e8212d7 commit 97eb697

File tree

5 files changed

+37
-23
lines changed

5 files changed

+37
-23
lines changed

django_mongodb_backend/base.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -162,11 +162,11 @@ def _isnull_operator_match(a, b):
162162
{"$or": [DatabaseWrapper._isnull_operator_match(b[1], True), {a: {"$lte": b[1]}}]},
163163
]
164164
},
165-
"iexact": lambda a, b: regex_match(a, ("^", b, {"$literal": "$"}), insensitive=True),
166-
"startswith": lambda a, b: regex_match(a, ("^", b)),
167-
"istartswith": lambda a, b: regex_match(a, ("^", b), insensitive=True),
168-
"endswith": lambda a, b: regex_match(a, (b, {"$literal": "$"})),
169-
"iendswith": lambda a, b: regex_match(a, (b, {"$literal": "$"}), insensitive=True),
165+
"iexact": lambda a, b: regex_match(a, f"^{b}$", insensitive=True),
166+
"startswith": lambda a, b: regex_match(a, f"^{b}"),
167+
"istartswith": lambda a, b: regex_match(a, f"^{b}", insensitive=True),
168+
"endswith": lambda a, b: regex_match(a, f"{b}$"),
169+
"iendswith": lambda a, b: regex_match(a, f"{b}$", insensitive=True),
170170
"contains": lambda a, b: regex_match(a, b),
171171
"icontains": lambda a, b: regex_match(a, b, insensitive=True),
172172
"regex": lambda a, b: regex_match(a, b),

django_mongodb_backend/expressions/builtins.py

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ def order_by(self, compiler, connection):
103103
return self.expression.as_mql(compiler, connection)
104104

105105

106-
def query(self, compiler, connection, get_wrapping_pipeline=None):
106+
def query(self, compiler, connection, get_wrapping_pipeline=None, as_path=False):
107107
subquery_compiler = self.get_compiler(connection=connection)
108108
subquery_compiler.pre_sql_setup(with_col_aliases=False)
109109
field_name, expr = subquery_compiler.columns[0]
@@ -145,6 +145,8 @@ def query(self, compiler, connection, get_wrapping_pipeline=None):
145145
# Erase project_fields since the required value is projected above.
146146
subquery.project_fields = None
147147
compiler.subqueries.append(subquery)
148+
if as_path:
149+
return f"{table_output}.{field_name}"
148150
return f"${table_output}.{field_name}"
149151

150152

@@ -167,20 +169,31 @@ def ref(self, compiler, connection, as_path=False): # noqa: ARG001
167169
return f"{prefix}{refs}"
168170

169171

170-
def star(self, compiler, connection): # noqa: ARG001
172+
def star(self, compiler, connection, **extra): # noqa: ARG001
171173
return {"$literal": True}
172174

173175

174-
def subquery(self, compiler, connection, get_wrapping_pipeline=None):
175-
return self.query.as_mql(compiler, connection, get_wrapping_pipeline=get_wrapping_pipeline)
176+
def subquery(self, compiler, connection, get_wrapping_pipeline=None, **extra):
177+
return self.query.as_mql(
178+
compiler, connection, get_wrapping_pipeline=get_wrapping_pipeline, **extra
179+
)
176180

177181

178-
def exists(self, compiler, connection, get_wrapping_pipeline=None):
182+
def exists(self, compiler, connection, get_wrapping_pipeline=None, as_path=False, **extra):
179183
try:
180-
lhs_mql = subquery(self, compiler, connection, get_wrapping_pipeline=get_wrapping_pipeline)
184+
lhs_mql = subquery(
185+
self,
186+
compiler,
187+
connection,
188+
get_wrapping_pipeline=get_wrapping_pipeline,
189+
as_path=as_path,
190+
**extra,
191+
)
181192
except EmptyResultSet:
182193
return Value(False).as_mql(compiler, connection)
183-
return connection.mongo_operators["isnull"](lhs_mql, False)
194+
if as_path:
195+
return connection.mongo_operators_match["isnull"](lhs_mql, False)
196+
return connection.mongo_operators_expr["isnull"](lhs_mql, False)
184197

185198

186199
def when(self, compiler, connection, **extra):

django_mongodb_backend/lookups.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from django.db import NotSupportedError
2-
from django.db.models.expressions import Value
2+
from django.db.models.expressions import Col, Ref, Value
33
from django.db.models.fields.related_lookups import In, RelatedIn
44
from django.db.models.lookups import (
55
BuiltinLookup,
@@ -16,9 +16,13 @@ def is_constant_value(value):
1616
return is_direct_value(value) or isinstance(value, Value)
1717

1818

19+
def is_simple_column(lhs):
20+
return isinstance(lhs, Col | Ref)
21+
22+
1923
def builtin_lookup(self, compiler, connection, as_expr=False):
2024
value = process_rhs(self, compiler, connection)
21-
if is_constant_value(self.rhs) and not as_expr:
25+
if is_simple_column(self.lhs) and is_constant_value(self.rhs) and not as_expr:
2226
lhs_mql = process_lhs(self, compiler, connection, as_path=True)
2327
return connection.mongo_operators_match[self.lookup_name](lhs_mql, value)
2428

django_mongodb_backend/query.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111
from django.db.models.sql.where import AND, OR, XOR, ExtraWhere, NothingNode, WhereNode
1212
from pymongo.errors import BulkWriteError, DuplicateKeyError, PyMongoError
1313

14-
from .query_conversion.query_optimizer import convert_expr_to_match
15-
1614

1715
def wrap_database_errors(func):
1816
@wraps(func)
@@ -89,7 +87,7 @@ def get_pipeline(self):
8987
for query in self.subqueries or ():
9088
pipeline.extend(query.get_pipeline())
9189
if self.match_mql:
92-
pipeline.extend(convert_expr_to_match(self.match_mql))
90+
pipeline.append({"$match": self.match_mql})
9391
if self.aggregation_pipeline:
9492
pipeline.extend(self.aggregation_pipeline)
9593
if self.project_fields:
@@ -275,7 +273,7 @@ def _get_reroot_replacements(expression):
275273
return lookup_pipeline
276274

277275

278-
def where_node(self, compiler, connection):
276+
def where_node(self, compiler, connection, **extra):
279277
if self.connector == AND:
280278
full_needed, empty_needed = len(self.children), 1
281279
else:
@@ -298,14 +296,14 @@ def where_node(self, compiler, connection):
298296
if len(self.children) > 2:
299297
rhs_sum = Mod(rhs_sum, 2)
300298
rhs = Exact(1, rhs_sum)
301-
return self.__class__([lhs, rhs], AND, self.negated).as_mql(compiler, connection)
299+
return self.__class__([lhs, rhs], AND, self.negated).as_mql(compiler, connection, **extra)
302300
else:
303301
operator = "$or"
304302

305303
children_mql = []
306304
for child in self.children:
307305
try:
308-
mql = child.as_mql(compiler, connection)
306+
mql = child.as_mql(compiler, connection, **extra)
309307
except EmptyResultSet:
310308
empty_needed -= 1
311309
except FullResultSet:
@@ -332,7 +330,7 @@ def where_node(self, compiler, connection):
332330
raise FullResultSet
333331

334332
if self.negated and mql:
335-
mql = {"$nor": mql}
333+
mql = {"$nor": [mql]}
336334

337335
return mql
338336

django_mongodb_backend/query_utils.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,7 @@ def regex_expr(field, regex_vals, insensitive=False):
5353
return {"$regexMatch": {"input": field, "regex": regex, "options": options}}
5454

5555

56-
def regex_match(field, regex_vals, insensitive=False):
57-
regex = {"$concat": regex_vals} if isinstance(regex_vals, tuple) else regex_vals
56+
def regex_match(field, regex, insensitive=False):
5857
options = "i" if insensitive else ""
5958
# return {"$regexMatch": {"input": field, "regex": regex, "options": options}}
6059
return {field: {"$regex": regex, "$options": options}}

0 commit comments

Comments
 (0)