"self.impl". This to support compilation correctly.
Behavior can be user-overridden in exactly the same way
as before to the same effect.
+
+ - Added type_coerce(expr, type_) expression element.
+ Treats the given expression as the given type when evaluating
+ expressions and processing result rows, but does not
+ affect the generation of SQL, other than an anonymous
+ label.
- Table.tometadata() now copies Index objects associated
with the Table as well.
.. autofunction:: tuple_
+.. autofunction:: type_coerce
+
.. autofunction:: union
.. autofunction:: union_all
subquery,
text,
tuple_,
+ type_coerce,
union,
union_all,
update,
table,
text,
tuple_,
+ type_coerce,
union,
union_all,
update,
def __init__(self, col, name):
self.element = col
self.name = name
+
+ @property
+ def type(self):
+ return self.element.type
@property
def quote(self):
if result_map is not None:
result_map[labelname.lower()] = \
- (label.name, (label, label.element, labelname), label.element.type)
+ (label.name, (label, label.element, labelname), label.type)
return self.process(label.element,
within_columns_clause=True,
return self.process(label.element,
within_columns_clause=False,
**kw)
-
+
def visit_column(self, column, result_map=None, **kwargs):
name = column.name
if name is None:
'except_', 'except_all', 'exists', 'extract', 'func', 'modifier',
'collate', 'insert', 'intersect', 'intersect_all', 'join', 'label',
'literal', 'literal_column', 'not_', 'null', 'or_', 'outparam',
- 'outerjoin', 'select', 'subquery', 'table', 'text', 'tuple_', 'union',
- 'union_all', 'update', ]
+ 'outerjoin', 'select', 'subquery', 'table', 'text', 'tuple_', 'type_coerce',
+ 'union', 'union_all', 'update', ]
PARSE_AUTOCOMMIT = util._symbol('PARSE_AUTOCOMMIT')
"""
return _Tuple(*expr)
+
+def type_coerce(expr, type_):
+ """Coerce the given expression into the given type, on the Python side only.
+
+ :func:`.type_coerce` is roughly similar to :func:.`cast`, except no
+ "CAST" expression is rendered - the given type is only applied towards
+ expression typing and against received result values.
+
+ e.g.::
+
+ from sqlalchemy.types import TypeDecorator
+ import uuid
+
+ class AsGuid(TypeDecorator):
+ impl = String
+
+ def process_bind_param(self, value, dialect):
+ if value is not None:
+ return str(value)
+ else:
+ return None
+
+ def process_result_value(self, value, dialect):
+ if value is not None:
+ return uuid.UUID(value)
+ else:
+ return None
+
+ conn.execute(
+ select([type_coerce(mytable.c.ident, AsGuid)]).\\
+ where(
+ type_coerce(mytable.c.ident, AsGuid) ==
+ uuid.uuid3(uuid.NAMESPACE_URL, 'bar')
+ )
+ )
+
+ """
+ if hasattr(expr, '__clause_expr__'):
+ return type_coerce(expr.__clause_expr__())
+
+ elif not isinstance(expr, Visitable):
+ if expr is None:
+ return null()
+ else:
+ return literal(expr, type_=type_)
+ else:
+ return _Label(None, expr, type_=type_)
+
def label(name, obj):
"""Return a :class:`_Label` object for the
t.dialect_impl(dialect=pg).impl.__class__,
Float().dialect_impl(pg).__class__
)
-
+
+ @testing.provide_metadata
+ def test_type_coerce(self):
+ """test ad-hoc usage of custom types with type_coerce()."""
+
+ class MyType(types.TypeDecorator):
+ impl = String
+
+ def process_bind_param(self, value, dialect):
+ return value[0:-8]
+
+ def process_result_value(self, value, dialect):
+ return value + "BIND_OUT"
+
+ t = Table('t', metadata, Column('data', String(50)))
+ metadata.create_all()
+
+ t.insert().values(data=type_coerce('d1BIND_OUT',MyType)).execute()
+
+ eq_(
+ select([type_coerce(t.c.data, MyType)]).execute().fetchall(),
+ [('d1BIND_OUT', )]
+ )
+
+ eq_(
+ select([t.c.data, type_coerce(t.c.data, MyType)]).execute().fetchall(),
+ [('d1', 'd1BIND_OUT')]
+ )
+
+ eq_(
+ select([t.c.data, type_coerce(t.c.data, MyType)]).\
+ where(type_coerce(t.c.data, MyType) == 'd1BIND_OUT').\
+ execute().fetchall(),
+ [('d1', 'd1BIND_OUT')]
+ )
+
+ eq_(
+ select([t.c.data, type_coerce(t.c.data, MyType)]).\
+ where(t.c.data == type_coerce('d1BIND_OUT', MyType)).\
+ execute().fetchall(),
+ [('d1', 'd1BIND_OUT')]
+ )
+
+ eq_(
+ select([t.c.data, type_coerce(t.c.data, MyType)]).\
+ where(t.c.data == type_coerce(None, MyType)).\
+ execute().fetchall(),
+ []
+ )
+
+ eq_(
+ select([t.c.data, type_coerce(t.c.data, MyType)]).\
+ where(type_coerce(t.c.data, MyType) == None).\
+ execute().fetchall(),
+ []
+ )
+
@classmethod
def setup_class(cls):
global users, metadata