Commits

Mike Bayer committed cf0cb4a

- all tests pass

Comments (0)

Files changed (7)

lib/sqlalchemy/orm/interfaces.py

 
         return self.__class__(self.prop, self.mapper, adapter)
 
-    def __getattr__(self, key):
-        return getattr(self.__clause_element__(), key)
-
     @staticmethod
     def any_op(a, b, **kwargs):
         return a.any(b, **kwargs)

lib/sqlalchemy/orm/properties.py

             else:
                 return self.prop.columns[0]._annotate({
                                                 "parententity": self.mapper,
-                                                "parentmapper":self.mapper})
+                                                "parentmapper": self.mapper})
+
+        def __getattr__(self, key):
+            """proxy attribute access down to the mapped column.
+
+            this allows user-defined comparison methods to be accessed.
+            """
+            return getattr(self.__clause_element__(), key)
 
         def operate(self, op, *other, **kwargs):
             return op(self.__clause_element__(), *other, **kwargs)
 
         if strategy_class:
             self.strategy_class = strategy_class
-        elif self.lazy== 'dynamic':
+        elif self.lazy == 'dynamic':
             from sqlalchemy.orm import dynamic
             self.strategy_class = dynamic.DynaLoader
         else:

lib/sqlalchemy/sql/expression.py

         return self.__compare(expr, op,
                               ClauseList(*args).self_group(against=op),
                               negate=negate_op)
-    def _neg_impl(self):
+    def _neg_impl(self, expr, op, **kw):
         """See :meth:`.ColumnOperators.__neg__`."""
-        return UnaryExpression(self.expr, operator=operators.neg)
-
-    def _startswith_impl(self, other, escape=None):
+        return UnaryExpression(expr, operator=operators.neg)
+
+    def _startswith_impl(self, expr, op, other, escape=None):
         """See :meth:`.ColumnOperators.startswith`."""
         # use __radd__ to force string concat behavior
         return self.__compare(
+            expr,
             operators.like_op,
             literal_column("'%'", type_=sqltypes.String).__radd__(
-                                self._check_literal(operators.like_op, other)
+                                self._check_literal(expr, operators.like_op, other)
                             ),
             escape=escape)
 
-    def _endswith_impl(self, other, escape=None):
+    def _endswith_impl(self, expr, op, other, escape=None):
         """See :meth:`.ColumnOperators.endswith`."""
         return self.__compare(
+            expr,
             operators.like_op,
             literal_column("'%'", type_=sqltypes.String) +
-                self._check_literal(operators.like_op, other),
+                self._check_literal(expr, operators.like_op, other),
             escape=escape)
 
-    def _contains_impl(self, other, escape=None):
+    def _contains_impl(self, expr, op, other, escape=None):
         """See :meth:`.ColumnOperators.contains`."""
         return self.__compare(
+            expr,
             operators.like_op,
             literal_column("'%'", type_=sqltypes.String) +
-                self._check_literal(operators.like_op, other) +
+                self._check_literal(expr, operators.like_op, other) +
                 literal_column("'%'", type_=sqltypes.String),
             escape=escape)
 
-    def _match_impl(self, other):
+    def _match_impl(self, expr, op, other):
         """See :meth:`.ColumnOperators.match`."""
-        return self.__compare(operators.match_op,
-                              self._check_literal(operators.match_op,
+        return self.__compare(expr, operators.match_op,
+                              self._check_literal(expr, operators.match_op,
                               other))
 
-    def _distinct_impl(self):
+    def _distinct_impl(self, expr, op):
         """See :meth:`.ColumnOperators.distinct`."""
-        return UnaryExpression(self, operator=operators.distinct_op,
-                                type_=self.type)
-
-    def _between_impl(self, cleft, cright):
+        return UnaryExpression(expr, operator=operators.distinct_op,
+                                type_=expr.type)
+
+    def _between_impl(self, expr, op, cleft, cright, **kw):
         """See :meth:`.ColumnOperators.between`."""
         return BinaryExpression(
-                self,
+                expr,
                 ClauseList(
-                    self._check_literal(operators.and_, cleft),
-                    self._check_literal(operators.and_, cright),
+                    self._check_literal(expr, operators.and_, cleft),
+                    self._check_literal(expr, operators.and_, cright),
                     operator=operators.and_,
                     group=False),
                 operators.between_op)
         "nullslast_op": (__scalar, nullslast),
         "in_op": (_in_impl, operators.notin_op),
         "collate": (_collate_impl,),
+        "match_op": (_match_impl,),
+        "distinct_op": (_distinct_impl,),
+        "between_op": (_between_impl, ),
+        "contains_op": (_contains_impl, ),
+        "startswith_op": (_startswith_impl,),
+        "endswith_op": (_endswith_impl,),
+        "neg": (_neg_impl,),
     }
 
     def operate(self, expr, op, *other, **kwargs):
         if self.comparator:
             return op(other, self.comparator, **kwargs)
         else:
-            return _DEFAULT_COMPARATOR.reverse_operate(self, op, *other, **kwargs)
+            return _DEFAULT_COMPARATOR.reverse_operate(self, op, other, **kwargs)
 
     def _bind_param(self, operator, obj):
         return BindParameter(None, obj,
                 _literal_as_text(clause)
                 for clause in clauses if clause is not None]
 
-    @util.memoized_property
-    def type(self):
-        if self.clauses:
-            return self.clauses[0].type
-        else:
-            return sqltypes.NULLTYPE
-
     def __iter__(self):
         return iter(self.clauses)
 
                     _as_truncated(name if name else self.name),
                     selectable=selectable,
                     type_=self.type,
-                    is_literal=is_literal,
-                    comparator_factory=self.comparator_factory
+                    is_literal=is_literal
                 )
         c.proxies = [self]
         if selectable._is_clone_of is not None:

test/lib/profiles.txt

-# /Users/classic/dev/sqlalchemy/./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 
 # environment is located within this file.  If it doesn't exist,
 
 # TEST: test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile
 
-test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 2.5_sqlite_pysqlite_nocextensions 9
-test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 2.6_sqlite_pysqlite_nocextensions 9
-test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 2.7_mysql_mysqldb_cextensions 9
-test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 2.7_mysql_mysqldb_nocextensions 9
-test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 2.7_postgresql_psycopg2_cextensions 9
-test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 2.7_postgresql_psycopg2_nocextensions 9
-test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 2.7_sqlite_pysqlite_cextensions 9
-test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 2.7_sqlite_pysqlite_nocextensions 9
-test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 3.2_postgresql_psycopg2_nocextensions 10
-test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 3.2_sqlite_pysqlite_nocextensions 10
+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
 

test/orm/test_mapper.py

             def __getitem__(self, key):
                 return 'value'
 
-        class UCComparator(sa.orm.PropComparator):
+        from sqlalchemy.orm.properties import ColumnProperty
+        class UCComparator(ColumnProperty.Comparator):
             __hash__ = None
 
             def method1(self):
 
             assert_raises_message(
                 AttributeError,
-                "Neither 'extendedproperty' object nor 'UCComparator' object has an attribute 'nonexistent'",
+                "Neither 'extendedproperty' object nor 'UCComparator' "
+                "object has an attribute 'nonexistent'",
                 getattr, User.uc_name, 'nonexistent')
 
             # test compile

test/sql/test_compiler.py

                             table1.c.myid.like('hoho')
         eq_(str(clause), str(util.pickle.loads(util.pickle.dumps(clause))))
 
+        clause = tuple_(1, 2, 3)
+        eq_(str(clause), str(util.pickle.loads(util.pickle.dumps(clause))))
 
     def test_like(self):
         for expr, check, dialect in [

test/sql/test_query.py

         r = testing.db.execute('select user_name from query_users').first()
         eq_(len(r), 1)
 
-    @testing.uses_deprecated(r'.*which subclass Executable')
-    def test_cant_execute_join(self):
-        try:
-            users.join(addresses).execute()
-        except exc.StatementError, e:
-            assert str(e).startswith('Not an executable clause ')
-
-
 
     def test_column_order_with_simple_query(self):
         # should return values in column definition order