Author: Alex
Date: 2010-06-21 11:11:17 -0500 (Mon, 21 Jun 2010)
New Revision: 13368

Modified:
   django/branches/soc2010/query-refactor/django/contrib/mongodb/base.py
   django/branches/soc2010/query-refactor/django/contrib/mongodb/compiler.py
   django/branches/soc2010/query-refactor/django/db/models/sql/query.py
   django/branches/soc2010/query-refactor/django/db/models/sql/where.py
   django/branches/soc2010/query-refactor/tests/regressiontests/mongodb/tests.py
Log:
[soc2010/query-refactor] Cleaned up implementation of negation in MongoDB, and 
no longer rely on a feature from MongoDB unstable version.

Modified: django/branches/soc2010/query-refactor/django/contrib/mongodb/base.py
===================================================================
--- django/branches/soc2010/query-refactor/django/contrib/mongodb/base.py       
2010-06-21 15:49:56 UTC (rev 13367)
+++ django/branches/soc2010/query-refactor/django/contrib/mongodb/base.py       
2010-06-21 16:11:17 UTC (rev 13368)
@@ -10,6 +10,7 @@
 class DatabaseFeatures(object):
     interprets_empty_strings_as_nulls = False
     typed_columns = False
+    sql_nulls = False
 
 
 class DatabaseOperations(object):

Modified: 
django/branches/soc2010/query-refactor/django/contrib/mongodb/compiler.py
===================================================================
--- django/branches/soc2010/query-refactor/django/contrib/mongodb/compiler.py   
2010-06-21 15:49:56 UTC (rev 13367)
+++ django/branches/soc2010/query-refactor/django/contrib/mongodb/compiler.py   
2010-06-21 16:11:17 UTC (rev 13368)
@@ -1,3 +1,6 @@
+from django.db.models.sql.datastructures import FullResultSet
+
+
 # TODO: ...
 class SQLCompiler(object):
     def __init__(self, query, connection, using):
@@ -5,7 +8,7 @@
         self.connection = connection
         self.using = using
     
-    def get_filters(self, where, correct=False):
+    def get_filters(self, where):
         assert where.connector == "AND"
         filters = {}
         for child in where.children:
@@ -15,13 +18,15 @@
                     if k in filters:
                         v = {"$and": [filters[k], v]}
                     if where.negated:
-                        v = {"$not": v}
-                    filters[k] = v
+                        filters.update(self.negate(k, v))
+                    else:
+                        filters[k] = v
             else:
-                field, val = self.make_atom(*child, **{"negated": 
where.negated})
-                filters[field] = val
-        if correct:
-            self.correct_filters(filters)
+                try:
+                    field, val = self.make_atom(*child, **{"negated": 
where.negated})
+                    filters[field] = val
+                except FullResultSet:
+                    pass
         return filters
     
     def make_atom(self, lhs, lookup_type, value_annotation, params_or_value, 
negated):
@@ -48,17 +53,10 @@
                 val = {"$not": val}
             return column, val
         elif lookup_type == "lt":
+            if negated:
+                return {"$gte": params[0]}
             return column, {"$lt": params[0]}
     
-    def correct_filters(self, filters):
-        for k, v in filters.items():
-            if isinstance(v, dict) and v.keys() == ["$not"]:
-                if isinstance(v["$not"], dict) and v["$not"].keys() == 
["$and"]:
-                    del filters[k]
-                    or_vals = [self.negate(k, v) for v in v["$not"]["$and"]]
-                    assert "$or" not in filters
-                    filters["$or"] = or_vals
-    
     def negate(self, k, v):
         if isinstance(v, dict):
             if v.keys() == ["$not"]:
@@ -76,7 +74,7 @@
         assert self.query.high_mark is None
         assert not self.query.order_by
         
-        filters = self.get_filters(self.query.where, correct=True)
+        filters = self.get_filters(self.query.where)
         return 
self.connection.db[self.query.model._meta.db_table].find(filters)
     
     def results_iter(self):

Modified: django/branches/soc2010/query-refactor/django/db/models/sql/query.py
===================================================================
--- django/branches/soc2010/query-refactor/django/db/models/sql/query.py        
2010-06-21 15:49:56 UTC (rev 13367)
+++ django/branches/soc2010/query-refactor/django/db/models/sql/query.py        
2010-06-21 16:11:17 UTC (rev 13368)
@@ -1077,7 +1077,11 @@
                     # it's short-circuited in the Where class.
                     # We also need to handle the case where a subquery is 
provided
                     entry = self.where_class()
-                    entry.add((Constraint(alias, col, None), 'isnull', True), 
AND)
+                    entry.add((
+                        Constraint(alias, col, None, eliminatable_if=lambda 
connection: not getattr(connection.features, "sql_nulls", True)),
+                        'isnull',
+                        True
+                    ), AND)
                     entry.negate()
                     self.where.add(entry, AND)
 

Modified: django/branches/soc2010/query-refactor/django/db/models/sql/where.py
===================================================================
--- django/branches/soc2010/query-refactor/django/db/models/sql/where.py        
2010-06-21 15:49:56 UTC (rev 13367)
+++ django/branches/soc2010/query-refactor/django/db/models/sql/where.py        
2010-06-21 16:11:17 UTC (rev 13368)
@@ -267,8 +267,9 @@
     An object that can be passed to WhereNode.add() and knows how to
     pre-process itself prior to including in the WhereNode.
     """
-    def __init__(self, alias, col, field):
+    def __init__(self, alias, col, field, eliminatable_if=None):
         self.alias, self.col, self.field = alias, col, field
+        self.elimintable_if = eliminatable_if
 
     def __getstate__(self):
         """Save the state of the Constraint for pickling.
@@ -321,6 +322,9 @@
         except ObjectDoesNotExist:
             raise EmptyShortCircuit
 
+        if self.elimintable_if and self.elimintable_if(connection):
+            raise FullResultSet
+
         return (self.alias, self.col, db_type), params
 
     def relabel_aliases(self, change_map):

Modified: 
django/branches/soc2010/query-refactor/tests/regressiontests/mongodb/tests.py
===================================================================
--- 
django/branches/soc2010/query-refactor/tests/regressiontests/mongodb/tests.py   
    2010-06-21 15:49:56 UTC (rev 13367)
+++ 
django/branches/soc2010/query-refactor/tests/regressiontests/mongodb/tests.py   
    2010-06-21 16:11:17 UTC (rev 13368)
@@ -62,20 +62,8 @@
         q = Group.objects.create(name="Queen", year_formed=1971)
         e = Group.objects.create(name="The E Street Band", year_formed=1972)
         
-        qs = Group.objects.exclude(year_formed=1972)
-        v = qs.query.get_compiler(qs.db).get_filters(qs.query.where, 
correct=True)
-        self.assertEqual(v, {
-            "$or": [
-                {"year_formed": {"$ne": 1972}},
-                {"year_formed": None},
-            ]
-        })
-        # A bug in MongoDB prevents this query from actually working, but test
-        # that we're at least generating the right query.
-        return
-        
         self.assertQuerysetEqual(
-            qs, [
+            Group.objects.exclude(year_formed=1972), [
                 "Queen",
             ],
             lambda g: g.name,
@@ -105,4 +93,10 @@
             [],
             lambda g: g.name
         )
-
+        
+        self.assertQuerysetEqual(
+            Group.objects.exclude(year_formed__lt=1972), [
+                "The E Street Band"
+            ],
+            lambda g: g.name,
+        )

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-upda...@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.

Reply via email to