-
-
Notifications
You must be signed in to change notification settings - Fork 301
Fix MySQL native ENUM autogenerate detection #1746
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -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 | ||||||||
|
||||||||
| # Compare the actual enum values | |
| # Compare the actual enum values; order matters for MySQL ENUMs. | |
| # Changing the order of ENUM values is a schema change in MySQL. |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -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 | ||||||
|
|
@@ -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 | ||||||
|
|
@@ -23,10 +25,12 @@ | |||||
| from alembic.autogenerate import compare | ||||||
| from alembic.migration import MigrationContext | ||||||
| from alembic.operations import ops | ||||||
| from alembic import testing | ||||||
| from alembic.testing import assert_raises_message | ||||||
| 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 | ||||||
|
|
@@ -771,3 +775,57 @@ 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 | ||||||
|
|
||||||
| @testing.fixture() | ||||||
| def connection(self): | ||||||
| with config.db.begin() as conn: | ||||||
| yield conn | ||||||
|
|
||||||
| @testing.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", | ||||||
| ) | ||||||
|
Comment on lines
+791
to
+816
|
||||||
| 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 | ||||||
|
||||||
| "mysql", connection, (), {}, None, None, None, lambda: None | |
| connection.dialect, connection, False, None, None, {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The docstring should document the return value and parameters for clarity. Consider expanding it: