1. Mike Bayer
  2. alembic

Issues

Issue #89 new

op.add_column() and op.drop_column() should check for SchemaType, run through the events for that type, or perhaps just create/drop

Wichert Akkerman
created an issue

I have a data model which has a simple enum column:

    size_type = schema.Column(
        types.Enum('normal', 'plus', name='size_type_type'),
        nullable=False, default='normal')

as part of an upgrade routine I need to add that column if it is missing:

    alembic.add_column('article_variant',
            ArticleVariant.__table__.c['size_type'].copy())

alembic is an operation instance here. This operation breaks due to a missing check if the enum type already exists. The resulting error is:

sqlalchemy.exc.ProgrammingError: (ProgrammingError) type "size_type_type" does not exist
LINE 1: ALTER TABLE article_variant ADD COLUMN size_type size_type_t...
                                                         ^
 'ALTER TABLE article_variant ADD COLUMN size_type size_type_type NOT NULL' {}

Comments (9)

  1. Wichert Akkerman reporter

    In case it is useful I added a local workaround which adds the type if it is missing:

    context = alembic.get_context()
    if context.bind.dialect.name == 'postgresql':
        has_size_type = context.bind.execute(
                "select exists (select 1 from pg_type "
                "where typname='size_type')").scalar()
        if not has_size_type:
            alembic.execute("CREATE TYPE size_type AS ENUM ('normal', 'plus')")
    
  2. Mike Bayer repo owner

    The creation/dropping of the associated type for ENUM and on some platforms boolean is a "schema event" which responds to metadata or Table oncreate/drop. There's currently not an event for "on column add/drop". So Alembic's add_column() and drop_column() should probably run through the "on table create/drop" events for the type.

    What you should do right now is use the create() method on the enumerated type:

    ArticleVariant.table.c.size_type.create(alembic.get_bind(), checkfirst=True)

  3. Mike Bayer repo owner

    correction:

    bind = alembic.get_bind()
    typ = ArticleVariant.__table__.c.size_type.type
    impl = typ.dialect_impl(bind.dialect)
    impl.create(bind, checkfirst=True)
    

    or this:

    bind = alembic.get_bind()
    typ = ArticleVariant.__table__.c.size_type.type
    typ._on_table_create(ArticleVariant.__table__, bind)
    
  4. Anonymous

    Slightly different for me I had to do

    bind = op.get_bind()
    typ = ArticleVariant.__table__.c.size_type.type
    typ._on_table_create(ArticleVariant.__table__, bind, checkfirst=True)
    
  5. Log in to comment