From: Mike Bayer Date: Tue, 9 Mar 2010 02:15:16 +0000 (-0500) Subject: still thinking about stuff here X-Git-Tag: rel_0_6beta2~62^2~3^2~3 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=c3fd9a55367a5342d517d4b77ea653dfc7447da9;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git still thinking about stuff here --- diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py index 49ec34ab22..e4a610e5df 100644 --- a/lib/sqlalchemy/sql/expression.py +++ b/lib/sqlalchemy/sql/expression.py @@ -1558,7 +1558,9 @@ class _CompareMixin(ColumnOperators): # use __radd__ to force string concat behavior return self.__compare( operators.like_op, - literal_column("'%'", type_=sqltypes.String).__radd__(self._check_literal(operators.like_op, other)), + literal_column("'%'", type_=sqltypes.String).__radd__( + self._check_literal(operators.like_op, other) + ), escape=escape) def endswith(self, other, escape=None): @@ -1566,7 +1568,8 @@ class _CompareMixin(ColumnOperators): return self.__compare( operators.like_op, - literal_column("'%'", type_=sqltypes.String) + self._check_literal(operators.like_op, other), + literal_column("'%'", type_=sqltypes.String) + + self._check_literal(operators.like_op, other), escape=escape) def contains(self, other, escape=None): @@ -1652,11 +1655,16 @@ class _CompareMixin(ColumnOperators): return lambda other: self.__operate(operator, other) def _bind_param(self, operator, obj): - return _BindParamClause(None, obj, _compared_to_operator=operator, _compared_to_type=self.type, unique=True) + return _BindParamClause(None, obj, + _compared_to_operator=operator, + _compared_to_type=self.type, unique=True) def _check_literal(self, operator, other): if isinstance(other, _BindParamClause) and \ isinstance(other.type, sqltypes.NullType): + # TODO: perhaps we should not mutate the incoming bindparam() + # here and instead make a copy of it. this might + # be the only place that we're mutating an incoming construct. other.type = self.type return other elif hasattr(other, '__clause_element__'): diff --git a/lib/sqlalchemy/types.py b/lib/sqlalchemy/types.py index 4d6a28aadc..fc9ad2d531 100644 --- a/lib/sqlalchemy/types.py +++ b/lib/sqlalchemy/types.py @@ -236,14 +236,19 @@ class UserDefinedType(TypeEngine): class TypeDecorator(AbstractType): """Allows the creation of types which add additional functionality to an existing type. + + This method is preferred to direct subclassing of SQLAlchemy's + built-in types as it ensures that all required functionality of + the underlying type is kept in place. Typical usage:: import sqlalchemy.types as types class MyType(types.TypeDecorator): - # Prefixes Unicode values with "PREFIX:" on the way in and - # strips it off on the way out. + '''Prefixes Unicode values with "PREFIX:" on the way in and + strips it off on the way out. + ''' impl = types.Unicode @@ -264,14 +269,14 @@ class TypeDecorator(AbstractType): Types that receive a Python type that isn't similar to the ultimate type used may want to define the :meth:`TypeDecorator.coerce_compared_value` - method=. This is used to give the expression system a hint - when coercing Python objects - into bind parameters within expressions. Consider this expression:: + method. This is used to give the expression system a hint + when coercing Python objects into bind parameters within expressions. + Consider this expression:: mytable.c.somecol + datetime.date(2009, 5, 15) Above, if "somecol" is an ``Integer`` variant, it makes sense that - we doing date arithmetic, where above is usually interpreted + we're doing date arithmetic, where above is usually interpreted by databases as adding a number of days to the given date. The expression system does the right thing by not attempting to coerce the "date()" value into an integer-oriented bind parameter. @@ -296,19 +301,10 @@ class TypeDecorator(AbstractType): def coerce_compared_value(self, op, value): if isinstance(value, datetime.date): - return Date + return self else: raise ValueError("Python date expected.") - The reason that type behavior is modified using class decoration - instead of subclassing is due to the way dialect specific types - are used. Such as with the example above, when using the mysql - dialect, the actual type in use will be a - ``sqlalchemy.databases.mysql.MSString`` instance. - ``TypeDecorator`` handles the mechanics of passing the values - between user-defined ``process_`` methods and the current - dialect-specific type in use. - """ __visit_name__ = "type_decorator" @@ -1449,6 +1445,13 @@ class Interval(_DateAffinity, TypeDecorator): value is stored as a date which is relative to the "epoch" (Jan. 1, 1970). + Note that the ``Interval`` type does not currently provide + date arithmetic operations on platforms which do not support + interval types natively. Such operations usually require + transformation of both sides of the expression (such as, conversion + of both sides into integer epoch values first) which currently + is a manual procedure (such as via :attr:`~sqlalchemy.sql.expression.func`). + """ impl = DateTime @@ -1477,7 +1480,7 @@ class Interval(_DateAffinity, TypeDecorator): self.native = native self.second_precision = second_precision self.day_precision = day_precision - + def adapt(self, cls): if self.native: return cls._adapt_from_generic_interval(self) diff --git a/test/sql/test_types.py b/test/sql/test_types.py index ad58f1867e..d7f0d1ed75 100644 --- a/test/sql/test_types.py +++ b/test/sql/test_types.py @@ -1181,7 +1181,8 @@ class IntervalTest(TestBase, AssertsExecutionResults): eq_(row['native_interval'], None) eq_(row['native_interval_args'], None) eq_(row['non_native_interval'], None) - + + class BooleanTest(TestBase, AssertsExecutionResults): @classmethod def setup_class(cls):