Author: Alex
Date: 2010-07-19 15:36:07 -0500 (Mon, 19 Jul 2010)
New Revision: 13437

Modified:
   django/branches/soc2010/query-refactor/django/contrib/mongodb/compiler.py
   django/branches/soc2010/query-refactor/django/db/__init__.py
   
django/branches/soc2010/query-refactor/tests/regressiontests/mongodb/models.py
   django/branches/soc2010/query-refactor/tests/regressiontests/mongodb/tests.py
Log:
[soc2010/query-refactor] On unsupported operations raise a useful exception.

Modified: 
django/branches/soc2010/query-refactor/django/contrib/mongodb/compiler.py
===================================================================
--- django/branches/soc2010/query-refactor/django/contrib/mongodb/compiler.py   
2010-07-17 09:33:27 UTC (rev 13436)
+++ django/branches/soc2010/query-refactor/django/contrib/mongodb/compiler.py   
2010-07-19 20:36:07 UTC (rev 13437)
@@ -2,6 +2,7 @@
 
 from pymongo import ASCENDING, DESCENDING
 
+from django.db import UnsupportedDatabaseOperation
 from django.db.models import F
 from django.db.models.sql.datastructures import FullResultSet, EmptyResultSet
 
@@ -43,10 +44,13 @@
                     pass
         return filters
     
-    def make_atom(self, lhs, lookup_type, value_annotation, params_or_value, 
negated):
+    def make_atom(self, lhs, lookup_type, value_annotation, params_or_value,
+        negated):
         assert lookup_type in self.LOOKUP_TYPES, lookup_type
         if hasattr(lhs, "process"):
-            lhs, params = lhs.process(lookup_type, params_or_value, 
self.connection)
+            lhs, params = lhs.process(
+                lookup_type, params_or_value, self.connection
+            )
         else:
             params = Field().get_db_prep_lookup(lookup_type, params_or_value, 
                 connection=self.connection, prepared=True)
@@ -56,7 +60,8 @@
         if column == self.query.model._meta.pk.column:
             column = "_id"
         
-        return column, self.LOOKUP_TYPES[lookup_type](params, 
value_annotation, negated)
+        val = self.LOOKUP_TYPES[lookup_type](params, value_annotation, negated)
+        return column, val
     
     def negate(self, k, v):
         # Regex lookups are of the form {"field": re.compile("pattern") and
@@ -79,14 +84,18 @@
         return None
     
     def build_query(self, aggregates=False):
