Apply DDLCompiler name rules to Index for autogenerate

The autogenerate compare scheme now takes into account the name truncation
rules applied by SQLAlchemy's DDL compiler to the names of the
:class:`.Index` object, when these names are dynamically truncated
due to a too-long identifier name.   As the identifier truncation is
deterministic, applying the same rule to the metadata name allows
correct comparison to the database-derived name.

Change-Id: I270fbde4430a41f4bcc7857f1932347d86f07675
Fixes: #421
This commit is contained in:
Mike Bayer 2017-03-15 17:10:28 -04:00
parent 50469dc261
commit 4cdb25bf5d
4 changed files with 49 additions and 1 deletions

View File

@ -277,6 +277,9 @@ def _compare_columns(schema, tname, conn_table, metadata_table,
class _constraint_sig(object):
def md_name_to_sql_name(self, context):
return self.name
def __eq__(self, other):
return self.const == other.const
@ -310,6 +313,9 @@ class _ix_constraint_sig(_constraint_sig):
self.sig = tuple(sorted([col.name for col in const.columns]))
self.is_unique = bool(const.unique)
def md_name_to_sql_name(self, context):
return sqla_compat._get_index_final_name(context.dialect, self.const)
@property
def column_names(self):
return sqla_compat._get_index_column_names(self.const)
@ -433,7 +439,7 @@ def _compare_indexes_and_uniques(
# 5. index things by name, for those objects that have names
metadata_names = dict(
(c.name, c) for c in
(c.md_name_to_sql_name(autogen_context), c) for c in
metadata_unique_constraints.union(metadata_indexes)
if c.name is not None)

View File

@ -171,3 +171,10 @@ def _get_index_expressions(idx):
def _get_index_column_names(idx):
return [getattr(exp, "name", None) for exp in _get_index_expressions(idx)]
def _get_index_final_name(dialect, idx):
if sqla_08:
return dialect.ddl_compiler(dialect, None)._prepared_index_name(idx)
else:
return idx.name

View File

@ -7,6 +7,17 @@ Changelog
:version: 0.9.2
:released:
.. change:: 421
:tags: bug, autogenerate
:tickets: 421
The autogenerate compare scheme now takes into account the name truncation
rules applied by SQLAlchemy's DDL compiler to the names of the
:class:`.Index` object, when these names are dynamically truncated
due to a too-long identifier name. As the identifier truncation is
deterministic, applying the same rule to the metadata name allows
correct comparison to the database-derived name.
.. change:: 419
:tags: bug environment
:tickets: 419

View File

@ -979,3 +979,27 @@ class IncludeHooksTest(AutogenFixtureTest, TestBase):
eq_(diffs[1][0], 'add_constraint')
eq_(diffs[1][1].name, 'uq2')
eq_(len(diffs), 2)
class TruncatedIdxTest(AutogenFixtureTest, TestBase):
__requires__ = ('sqlalchemy_09', )
def setUp(self):
self.bind = engines.testing_engine()
self.bind.dialect.max_identifier_length = 30
def test_idx_matches_long(self):
from alembic.operations.base import conv
m1 = MetaData()
Table(
'q', m1,
Column('id', Integer, primary_key=True),
Column('data', Integer),
Index(
conv("idx_q_table_this_is_more_than_thirty_characters"),
"data")
)
diffs = self._fixture(m1, m1)
eq_(diffs, [])