Fix issue 94 - it was impossible to add a column with a non-unique index.
Also implement more functionality with unique and foreign key constrains for sqlite.
This commit is contained in:
parent
a085ffa590
commit
adf4113a0b
@ -14,6 +14,11 @@ Fixed bugs
|
||||
- fixed bug with column dropping in sqlite (issue 96)
|
||||
- fixed bug with column dropping involving foreign keys
|
||||
- implemented column adding when foreign keys are present for sqlite
|
||||
- fixed bug that prevented non-unique indexes being created (issue 94)
|
||||
- implemented columns adding with unique constraints for sqlite
|
||||
- implemented adding unique and foreign key constraints to columns
|
||||
for sqlite
|
||||
- fixed bug when dropping columns with unique constraints in sqlite
|
||||
|
||||
0.6 (11.07.2010)
|
||||
---------------------------
|
||||
|
@ -108,10 +108,7 @@ class ANSIColumnGenerator(AlterTableVisitor, SchemaGenerator):
|
||||
|
||||
# add indexes and unique constraints
|
||||
if column.index_name:
|
||||
ix = Index(column.index_name,
|
||||
column,
|
||||
unique=bool(column.index_name or column.index))
|
||||
ix.create()
|
||||
Index(column.index_name,column).create()
|
||||
elif column.unique_name:
|
||||
constraint.UniqueConstraint(column,
|
||||
name=column.unique_name).create()
|
||||
|
@ -26,13 +26,7 @@ class SQLiteCommon(object):
|
||||
|
||||
class SQLiteHelper(SQLiteCommon):
|
||||
|
||||
def visit_column(self, delta):
|
||||
if isinstance(delta, DictMixin):
|
||||
column = delta.result_column
|
||||
table = self._to_table(delta.table)
|
||||
else:
|
||||
column = delta
|
||||
table = self._to_table(column.table)
|
||||
def recreate_table(self,table,column=None,delta=None):
|
||||
table_name = self.preparer.format_table(table)
|
||||
|
||||
# we remove all indexes so as not to have
|
||||
@ -50,6 +44,15 @@ class SQLiteHelper(SQLiteCommon):
|
||||
self.execute()
|
||||
self.append('DROP TABLE migration_tmp')
|
||||
self.execute()
|
||||
|
||||
def visit_column(self, delta):
|
||||
if isinstance(delta, DictMixin):
|
||||
column = delta.result_column
|
||||
table = self._to_table(delta.table)
|
||||
else:
|
||||
column = delta
|
||||
table = self._to_table(column.table)
|
||||
self.recreate_table(table,column,delta)
|
||||
|
||||
class SQLiteColumnGenerator(SQLiteSchemaGenerator,
|
||||
ansisql.ANSIColumnGenerator,
|
||||
@ -93,7 +96,7 @@ class SQLiteSchemaChanger(SQLiteHelper, ansisql.ANSISchemaChanger):
|
||||
self._not_supported('ALTER INDEX')
|
||||
|
||||
|
||||
class SQLiteConstraintGenerator(ansisql.ANSIConstraintGenerator, SQLiteCommon):
|
||||
class SQLiteConstraintGenerator(ansisql.ANSIConstraintGenerator, SQLiteHelper, SQLiteCommon):
|
||||
|
||||
def visit_migrate_primary_key_constraint(self, constraint):
|
||||
tmpl = "CREATE UNIQUE INDEX %s ON %s ( %s )"
|
||||
@ -104,11 +107,14 @@ class SQLiteConstraintGenerator(ansisql.ANSIConstraintGenerator, SQLiteCommon):
|
||||
self.append(msg)
|
||||
self.execute()
|
||||
|
||||
def _modify_table(self, table, column, delta):
|
||||
return 'INSERT INTO %(table_name)s SELECT * from migration_tmp'
|
||||
|
||||
def visit_migrate_foreign_key_constraint(self, *p, **k):
|
||||
self._not_supported('ALTER TABLE ADD CONSTRAINT')
|
||||
self.recreate_table(p[0].table)
|
||||
|
||||
def visit_migrate_unique_constraint(self, *p, **k):
|
||||
self._not_supported('ALTER TABLE ADD CONSTRAINT')
|
||||
self.recreate_table(p[0].table)
|
||||
|
||||
|
||||
class SQLiteConstraintDropper(ansisql.ANSIColumnDropper,
|
||||
|
@ -8,6 +8,7 @@ from UserDict import DictMixin
|
||||
import sqlalchemy
|
||||
|
||||
from sqlalchemy.schema import ForeignKeyConstraint
|
||||
from sqlalchemy.schema import UniqueConstraint
|
||||
|
||||
from migrate.exceptions import *
|
||||
from migrate.changeset import SQLA_06
|
||||
@ -570,6 +571,9 @@ populated with defaults
|
||||
if table is not None and self.table is None:
|
||||
self._set_parent(table)
|
||||
|
||||
def _col_name_in_constraint(self,cons,name):
|
||||
return False
|
||||
|
||||
def remove_from_table(self, table, unset_table=True):
|
||||
# TODO: remove primary keys, constraints, etc
|
||||
if unset_table:
|
||||
@ -590,14 +594,13 @@ populated with defaults
|
||||
to_drop = set()
|
||||
for cons in table.constraints:
|
||||
# TODO: deal with other types of constraint
|
||||
if isinstance(cons,ForeignKeyConstraint):
|
||||
col_names = []
|
||||
if isinstance(cons,(ForeignKeyConstraint,
|
||||
UniqueConstraint)):
|
||||
for col_name in cons.columns:
|
||||
if not isinstance(col_name,basestring):
|
||||
col_name = col_name.name
|
||||
col_names.append(col_name)
|
||||
if self.name in col_names:
|
||||
to_drop.add(cons)
|
||||
if self.name==col_name:
|
||||
to_drop.add(cons)
|
||||
table.constraints = table.constraints - to_drop
|
||||
|
||||
if table.c.contains_column(self):
|
||||
|
@ -223,11 +223,11 @@ class TestAddDropColumn(fixture.DB):
|
||||
|
||||
col.drop()
|
||||
|
||||
@fixture.usedb(not_supported='sqlite')
|
||||
def test_unique(self):
|
||||
"""Can create columns with unique constraint"""
|
||||
@fixture.usedb()
|
||||
def test_unique_constraint(self):
|
||||
self.assertRaises(exceptions.InvalidConstraintError,
|
||||
Column('data', Integer, unique=True).create, self.table)
|
||||
|
||||
col = Column('data', Integer)
|
||||
col.create(self.table, unique_name='data_unique')
|
||||
|
||||
@ -244,14 +244,34 @@ class TestAddDropColumn(fixture.DB):
|
||||
col.drop(self.table)
|
||||
|
||||
# TODO: remove already attached columns with indexes, uniques, pks, fks ..
|
||||
|
||||
def _check_index(self,expected):
|
||||
if 'mysql' in self.engine.name or 'postgres' in self.engine.name:
|
||||
for index in tuple(
|
||||
Table(self.table.name, MetaData(),
|
||||
autoload=True, autoload_with=self.engine).indexes
|
||||
):
|
||||
if index.name=='ix_data':
|
||||
break
|
||||
self.assertEqual(expected,index.unique)
|
||||
|
||||
@fixture.usedb()
|
||||
def test_index(self):
|
||||
"""Can create columns with indexes"""
|
||||
self.assertRaises(exceptions.InvalidConstraintError,
|
||||
Column('data', Integer).create, self.table, index_name=True)
|
||||
col = Column('data', Integer)
|
||||
col.create(self.table, index_name='ix_data')
|
||||
|
||||
self._check_index(False)
|
||||
|
||||
Index('ix_data', col).drop(bind=self.engine)
|
||||
col.drop()
|
||||
|
||||
@fixture.usedb()
|
||||
def test_index_unique(self):
|
||||
# shows how to create a unique index
|
||||
col = Column('data', Integer)
|
||||
col.create(self.table)
|
||||
Index('ix_data', col, unique=True).create(bind=self.engine)
|
||||
|
||||
# check if index was added
|
||||
self.table.insert(values={'data': 5}).execute()
|
||||
try:
|
||||
@ -262,9 +282,11 @@ class TestAddDropColumn(fixture.DB):
|
||||
else:
|
||||
self.fail()
|
||||
|
||||
self._check_index(True)
|
||||
|
||||
Index('ix_data', col).drop(bind=self.engine)
|
||||
col.drop()
|
||||
|
||||
|
||||
@fixture.usedb()
|
||||
def test_server_defaults(self):
|
||||
"""Can create columns with server_default values"""
|
||||
|
Loading…
x
Reference in New Issue
Block a user