-        assert len([a for a in self.query.alias_map if 
self.query.alias_refcount[a]]) <= 1
+        if len([a for a in self.query.alias_map if 
self.query.alias_refcount[a]]) > 1:
+            raise UnsupportedDatabaseOperation("MongoDB does not support "
+                "operations across relations.")
+        if self.query.extra:
+            raise UnsupportedDatabaseOperation("MongoDB does not support 
extra().")
         assert not self.query.distinct
-        assert not self.query.extra
         assert not self.query.having
         
         filters = self.get_filters(self.query.where)
         fields = self.get_fields(aggregates=aggregates)
-        cursor = 
self.connection.db[self.query.model._meta.db_table].find(filters, fields=fields)
+        collection = self.connection.db[self.query.model._meta.db_table]
+        cursor = collection.find(filters, fields=fields)
         if self.query.order_by:
             cursor = cursor.sort([
                 (ordering.lstrip("-"), DESCENDING if ordering.startswith("-") 
else ASCENDING)
@@ -125,14 +134,19 @@
             return True
     
     def get_aggregates(self):
+        if len(self.query.aggregates) != 1:
+            raise UnsupportedDatabaseOperation("MongoDB doesn't support "
+                "multiple aggregates in a single query.")
         assert len(self.query.aggregates) == 1
         agg = self.query.aggregates.values()[0]
-        assert (
-            isinstance(agg, self.query.aggregates_module.Count) and (
-                agg.col == "*" or 
-                isinstance(agg.col, tuple) and agg.col == 
(self.query.model._meta.db_table, self.query.model._meta.pk.column)
-            )
-        )
+        if not isinstance(agg, self.query.aggregates_module.Count):
+            raise UnsupportedDatabaseOperation("MongoDB does not support "
+                "aggregates other than Count.")
+        opts = self.query.model._meta
+        if not (agg.col == "*" or agg.col == (opts.db_table, opts.pk.column)):
+            raise UnsupportedDatabaseOperation("MongoDB does not support "
+                "aggregation over fields besides the primary key.")
+
         return [self.build_query(aggregates=True).count()]
 
 
@@ -152,8 +166,7 @@
     def update(self, result_type):
         # TODO: more asserts
         filters = self.get_filters(self.query.where)
-        # TODO: Don't use set for everything, use INC and such where
-        # appropriate.
+
         vals = {}
         for field, o, value in self.query.values:
             if hasattr(value, "evaluate"):

Modified: django/branches/soc2010/query-refactor/django/db/__init__.py
===================================================================
--- django/branches/soc2010/query-refactor/django/db/__init__.py        
2010-07-17 09:33:27 UTC (rev 13436)
+++ django/branches/soc2010/query-refactor/django/db/__init__.py        
2010-07-19 20:36:07 UTC (rev 13437)
@@ -6,7 +6,7 @@
 from django.utils.functional import curry
 
 __all__ = ('backend', 'connection', 'connections', 'router', 'DatabaseError',
-    'IntegrityError', 'DEFAULT_DB_ALIAS')
+    'IntegrityError', 'UnsupportedDatabaseOperation', 'DEFAULT_DB_ALIAS')
 
 
 # For backwards compatibility - Port any old database settings over to
@@ -75,6 +75,12 @@
 connection = connections[DEFAULT_DB_ALIAS]
 backend = load_backend(connection.settings_dict['ENGINE'])
 
+class UnsupportedDatabaseOperation(Exception):
+    """
+    Raised when an operation attempted on a QuerySet is unsupported on the
+    database for it's execution.
+    """
+
 # Register an event that closes the database connection
 # when a Django request is finished.
 def close_connection(**kwargs):

Modified: 
django/branches/soc2010/query-refactor/tests/regressiontests/mongodb/models.py
===================================================================
--- 
django/branches/soc2010/query-refactor/tests/regressiontests/mongodb/models.py  
    2010-07-17 09:33:27 UTC (rev 13436)
+++ 
django/branches/soc2010/query-refactor/tests/regressiontests/mongodb/models.py  
    2010-07-19 20:36:07 UTC (rev 13437)
@@ -7,7 +7,8 @@
     good = models.BooleanField()
     age = models.IntegerField(null=True)
     
-    current_group = models.ForeignKey("Group", null=True)
+    current_group = models.ForeignKey("Group", null=True,
+        related_name="current_artists")
     
     def __unicode__(self):
         return self.name

Modified: 
django/branches/soc2010/query-refactor/tests/regressiontests/mongodb/tests.py
===================================================================
--- 
django/branches/soc2010/query-refactor/tests/regressiontests/mongodb/tests.py   
    2010-07-17 09:33:27 UTC (rev 13436)
+++ 
django/branches/soc2010/query-refactor/tests/regressiontests/mongodb/tests.py   
    2010-07-19 20:36:07 UTC (rev 13437)
@@ -1,5 +1,5 @@
-from django.db import connection
-from django.db.models import Count, F
+from django.db import connection, UnsupportedDatabaseOperation
+from django.db.models import Count, Sum, F
 from django.test import TestCase
 
 from models import Artist, Group
@@ -359,3 +359,36 @@
         # Ensure that closing a connection that was never established doesn't
         # blow up.
         connection.close()
+    
+    def assert_unsupported(self, obj):
+        if callable(obj):
+            # Queryset wrapped in a function (for aggregates and such)
+            self.assertRaises(UnsupportedDatabaseOperation, obj)
+        else:
+            # Just a queryset that blows up on evaluation
+            self.assertRaises(UnsupportedDatabaseOperation, list, obj)
+    
+    def test_unsupported_ops(self):
+        self.assert_unsupported(
+            Artist.objects.filter(current_group__name="The Beatles")
+        )
+        
+        self.assert_unsupported(
+            Artist.objects.extra(select={"a": "1.0"})
+        )
+        
+        self.assert_unsupported(
+            Group.objects.annotate(artists=Count("current_artists"))
+        )
+        
+        self.assert_unsupported(
+            lambda: Artist.objects.aggregate(Sum("age"))
+        )
+        
+        self.assert_unsupported(
+            lambda: Artist.objects.aggregate(Count("age"))
+        )
+        
+        self.assert_unsupported(
+            lambda: Artist.objects.aggregate(Count("id"), Count("pk"))
+        )

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

Reply via email to