:paramref:`.EnvironmentContext.configure.include_object` hook.
Indexes are sent with type ``"index"`` and unique constraints with
type ``"unique_constraint"``.
fixes #203
def obj_added(obj):
if obj.is_index:
- diffs.append(("add_index", obj.const))
- log.info("Detected added index '%s' on %s",
- obj.name, ', '.join([
- "'%s'" % obj.column_names
- ])
- )
+ if _run_filters(
+ obj.const, obj.name, "index", False, None, object_filters):
+ diffs.append(("add_index", obj.const))
+ log.info("Detected added index '%s' on %s",
+ obj.name, ', '.join([
+ "'%s'" % obj.column_names
+ ]))
else:
if not supports_unique_constraints:
# can't report unique indexes as added if we don't
if is_create_table:
# unique constraints are created inline with table defs
return
- diffs.append(("add_constraint", obj.const))
- log.info("Detected added unique constraint '%s' on %s",
- obj.name, ', '.join([
- "'%s'" % obj.column_names
- ])
- )
+ if _run_filters(
+ obj.const, obj.name,
+ "unique_constraint", False, None, object_filters):
+ diffs.append(("add_constraint", obj.const))
+ log.info("Detected added unique constraint '%s' on %s",
+ obj.name, ', '.join([
+ "'%s'" % obj.column_names
+ ]))
def obj_removed(obj):
if obj.is_index:
# be sure what we're doing here
return
- diffs.append(("remove_index", obj.const))
- log.info("Detected removed index '%s' on '%s'", obj.name, tname)
+ if _run_filters(
+ obj.const, obj.name, "index", True, None, object_filters):
+ diffs.append(("remove_index", obj.const))
+ log.info(
+ "Detected removed index '%s' on '%s'", obj.name, tname)
else:
- diffs.append(("remove_constraint", obj.const))
- log.info("Detected removed unique constraint '%s' on '%s'",
- obj.name, tname
- )
+ if _run_filters(
+ obj.const, obj.name,
+ "unique_constraint", True, None, object_filters):
+ diffs.append(("remove_constraint", obj.const))
+ log.info("Detected removed unique constraint '%s' on '%s'",
+ obj.name, tname
+ )
def obj_changed(old, new, msg):
if old.is_index:
- log.info("Detected changed index '%s' on '%s':%s",
- old.name, tname, ', '.join(msg)
- )
- diffs.append(("remove_index", old.const))
- diffs.append(("add_index", new.const))
+ if _run_filters(
+ new.const, new.name, "index",
+ False, old.const, object_filters):
+ log.info("Detected changed index '%s' on '%s':%s",
+ old.name, tname, ', '.join(msg)
+ )
+ diffs.append(("remove_index", old.const))
+ diffs.append(("add_index", new.const))
else:
- log.info("Detected changed unique constraint '%s' on '%s':%s",
- old.name, tname, ', '.join(msg)
- )
- diffs.append(("remove_constraint", old.const))
- diffs.append(("add_constraint", new.const))
+ if _run_filters(
+ new.const, new.name,
+ "unique_constraint", False, old.const, object_filters):
+ log.info("Detected changed unique constraint '%s' on '%s':%s",
+ old.name, tname, ', '.join(msg)
+ )
+ diffs.append(("remove_constraint", old.const))
+ diffs.append(("add_constraint", new.const))
for added_name in sorted(set(metadata_names).difference(conn_names)):
obj = metadata_names[added_name]
The function accepts the following positional arguments:
* ``object``: a :class:`~sqlalchemy.schema.SchemaItem` object such
- as a :class:`~sqlalchemy.schema.Table` or
- :class:`~sqlalchemy.schema.Column` object
+ as a :class:`~sqlalchemy.schema.Table`,
+ :class:`~sqlalchemy.schema.Column`,
+ :class:`~sqlalchemy.schema.Index`
+ or :class:`~sqlalchemy.schema.UniqueConstraint` object
* ``name``: the name of the object. This is typically available
via ``object.name``.
* ``type``: a string describing the type of object; currently
- ``"table"`` or ``"column"``
+ ``"table"``, ``"column"``, ``"index"`` or ``"unique_constraint"``.
+
+ .. versionadded:: 0.7.0 Support for indexes and unique constraints
+ within the
+ :paramref:`~.EnvironmentContext.configure.include_object` hook.
+
* ``reflected``: ``True`` if the given object was produced based on
table reflection, ``False`` if it's from a local :class:`.MetaData`
object.
.. changelog::
:version: 0.7.0
+ .. change::
+ :tags: feature, autogenerate
+ :tickets: 203
+
+ Indexes and unique constraints are now included in the
+ :paramref:`.EnvironmentContext.configure.include_object` hook.
+ Indexes are sent with type ``"index"`` and unique constraints with
+ type ``"unique_constraint"``.
+
.. change::
:tags: bug, autogenerate
:tickets: 219
eng.dialect.get_unique_constraints = unimpl
eng.dialect.get_indexes = get_indexes
return eng
+
+
+class IncludeHooksTest(AutogenFixtureTest, TestBase):
+ __backend__ = True
+
+ def test_remove_connection_index(self):
+ m1 = MetaData()
+ m2 = MetaData()
+
+ t1 = Table('t', m1, Column('x', Integer))
+ Index('ix1', t1.c.x)
+ Index('ix2', t1.c.x)
+
+ Table('t', m2, Column('x', Integer))
+
+ def include_object(object_, name, type_, reflected, compare_to):
+ if type_ == 'unique_constraint':
+ return False
+ return not (
+ isinstance(object_, Index) and
+ type_ == 'index' and reflected and name == 'ix1')
+
+ diffs = self._fixture(m1, m2, object_filters=[include_object])
+
+ eq_(diffs[0][0], 'remove_index')
+ eq_(diffs[0][1].name, 'ix2')
+ eq_(len(diffs), 1)
+
+ def test_remove_connection_uq(self):
+ m1 = MetaData()
+ m2 = MetaData()
+
+ Table(
+ 't', m1, Column('x', Integer), Column('y', Integer),
+ UniqueConstraint('x', name='uq1'),
+ UniqueConstraint('y', name='uq2'),
+ )
+
+ Table('t', m2, Column('x', Integer), Column('y', Integer))
+
+ def include_object(object_, name, type_, reflected, compare_to):
+ if type_ == 'index':
+ return False
+ return not (
+ isinstance(object_, UniqueConstraint) and
+ type_ == 'unique_constraint' and reflected and name == 'uq1')
+
+ diffs = self._fixture(m1, m2, object_filters=[include_object])
+
+ eq_(diffs[0][0], 'remove_constraint')
+ eq_(diffs[0][1].name, 'uq2')
+ eq_(len(diffs), 1)
+
+ def test_add_metadata_index(self):
+ m1 = MetaData()
+ m2 = MetaData()
+
+ Table('t', m1, Column('x', Integer))
+
+ t2 = Table('t', m2, Column('x', Integer))
+ Index('ix1', t2.c.x)
+ Index('ix2', t2.c.x)
+
+ def include_object(object_, name, type_, reflected, compare_to):
+ return not (
+ isinstance(object_, Index) and
+ type_ == 'index' and not reflected and name == 'ix1')
+
+ diffs = self._fixture(m1, m2, object_filters=[include_object])
+
+ eq_(diffs[0][0], 'add_index')
+ eq_(diffs[0][1].name, 'ix2')
+ eq_(len(diffs), 1)
+
+ def test_add_metadata_unique(self):
+ m1 = MetaData()
+ m2 = MetaData()
+
+ Table('t', m1, Column('x', Integer))
+
+ Table(
+ 't', m2, Column('x', Integer),
+ UniqueConstraint('x', name='uq1'),
+ UniqueConstraint('x', name='uq2')
+ )
+
+ def include_object(object_, name, type_, reflected, compare_to):
+ return not (
+ isinstance(object_, UniqueConstraint) and
+ type_ == 'unique_constraint' and
+ not reflected and name == 'uq1')
+
+ diffs = self._fixture(m1, m2, object_filters=[include_object])
+
+ eq_(diffs[0][0], 'add_constraint')
+ eq_(diffs[0][1].name, 'uq2')
+ eq_(len(diffs), 1)
+
+ def test_change_index(self):
+ m1 = MetaData()
+ m2 = MetaData()
+
+ t1 = Table('t', m1, Column('x', Integer), Column('y', Integer))
+ Index('ix1', t1.c.x)
+ Index('ix2', t1.c.x)
+
+ t2 = Table('t', m2, Column('x', Integer), Column('y', Integer))
+ Index('ix1', t2.c.x, t2.c.y)
+ Index('ix2', t2.c.x, t2.c.y)
+
+ def include_object(object_, name, type_, reflected, compare_to):
+ return not (
+ isinstance(object_, Index) and
+ type_ == 'index' and not reflected and name == 'ix1'
+ and isinstance(compare_to, Index))
+
+ diffs = self._fixture(m1, m2, object_filters=[include_object])
+
+ eq_(diffs[0][0], 'remove_index')
+ eq_(diffs[0][1].name, 'ix2')
+ eq_(diffs[1][0], 'add_index')
+ eq_(diffs[1][1].name, 'ix2')
+ eq_(len(diffs), 2)
+
+ def test_change_unique(self):
+ m1 = MetaData()
+ m2 = MetaData()
+
+ Table(
+ 't', m1, Column('x', Integer),
+ Column('y', Integer), Column('z', Integer),
+ UniqueConstraint('x', name='uq1'),
+ UniqueConstraint('y', name='uq2')
+ )
+
+ Table(
+ 't', m2, Column('x', Integer), Column('y', Integer),
+ Column('z', Integer),
+ UniqueConstraint('x', 'z', name='uq1'),
+ UniqueConstraint('y', 'z', name='uq2')
+ )
+
+ def include_object(object_, name, type_, reflected, compare_to):
+ if type_ == 'index':
+ return False
+ return not (
+ isinstance(object_, UniqueConstraint) and
+ type_ == 'unique_constraint' and
+ not reflected and name == 'uq1'
+ and isinstance(compare_to, UniqueConstraint))
+
+ diffs = self._fixture(m1, m2, object_filters=[include_object])
+
+ eq_(diffs[0][0], 'remove_constraint')
+ eq_(diffs[0][1].name, 'uq2')
+ eq_(diffs[1][0], 'add_constraint')
+ eq_(diffs[1][1].name, 'uq2')
+ eq_(len(diffs), 2)
cls.m2 = cls._get_model_schema()
conn = cls.bind.connect()
- opts = cls.configure_opts.copy()
- opts.update({
+ ctx_opts = {
'compare_type': True,
'compare_server_default': True,
'target_metadata': cls.m2,
'downgrade_token': "downgrades",
'alembic_module_prefix': 'op.',
'sqlalchemy_module_prefix': 'sa.',
- })
+ }
+ if cls.configure_opts:
+ ctx_opts.update(cls.configure_opts)
cls.context = context = MigrationContext.configure(
connection=conn,
- opts=opts
+ opts=ctx_opts
)
connection = context.bind
class AutogenFixtureTest(object):
- def _fixture(self, m1, m2, include_schemas=False):
+ def _fixture(
+ self, m1, m2, include_schemas=False,
+ opts=None, object_filters=_default_object_filters):
self.metadata, model_metadata = m1, m2
self.metadata.create_all(self.bind)
with self.bind.connect() as conn:
+ ctx_opts = {
+ 'compare_type': True,
+ 'compare_server_default': True,
+ 'target_metadata': model_metadata,
+ 'upgrade_token': "upgrades",
+ 'downgrade_token': "downgrades",
+ 'alembic_module_prefix': 'op.',
+ 'sqlalchemy_module_prefix': 'sa.',
+ }
+ if opts:
+ ctx_opts.update(opts)
self.context = context = MigrationContext.configure(
connection=conn,
- opts={
- 'compare_type': True,
- 'compare_server_default': True,
- 'target_metadata': model_metadata,
- 'upgrade_token': "upgrades",
- 'downgrade_token': "downgrades",
- 'alembic_module_prefix': 'op.',
- 'sqlalchemy_module_prefix': 'sa.',
- }
+ opts=ctx_opts
)
connection = context.bind
autogenerate._produce_net_changes(
connection, model_metadata, diffs,
autogen_context,
- object_filters=_default_object_filters,
+ object_filters=object_filters,
include_schemas=include_schemas
)
return diffs