Skip to content

document this workaround for custom SchemaType + per-type CheckConstraint #268

@sqlalchemy-bot

Description

@sqlalchemy-bot

Migrated issue, originally created by Adrian (@thiefmaster)

I'm using this custom type in SQLAlchemy:

class PyIntEnum(TypeDecorator, SchemaType):
    """Custom type which handles values from a PEP-435 Enum.

    In addition to the Python-side validation this also creates a
    CHECK constraint to ensure only valid enum members are stored.

    :param enum: the Enum repesented by this type's values
    :raise ValueError: when using/loading a value not in the Enum.
    """

    impl = SmallInteger

    def __init__(self, enum=None):
        self.enum = enum
        TypeDecorator.__init__(self)
        SchemaType.__init__(self)

    def process_bind_param(self, value, dialect):
        if value is None:
            return None
        if not isinstance(value, self.enum):
            # Convert plain (int) value to enum member
            value = self.enum(value)
        return _EnumIntWrapper(value)

    def process_result_value(self, value, dialect):
        if value is None:
            return None
        # Note: This raises a ValueError if `value` is not in the Enum.
        return self.enum(value)

    def _set_table(self, column, table):
        e = CheckConstraint(type_coerce(column, self).in_(x.value for x in self.enum))
        assert e.table is table

    def alembic_render_type(self, autogen_context):
        imports = autogen_context['imports']
        imports.add('from indico.core.db.sqlalchemy import PyIntEnum')
        imports.add('from {} import {}'.format(self.enum.__module__, self.enum.__name__))
        return '{}({})'.format(type(self).__name__, self.enum.__name__)

The alembic_render_type is called from a render_item function.
Everything works fine, but when autogenerating a revision I end up with this in the op.create_table call (unrelated columns etc. omitted when pasting it here):

    op.create_table('foobar',
                    sa.Column('state', PyIntEnum(RequestState), nullable=False),
                    sa.CheckConstraint('foobar.state IN (%(param_1)s, %(param_2)s, %(param_3)s)'))

There are no check constraints defined manually, only the one added by the custom type.

I believe Alembic shouldn't add a CheckConstraint for this. Is there any way to indicate that the constraint is handled by the type and thus doesn't belong into the table definition?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Tier 1High priority issues / Desired features that should be prioritised in release planningautogenerate - renderingbugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions