.. changelog::
:version: 1.1.0b1
+ .. change::
+ :tags: bug, sql
+ :tickets: 2919
+
+ The :class:`.TypeDecorator` type extender will now work in conjunction
+ with a :class:`.SchemaType` implementation, typically :class:`.Enum`
+ or :class:`.Boolean` with regards to ensuring that the per-table
+ events are propagated from the implementation type to the outer type.
+ These events are used
+ to ensure that the constraints or Postgresql types (e.g. ENUM)
+ are correctly created (and possibly dropped) along with the parent
+ table.
+
+ .. seealso::
+
+ :ref:`change_2919`
+
.. change::
:tags: feature, sql
:tickets: 1370
:ticket:`3132` :ticket:`1370`
+.. _change_2919:
+
+TypeDecorator now works with Enum, Boolean, "schema" types automatically
+------------------------------------------------------------------------
+
+The :class:`.SchemaType` types include types such as :class:`.Enum`
+and :class:`.Boolean` which, in addition to corresponding to a database
+type, also generate either a CHECK constraint or in the case of Postgresql
+ENUM a new CREATE TYPE statement, will now work automatically with
+:class:`.TypeDecorator` recipes. Previously, a :class:`.TypeDecorator` for
+an :class:`.postgresql.ENUM` had to look like this::
+
+ # old way
+ class MyEnum(TypeDecorator, SchemaType):
+ impl = postgresql.ENUM('one', 'two', 'three', name='myenum')
+
+ def _set_table(self, table):
+ self.impl._set_table(table)
+
+The :class:`.TypeDecorator` now propagates those additional events so it
+can be done like any other type::
+
+ # new way
+ class MyEnum(TypeDecorator):
+ impl = postgresql.ENUM('one', 'two', 'three', name='myenum')
+
+
+:ticket:`2919`
+
Key Behavioral Changes - ORM
============================
from .. import exc, util
from . import operators
from .visitors import Visitable, VisitableType
+from .base import SchemaEventTarget
# these are back-assigned by sqltypes.
BOOLEANTYPE = None
return self
-class TypeDecorator(TypeEngine):
+class TypeDecorator(SchemaEventTarget, TypeEngine):
"""Allows the creation of types which add additional functionality
to an existing type.
"""
return self.impl._type_affinity
+ def _set_parent(self, column):
+ """Support SchemaEentTarget"""
+
+ if isinstance(self.impl, SchemaEventTarget):
+ self.impl._set_parent(column)
+
+ def _set_parent_with_dispatch(self, parent):
+ """Support SchemaEentTarget"""
+
+ if isinstance(self.impl, SchemaEventTarget):
+ self.impl._set_parent_with_dispatch(parent)
+
def type_engine(self, dialect):
"""Return a dialect-specific :class:`.TypeEngine` instance
for this :class:`.TypeDecorator`.
finally:
metadata.drop_all()
+ @testing.provide_metadata
+ def test_custom_subclass(self):
+ class MyEnum(TypeDecorator):
+ impl = Enum('oneHI', 'twoHI', 'threeHI', name='myenum')
+
+ def process_bind_param(self, value, dialect):
+ if value is not None:
+ value += "HI"
+ return value
+
+ def process_result_value(self, value, dialect):
+ if value is not None:
+ value += "THERE"
+ return value
+
+ t1 = Table(
+ 'table1', self.metadata,
+ Column('data', MyEnum())
+ )
+ self.metadata.create_all(testing.db)
+
+ with testing.db.connect() as conn:
+ conn.execute(t1.insert(), {"data": "two"})
+ eq_(
+ conn.scalar(select([t1.c.data])),
+ "twoHITHERE"
+ )
+
class OIDTest(fixtures.TestBase):
__only_on__ = 'postgresql'
def __init__(self, name):
self.name = name
- class MyEnum(types.SchemaType, TypeDecorator):
+ class MyEnum(TypeDecorator):
def __init__(self, values):
self.impl = Enum(
*[v.name for v in values], name="myenum",
native_enum=False)
- def _set_table(self, table, column):
- self.impl._set_table(table, column)
-
# future method
def process_literal_param(self, value, dialect):
return value.name
def __init__(self, value):
self.value = value
- class MyBool(types.SchemaType, TypeDecorator):
+ class MyBool(TypeDecorator):
impl = Boolean()
- def _set_table(self, table, column):
- self.impl._set_table(table, column)
-
# future method
def process_literal_param(self, value, dialect):
return value.value