diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2018-08-07 18:59:05 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2018-08-08 17:29:32 -0400 |
| commit | f03c7918796e1080d971a9c03943962478be4caf (patch) | |
| tree | 1fc625022979151be27a9a3403726a4d2179f44d /lib/sqlalchemy/sql | |
| parent | b17fa2513e412b8f9aa1f62c0acc7fa3805e632b (diff) | |
| download | sqlalchemy-f03c7918796e1080d971a9c03943962478be4caf.tar.gz | |
Fixed issue with :meth:`.TypeEngine.bind_expression` and
:meth:`.TypeEngine.column_expression` methods where these methods would not
work if the target type were part of a :class:`.Variant`, or other target
type of a :class:`.TypeDecorator`. Additionally, the SQL compiler now
calls upon the dialect-level implementation when it renders these methods
so that dialects can now provide for SQL-level processing for built-in
types.
Change-Id: Ic7b39575184db582e628e6ecee48dcda7d03a817
Fixes: #3981
Diffstat (limited to 'lib/sqlalchemy/sql')
| -rw-r--r-- | lib/sqlalchemy/sql/compiler.py | 23 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/type_api.py | 29 |
2 files changed, 43 insertions, 9 deletions
diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index 57da43217..5fbc7d87f 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -1237,10 +1237,17 @@ class SQLCompiler(Compiled): literal_binds=False, skip_bind_expression=False, **kwargs): - if not skip_bind_expression and bindparam.type._has_bind_expression: - bind_expression = bindparam.type.bind_expression(bindparam) - return self.process(bind_expression, - skip_bind_expression=True) + + if not skip_bind_expression: + impl = bindparam.type.dialect_impl(self.dialect) + if impl._has_bind_expression: + bind_expression = impl.bind_expression(bindparam) + return self.process( + bind_expression, skip_bind_expression=True, + within_columns_clause=within_columns_clause, + literal_binds=literal_binds, + **kwargs + ) if literal_binds or \ (within_columns_clause and @@ -1510,10 +1517,12 @@ class SQLCompiler(Compiled): within_columns_clause=True): """produce labeled columns present in a select().""" - if column.type._has_column_expression and \ + impl = column.type.dialect_impl(self.dialect) + if impl._has_column_expression and \ populate_result_map: - col_expr = column.type.column_expression(column) - add_to_result_map = lambda keyname, name, objects, type_: \ + col_expr = impl.column_expression(column) + + def add_to_result_map(keyname, name, objects, type_): self._add_to_result_map( keyname, name, (column,) + objects, type_) diff --git a/lib/sqlalchemy/sql/type_api.py b/lib/sqlalchemy/sql/type_api.py index 6a323683b..a8dfa19be 100644 --- a/lib/sqlalchemy/sql/type_api.py +++ b/lib/sqlalchemy/sql/type_api.py @@ -1239,6 +1239,33 @@ class TypeDecorator(SchemaEventTarget, TypeEngine): else: return self.impl.result_processor(dialect, coltype) + @util.memoized_property + def _has_bind_expression(self): + return ( + self.__class__.bind_expression.__code__ + is not TypeDecorator.bind_expression.__code__ + ) or self.impl._has_bind_expression + + def bind_expression(self, bindparam): + return self.impl.bind_expression(bindparam) + + @util.memoized_property + def _has_column_expression(self): + """memoized boolean, check if column_expression is implemented. + + Allows the method to be skipped for the vast majority of expression + types that don't use this feature. + + """ + + return ( + self.__class__.column_expression.__code__ + is not TypeDecorator.column_expression.__code__ + ) or self.impl._has_column_expression + + def column_expression(self, column): + return self.impl.column_expression(column) + def coerce_compared_value(self, op, value): """Suggest a type for a 'coerced' Python value in an expression. @@ -1299,8 +1326,6 @@ class TypeDecorator(SchemaEventTarget, TypeEngine): return util.generic_repr(self, to_inspect=self.impl) - - class Variant(TypeDecorator): """A wrapping type that selects among a variety of implementations based on dialect in use. |
