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 in sqlite (issue 96)
|
||||||
- fixed bug with column dropping involving foreign keys
|
- fixed bug with column dropping involving foreign keys
|
||||||
- implemented column adding when foreign keys are present for sqlite
|
- 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)
|
0.6 (11.07.2010)
|
||||||
---------------------------
|
---------------------------
|
||||||
|
@ -108,10 +108,7 @@ class ANSIColumnGenerator(AlterTableVisitor, SchemaGenerator):
|
|||||||
|
|
||||||
# add indexes and unique constraints
|
# add indexes and unique constraints
|
||||||
if column.index_name:
|
if column.index_name:
|
||||||
ix = Index(column.index_name,
|
Index(column.index_name,column).create()
|
||||||
column,
|
|
||||||
unique=bool(column.index_name or column.index))
|
|
||||||
ix.create()
|
|
||||||
elif column.unique_name:
|
elif column.unique_name:
|
||||||
constraint.UniqueConstraint(column,
|
constraint.UniqueConstraint(column,
|
||||||
name=column.unique_name).create()
|
name=column.unique_name).create()
|
||||||
|
@ -26,13 +26,7 @@ class SQLiteCommon(object):
|
|||||||
|
|
||||||
class SQLiteHelper(SQLiteCommon):
|
class SQLiteHelper(SQLiteCommon):
|
||||||
|
|
||||||
def visit_column(self, delta):
|
def recreate_table(self,table,column=None,delta=None):
|
||||||
if isinstance(delta, DictMixin):
|
|
||||||
column = delta.result_column
|
|
||||||
table = self._to_table(delta.table)
|
|
||||||
else:
|
|
||||||
column = delta
|
|
||||||
table = self._to_table(column.table)
|
|
||||||
table_name = self.preparer.format_table(table)
|
table_name = self.preparer.format_table(table)
|
||||||
|
|
||||||
# we remove all indexes so as not to have
|
# we remove all indexes so as not to have
|
||||||
@ -51,6 +45,15 @@ class SQLiteHelper(SQLiteCommon):
|
|||||||
self.append('DROP TABLE migration_tmp')
|
self.append('DROP TABLE migration_tmp')
|
||||||
self.execute()
|
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,
|
class SQLiteColumnGenerator(SQLiteSchemaGenerator,
|
||||||
ansisql.ANSIColumnGenerator,
|
ansisql.ANSIColumnGenerator,
|
||||||
# at the end so we get the normal
|
# at the end so we get the normal
|
||||||
@ -93,7 +96,7 @@ class SQLiteSchemaChanger(SQLiteHelper, ansisql.ANSISchemaChanger):
|
|||||||
self._not_supported('ALTER INDEX')
|
self._not_supported('ALTER INDEX')
|
||||||
|
|
||||||
|
|
||||||
class SQLiteConstraintGenerator(ansisql.ANSIConstraintGenerator, SQLiteCommon):
|
class SQLiteConstraintGenerator(ansisql.ANSIConstraintGenerator, SQLiteHelper, SQLiteCommon):
|
||||||
|
|
||||||
def visit_migrate_primary_key_constraint(self, constraint):
|
def visit_migrate_primary_key_constraint(self, constraint):
|
||||||
tmpl = "CREATE UNIQUE INDEX %s ON %s ( %s )"
|
tmpl = "CREATE UNIQUE INDEX %s ON %s ( %s )"
|
||||||
@ -104,11 +107,14 @@ class SQLiteConstraintGenerator(ansisql.ANSIConstraintGenerator, SQLiteCommon):
|
|||||||
self.append(msg)
|
self.append(msg)
|
||||||
self.execute()
|
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):
|
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):
|
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,
|
class SQLiteConstraintDropper(ansisql.ANSIColumnDropper,
|
||||||
|
@ -8,6 +8,7 @@ from UserDict import DictMixin
|
|||||||
import sqlalchemy
|
import sqlalchemy
|
||||||
|
|
||||||
from sqlalchemy.schema import ForeignKeyConstraint
|
from sqlalchemy.schema import ForeignKeyConstraint
|
||||||
|
from sqlalchemy.schema import UniqueConstraint
|
||||||
|
|
||||||
from migrate.exceptions import *
|
from migrate.exceptions import *
|
||||||
from migrate.changeset import SQLA_06
|
from migrate.changeset import SQLA_06
|
||||||
@ -570,6 +571,9 @@ populated with defaults
|
|||||||
if table is not None and self.table is None:
|
if table is not None and self.table is None:
|
||||||
self._set_parent(table)
|
self._set_parent(table)
|
||||||
|
|
||||||
|
def _col_name_in_constraint(self,cons,name):
|
||||||
|
return False
|
||||||
|
|
||||||
def remove_from_table(self, table, unset_table=True):
|
def remove_from_table(self, table, unset_table=True):
|
||||||
# TODO: remove primary keys, constraints, etc
|
# TODO: remove primary keys, constraints, etc
|
||||||
if unset_table:
|
if unset_table:
|
||||||
@ -590,13 +594,12 @@ populated with defaults
|
|||||||
to_drop = set()
|
to_drop = set()
|
||||||
for cons in table.constraints:
|
for cons in table.constraints:
|
||||||
# TODO: deal with other types of constraint
|
# TODO: deal with other types of constraint
|
||||||
if isinstance(cons,ForeignKeyConstraint):
|
if isinstance(cons,(ForeignKeyConstraint,
|
||||||
col_names = []
|
UniqueConstraint)):
|
||||||
for col_name in cons.columns:
|
for col_name in cons.columns:
|
||||||
if not isinstance(col_name,basestring):
|
if not isinstance(col_name,basestring):
|
||||||
col_name = col_name.name
|
col_name = col_name.name
|
||||||
col_names.append(col_name)
|
if self.name==col_name:
|
||||||
if self.name in col_names:
|
|
||||||
to_drop.add(cons)
|
to_drop.add(cons)
|
||||||
table.constraints = table.constraints - to_drop
|
table.constraints = table.constraints - to_drop
|
||||||
|
|
||||||
|
@ -223,11 +223,11 @@ class TestAddDropColumn(fixture.DB):
|
|||||||
|
|
||||||
col.drop()
|
col.drop()
|
||||||
|
|
||||||
@fixture.usedb(not_supported='sqlite')
|
@fixture.usedb()
|
||||||
def test_unique(self):
|
def test_unique_constraint(self):
|
||||||
"""Can create columns with unique constraint"""
|
|
||||||
self.assertRaises(exceptions.InvalidConstraintError,
|
self.assertRaises(exceptions.InvalidConstraintError,
|
||||||
Column('data', Integer, unique=True).create, self.table)
|
Column('data', Integer, unique=True).create, self.table)
|
||||||
|
|
||||||
col = Column('data', Integer)
|
col = Column('data', Integer)
|
||||||
col.create(self.table, unique_name='data_unique')
|
col.create(self.table, unique_name='data_unique')
|
||||||
|
|
||||||
@ -244,14 +244,34 @@ class TestAddDropColumn(fixture.DB):
|
|||||||
col.drop(self.table)
|
col.drop(self.table)
|
||||||
|
|
||||||
# TODO: remove already attached columns with indexes, uniques, pks, fks ..
|
# 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()
|
@fixture.usedb()
|
||||||
def test_index(self):
|
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 = Column('data', Integer)
|
||||||
col.create(self.table, index_name='ix_data')
|
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
|
# check if index was added
|
||||||
self.table.insert(values={'data': 5}).execute()
|
self.table.insert(values={'data': 5}).execute()
|
||||||
try:
|
try:
|
||||||
@ -262,6 +282,8 @@ class TestAddDropColumn(fixture.DB):
|
|||||||
else:
|
else:
|
||||||
self.fail()
|
self.fail()
|
||||||
|
|
||||||
|
self._check_index(True)
|
||||||
|
|
||||||
Index('ix_data', col).drop(bind=self.engine)
|
Index('ix_data', col).drop(bind=self.engine)
|
||||||
col.drop()
|
col.drop()
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user