Commits

Mike Bayer committed c0d0a74

- we're going to attempt to get the type/operator system to eat its own dogfood and
use the type-based comparator in all cases. will attempt to remove the _adapt_expression()
method entirely as this represents an incomplete and redundant system (though it might
be a lot faster)

Comments (0)

Files changed (4)

lib/sqlalchemy/sql/expression.py

             if isinstance(other, (SelectBase, Alias)):
                 other = other.as_scalar()
             return other
+        elif isinstance(other, sqltypes.TypeEngine.Comparator):
+            return other.expr
         elif not isinstance(other, ClauseElement):
             return expr._bind_param(operator, other)
         elif isinstance(other, (SelectBase, Alias)):
     __visit_name__ = 'column'
     primary_key = False
     foreign_keys = []
-    type = None
     quote = None
     _label = None
     _key_label = None
     _alt_names = ()
 
     @util.memoized_property
+    def type(self):
+        return sqltypes.NULLTYPE
+
+    @util.memoized_property
     def comparator(self):
-        if self.type is None:
-            return None
-        elif self.type.comparator_factory is not None:
-            return self.type.comparator_factory(self)
-        else:
-            return None
+        return self.type.comparator_factory(self)
+
+    #def _assert_comparator(self):
+    #    assert self.comparator.expr is self
 
     def __getattr__(self, key):
-        if self.comparator is None:
-            raise AttributeError(key)
+        #self._assert_comparator()
         try:
             return getattr(self.comparator, key)
         except AttributeError:
                     key)
             )
 
-    @property
-    def expression(self):
-        """Return a column expression.
-
-        Part of the inspection interface; returns self.
-
-        """
-        return self
-
     def operate(self, op, *other, **kwargs):
-        if self.comparator:
-            return op(self.comparator, *other, **kwargs)
-        else:
-            return _DEFAULT_COMPARATOR.operate(self, op, *other, **kwargs)
+        #self._assert_comparator()
+        return op(self.comparator, *other, **kwargs)
 
     def reverse_operate(self, op, other, **kwargs):
-        if self.comparator:
-            return op(other, self.comparator, **kwargs)
-        else:
-            return _DEFAULT_COMPARATOR.reverse_operate(self, op, other, **kwargs)
+        #self._assert_comparator()
+        return op(other, self.comparator, **kwargs)
 
     def _bind_param(self, operator, obj):
         return BindParameter(None, obj,
                                     _compared_to_type=self.type, unique=True)
 
     @property
+    def expression(self):
+        """Return a column expression.
+
+        Part of the inspection interface; returns self.
+
+        """
+        return self
+
+    @property
     def _select_iterable(self):
         return (self, )
 
 
     def __init__(self, element):
         self.element = element
-        self.type = getattr(element, 'type', None)
+        self.type = getattr(element, 'type', sqltypes.NULLTYPE)
 
     @property
     def _label(self):

lib/sqlalchemy/sql/util.py

             element.c
 
         self.__dict__ = element.__dict__.copy()
+        self.__dict__.pop('comparator', None)
         self.__element = element
         self._annotations = values
 
     def _with_annotations(self, values):
         clone = self.__class__.__new__(self.__class__)
         clone.__dict__ = self.__dict__.copy()
+        clone.__dict__.pop('comparator', None)
         clone._annotations = values
         return clone
 

lib/sqlalchemy/types.py

         type level.  See :attr:`.TypeEngine.comparator_factory`.
 
         """
+
         def __init__(self, expr):
             self.expr = expr
 
+        def __reduce__(self):
+            return _reconstitute_comparator, (self.expr, )
+
         def operate(self, op, *other, **kwargs):
             return _DEFAULT_COMPARATOR.operate(self.expr, op, *other, **kwargs)
 
             return _DEFAULT_COMPARATOR.reverse_operate(self.expr, op, other,
                                                 **kwargs)
 
-    comparator_factory = None
+    comparator_factory = Comparator
     """A :class:`.TypeEngine.Comparator` class which will apply
     to operations performed by owning :class:`.ColumnElement` objects.
 
     def __repr__(self):
         return util.generic_repr(self)
 
+def _reconstitute_comparator(expression):
+    return expression.comparator
+
 class UserDefinedType(TypeEngine):
     """Base for user defined types.
 

test/lib/profiles.txt

 # /Users/classic/dev/sqla_comparators/./test/lib/profiles.txt
 # This file is written out on a per-environment basis.
-# For each test in aaa_profiling, the corresponding function and 
+# For each test in aaa_profiling, the corresponding function and
 # environment is located within this file.  If it doesn't exist,
 # the test is skipped.
-# If a callcount does exist, it is compared to what we received. 
+# If a callcount does exist, it is compared to what we received.
 # assertions are raised if the counts do not match.
-# 
-# To add a new callcount test, apply the function_call_count 
-# decorator and re-run the tests using the --write-profiles option - 
+#
+# To add a new callcount test, apply the function_call_count
+# decorator and re-run the tests using the --write-profiles option -
 # this file will be rewritten including the new count.
-# 
+#
 
 # TEST: test.aaa_profiling.test_compiler.CompileTest.test_insert
 
 
 # TEST: test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile
 
-test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 2.6_sqlite_pysqlite_nocextensions 12
-test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 2.7_mysql_mysqldb_cextensions 12
-test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 2.7_mysql_mysqldb_nocextensions 12
-test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 2.7_postgresql_psycopg2_cextensions 12
-test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 2.7_postgresql_psycopg2_nocextensions 12
-test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 2.7_sqlite_pysqlite_cextensions 12
-test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 2.7_sqlite_pysqlite_nocextensions 12
 
 # TEST: test.aaa_profiling.test_resultset.ResultSetTest.test_string