Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions alembic/ddl/mysql.py
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,30 @@ def correct_for_autogen_foreignkeys(self, conn_fks, metadata_fks):
):
cnfk.onupdate = "RESTRICT"

def compare_type(
self,
inspector_column: schema.Column[Any],
metadata_column: schema.Column,
) -> bool:
"""Override compare_type to properly detect MySQL native ENUM changes.

This addresses the issue where autogenerate fails to detect when new
values are added to or removed from MySQL native ENUM columns.
"""
metadata_type = metadata_column.type
inspector_type = inspector_column.type

# Check if both columns are MySQL native ENUMs
if isinstance(metadata_type, sqltypes.Enum) and isinstance(
inspector_type, sqltypes.Enum
):
# Compare the actual enum values
if metadata_type.enums != inspector_type.enums:
return True

# Fall back to default comparison for non-ENUM types
return super().compare_type(inspector_column, metadata_column)


class MariaDBImpl(MySQLImpl):
__dialect__ = "mariadb"
Expand Down
41 changes: 41 additions & 0 deletions tests/test_mysql.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from sqlalchemy import Column
from sqlalchemy import Computed
from sqlalchemy import DATETIME
from sqlalchemy import Enum
from sqlalchemy import exc
from sqlalchemy import Float
from sqlalchemy import func
Expand All @@ -14,6 +15,7 @@
from sqlalchemy import Table
from sqlalchemy import text
from sqlalchemy import TIMESTAMP
from sqlalchemy.dialects.mysql import ENUM as MySQL_ENUM
from sqlalchemy.dialects.mysql import VARCHAR

from alembic import autogenerate
Expand All @@ -27,6 +29,7 @@
from alembic.testing import combinations
from alembic.testing import config
from alembic.testing import eq_ignore_whitespace
from alembic.testing import is_
from alembic.testing.env import clear_staging_env
from alembic.testing.env import staging_env
from alembic.testing.fixtures import AlterColRoundTripFixture
Expand Down Expand Up @@ -771,3 +774,41 @@ def test_render_add_index_expr_func(self):
"op.create_index('foo_idx', 't', "
"['x', sa.literal_column('(coalesce(y, 0))')], unique=False)",
)


class MySQLEnumCompareTest(TestBase):
"""Test MySQL native ENUM comparison in autogenerate."""

__only_on__ = "mysql", "mariadb"
__backend__ = True

@combinations.fixture()
def connection(self):
with config.db.begin() as conn:
yield conn

@combinations(
(Enum("A", "B", "C", native_enum=True), Enum("A", "B", "C", native_enum=True), False),
(Enum("A", "B", "C", native_enum=True), Enum("A", "B", "C", "D", native_enum=True), True),
(Enum("A", "B", "C", "D", native_enum=True), Enum("A", "B", "C", native_enum=True), True),
(Enum("A", "B", "C", native_enum=True), Enum("C", "B", "A", native_enum=True), True),
(MySQL_ENUM("A", "B", "C"), MySQL_ENUM("A", "B", "C"), False),
(MySQL_ENUM("A", "B", "C"), MySQL_ENUM("A", "B", "C", "D"), True),
id_="ssa",
argnames="inspected_type,metadata_type,expected",
)
def test_compare_enum_types(
self, inspected_type, metadata_type, expected, connection
):
from alembic.ddl.mysql import MySQLImpl

impl = MySQLImpl(
"mysql", connection, (), {}, None, None, None, lambda: None
)

is_(
impl.compare_type(
Column("x", inspected_type), Column("x", metadata_type)
),
expected,
)
Loading