Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix QuerySet results when Q() conditions are empty or full #23

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/test-python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ jobs:
lookup.tests.LookupQueryingTests.test_isnull_lookup_in_filter
model_fields
or_lookups
queries.tests.Ticket12807Tests.test_ticket_12807
sessions_tests
update

Expand Down
7 changes: 5 additions & 2 deletions django_mongodb/compiler.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from django.conf import settings
from django.core.exceptions import EmptyResultSet
from django.core.exceptions import EmptyResultSet, FullResultSet
from django.db import (
DatabaseError,
IntegrityError,
Expand Down Expand Up @@ -128,7 +128,10 @@ def build_query(self, columns=None):
self.check_query()
self.setup_query()
query = self.query_class(self, columns)
query.add_filters(self.query.where)
try:
query.add_filters(self.query.where)
except FullResultSet:
query.mongo_query = []
query.order_by(self._get_ordering())

# This at least satisfies the most basic unit tests.
Expand Down
2 changes: 0 additions & 2 deletions django_mongodb/features.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
# 'TruncDate' object has no attribute 'alias'
"model_fields.test_datetimefield.DateTimeFieldTests.test_lookup_date_with_use_tz",
"model_fields.test_datetimefield.DateTimeFieldTests.test_lookup_date_without_use_tz",
# Empty queryset ORed (|) with another gives empty results.
"or_lookups.tests.OrLookupsTests.test_empty_in",
}

django_test_skips = {
Expand Down
38 changes: 35 additions & 3 deletions django_mongodb/query.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import re
from functools import wraps

from django.core.exceptions import FullResultSet
from django.core.exceptions import EmptyResultSet, FullResultSet
from django.db import DatabaseError, IntegrityError, NotSupportedError
from django.db.models.lookups import UUIDTextMixin
from django.db.models.query import QuerySet
from django.db.models.sql.where import OR, SubqueryConstraint
from django.db.models.sql.where import AND, OR, SubqueryConstraint
from django.utils.tree import Node
from pymongo import ASCENDING, DESCENDING
from pymongo.errors import DuplicateKeyError, PyMongoError
Expand Down Expand Up @@ -142,6 +142,11 @@ def get_cursor(self):
def add_filters(self, filters, query=None):
children = self._get_children(filters.children)

if filters.connector == AND:
full_needed, empty_needed = len(children), 1
else:
full_needed, empty_needed = 1, len(children)

if query is None:
query = self.mongo_query

Expand All @@ -162,7 +167,20 @@ def add_filters(self, filters, query=None):
if filters.connector == OR and filters.negated:
raise NotImplementedError("Negated ORs are not supported.")

self.add_filters(child, query=subquery)
try:
self.add_filters(child, query=subquery)
except EmptyResultSet:
empty_needed -= 1
if empty_needed == 0:
exc = FullResultSet if filters.negated else EmptyResultSet
raise exc from None
continue
except FullResultSet:
full_needed -= 1
if full_needed == 0:
exc = EmptyResultSet if filters.negated else FullResultSet
raise exc from None
continue

if filters.connector == OR and subquery:
or_conditions.extend(subquery.pop("$or", []))
Expand All @@ -173,7 +191,21 @@ def add_filters(self, filters, query=None):

try:
field, lookup_type, value = self._decode_child(child)
except EmptyResultSet:
empty_needed -= 1
if empty_needed == 0:
if filters.negated:
self._negated = not self._negated
exc = FullResultSet if filters.negated else EmptyResultSet
raise exc from None
continue
except FullResultSet:
full_needed -= 1
if full_needed == 0:
if filters.negated:
self._negated = not self._negated
exc = EmptyResultSet if filters.negated else FullResultSet
raise exc from None
continue

column = field.column
Expand Down
Loading