Use two models in generated migrations. Test column addition and removal.

This commit is contained in:
Gabriel 2011-07-07 19:12:18 +02:00
parent 15f571d296
commit a1968e7f7d
3 changed files with 93 additions and 49 deletions

View File

@ -42,14 +42,15 @@ class TestSchemaDiff(fixture.DB):
def assertDiff(isDiff, tablesMissingInDatabase, tablesMissingInModel, tablesWithDiff):
diff = schemadiff.getDiffOfModelAgainstDatabase(self.meta, self.engine, excludeTables=['migrate_version'])
eq_(bool(diff), isDiff)
eq_(
(diff.tables_missing_from_B,
diff.tables_missing_from_A,
diff.tables_different.keys()),
diff.tables_different.keys(),
bool(diff)),
(tablesMissingInDatabase,
tablesMissingInModel,
tablesWithDiff)
tablesWithDiff,
isDiff)
)
# Model is defined but database is empty.
@ -64,8 +65,9 @@ class TestSchemaDiff(fixture.DB):
if repr(String()) == 'String()':
self.assertEqualsIgnoreWhitespace(decls, '''
from migrate.changeset import schema
meta = MetaData()
tmp_schemadiff = Table('tmp_schemadiff', meta,
pre_meta = MetaData()
post_meta = MetaData()
tmp_schemadiff = Table('tmp_schemadiff', post_meta,
Column('id', Integer, primary_key=True, nullable=False),
Column('name', UnicodeText),
Column('data', UnicodeText),
@ -74,19 +76,14 @@ class TestSchemaDiff(fixture.DB):
else:
self.assertEqualsIgnoreWhitespace(decls, '''
from migrate.changeset import schema
meta = MetaData()
tmp_schemadiff = Table('tmp_schemadiff', meta,
pre_meta = MetaData()
post_meta = MetaData()
tmp_schemadiff = Table('tmp_schemadiff', post_meta,
Column('id', Integer, primary_key=True, nullable=False),
Column('name', UnicodeText(length=None)),
Column('data', UnicodeText(length=None)),
)
''')
self.assertEqualsIgnoreWhitespace(upgradeCommands,
'''meta.bind = migrate_engine
tmp_schemadiff.create()''')
self.assertEqualsIgnoreWhitespace(downgradeCommands,
'''meta.bind = migrate_engine
tmp_schemadiff.drop()''')
# Create table in database, now model should match database.
self._applyLatestModel()
@ -111,12 +108,14 @@ class TestSchemaDiff(fixture.DB):
else:
dataId = result.last_inserted_ids()[0]
# Modify table in model (by removing it and adding it back to model) -- drop column data and add column data2.
# Modify table in model (by removing it and adding it back to model)
# Drop column data, add columns data2 and data3.
self.meta.remove(self.table)
self.table = Table(self.table_name,self.meta,
Column('id',Integer(),primary_key=True),
Column('name',UnicodeText(length=None)),
Column('data2',Integer(),nullable=True),
Column('data3',Integer(),nullable=True),
)
assertDiff(True, [], [], [self.table_name])
@ -124,6 +123,36 @@ class TestSchemaDiff(fixture.DB):
self._applyLatestModel()
assertDiff(False, [], [], [])
# Drop column data3, add data4
self.meta.remove(self.table)
self.table = Table(self.table_name,self.meta,
Column('id',Integer(),primary_key=True),
Column('name',UnicodeText(length=None)),
Column('data2',Integer(),nullable=True),
Column('data4',Float(),nullable=True),
)
assertDiff(True, [], [], [self.table_name])
diff = schemadiff.getDiffOfModelAgainstDatabase(
self.meta, self.engine, excludeTables=['migrate_version'])
decls, upgradeCommands, downgradeCommands = genmodel.ModelGenerator(diff,self.engine).genB2AMigration(indent='')
# decls have changed since genBDefinition
exec decls in locals()
# migration commands expect a namespace containing migrate_engine
migrate_engine = self.engine
# run the migration up and down
exec upgradeCommands in locals()
assertDiff(False, [], [], [])
exec decls in locals()
exec downgradeCommands in locals()
assertDiff(True, [], [], [self.table_name])
exec decls in locals()
exec upgradeCommands in locals()
assertDiff(False, [], [], [])
if not self.engine.name == 'oracle':
# Make sure data is still present.
result = self.engine.execute(self.table.select(self.table.c.id==dataId))

View File

@ -158,8 +158,8 @@ def upgrade(migrate_engine):
repository=self.repo_path,
)
self.assertTrue('User.create()' in source_script)
self.assertTrue('User.drop()' in source_script)
self.assertTrue("['User'].create()" in source_script)
self.assertTrue("['User'].drop()" in source_script)
@fixture.usedb()
def test_make_update_script_for_equal_models(self):
@ -196,9 +196,9 @@ def upgrade(migrate_engine):
self.assertTrue(0
< source_script.find('upgrade')
< source_script.find('User.create()')
< source_script.find("['User'].create()")
< source_script.find('downgrade')
< source_script.find('User.drop()'))
< source_script.find("['User'].drop()"))
def setup_model_params(self):
self.script_path = self.tmp_py()

View File

@ -96,7 +96,7 @@ class ModelGenerator(object):
else:
return """Column(%(name)r, %(commonStuff)s)""" % data
def _getTableDefn(self, table):
def _getTableDefn(self, table, metaName='meta'):
out = []
tableName = table.name
if self.declarative:
@ -107,8 +107,8 @@ class ModelGenerator(object):
out.append(" %s" % self.column_repr(col))
out.append('\n')
else:
out.append("%(table)s = Table('%(table)s', meta," %
{'table': tableName})
out.append("%(table)s = Table('%(table)s', %(meta)s," %
{'table': tableName, 'meta': metaName})
for col in table.columns:
out.append(" %s," % self.column_repr(col))
out.append(")\n")
@ -151,46 +151,61 @@ class ModelGenerator(object):
'''
decls = ['from migrate.changeset import schema',
'meta = MetaData()']
for table in self._get_tables(
missingA=True,missingB=True,modified=True
):
decls.extend(self._getTableDefn(table))
'pre_meta = MetaData()',
'post_meta = MetaData()',
]
upgradeCommands = ['pre_meta.bind = migrate_engine',
'post_meta.bind = migrate_engine']
downgradeCommands = list(upgradeCommands)
upgradeCommands, downgradeCommands = [], []
for tableName in self.diff.tables_missing_from_A:
upgradeCommands.append("%(table)s.drop()" % {'table': tableName})
downgradeCommands.append("%(table)s.create()" % \
{'table': tableName})
for tableName in self.diff.tables_missing_from_B:
upgradeCommands.append("%(table)s.create()" % {'table': tableName})
downgradeCommands.append("%(table)s.drop()" % {'table': tableName})
for tn in self.diff.tables_missing_from_A:
pre_table = self.diff.metadataB.tables[tn]
decls.extend(self._getTableDefn(pre_table, metaName='pre_meta'))
upgradeCommands.append(
"pre_meta.tables[%(table)r].drop()" % {'table': tn})
downgradeCommands.append(
"pre_meta.tables[%(table)r].create()" % {'table': tn})
for tn in self.diff.tables_missing_from_B:
post_table = self.diff.metadataA.tables[tn]
decls.extend(self._getTableDefn(post_table, metaName='post_meta'))
upgradeCommands.append(
"post_meta.tables[%(table)r].create()" % {'table': tn})
downgradeCommands.append(
"post_meta.tables[%(table)r].drop()" % {'table': tn})
for (tn, td) in self.diff.tables_different.iteritems():
if td.columns_missing_from_A or td.columns_different:
pre_table = self.diff.metadataB.tables[tn]
decls.extend(self._getTableDefn(
pre_table, metaName='pre_meta'))
if td.columns_missing_from_B or td.columns_different:
post_table = self.diff.metadataA.tables[tn]
decls.extend(self._getTableDefn(
post_table, metaName='post_meta'))
for tableName in self.diff.tables_different:
dbTable = self.diff.metadataB.tables[tableName]
td = self.diff.tables_different[tableName]
for col in td.columns_missing_from_A:
upgradeCommands.append('%s.append_column(%s)' % (
tableName,
self.column_repr(
self.diff.metadataB.tables[tableName].columns[col])))
downgradeCommands.append('%s.columns[%r].drop()' % (tableName, col))
upgradeCommands.append(
'pre_meta.tables[%r].columns[%r].drop()' % (tn, col))
downgradeCommands.append(
'pre_meta.tables[%r].columns[%r].create()' % (tn, col))
for col in td.columns_missing_from_B:
upgradeCommands.append('%s.columns[%r].drop()' % (tableName, col))
downgradeCommands.append('%s.columns[%r].create()' % (tableName, col))
upgradeCommands.append(
'post_meta.tables[%r].columns[%r].create()' % (tn, col))
downgradeCommands.append(
'post_meta.tables[%r].columns[%r].drop()' % (tn, col))
for modelCol, databaseCol, modelDecl, databaseDecl in td.columns_different:
upgradeCommands.append(
'assert False, "Can\'t alter columns: %s:%s=>%s"' % (
tableName, modelCol.name, databaseCol.name))
tn, modelCol.name, databaseCol.name))
downgradeCommands.append(
'assert False, "Can\'t alter columns: %s:%s=>%s"' % (
tableName, modelCol.name, databaseCol.name))
pre_command = ' meta.bind = migrate_engine'
tn, modelCol.name, databaseCol.name))
return (
'\n'.join(decls),
'\n'.join([pre_command] + ['%s%s' % (indent, line) for line in upgradeCommands]),
'\n'.join([pre_command] + ['%s%s' % (indent, line) for line in downgradeCommands]))
'\n'.join('%s%s' % (indent, line) for line in upgradeCommands),
'\n'.join('%s%s' % (indent, line) for line in downgradeCommands))
def _db_can_handle_this_change(self,td):
"""Check if the database can handle going from B to A."""