diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2015-06-18 20:52:19 -0400 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2015-06-18 20:52:19 -0400 |
commit | 9ac68646a848dd991c505ffed4be3361dd40b612 (patch) | |
tree | 3d401857af5812cbc4527a695f152d16e3498679 | |
parent | 89a6fa3c1436a490d3c664ee5d37aa95e2d8a9a9 (diff) | |
download | alembic-9ac68646a848dd991c505ffed4be3361dd40b612.tar.gz |
- wip
-rw-r--r-- | alembic/ddl/base.py | 151 | ||||
-rw-r--r-- | alembic/operations/batch.py | 2 | ||||
-rw-r--r-- | alembic/util/sqla_compat.py | 61 |
3 files changed, 71 insertions, 143 deletions
diff --git a/alembic/ddl/base.py b/alembic/ddl/base.py index dbdc991..f19a9a9 100644 --- a/alembic/ddl/base.py +++ b/alembic/ddl/base.py @@ -1,94 +1,20 @@ import functools from sqlalchemy.ext.compiler import compiles -from sqlalchemy.schema import DDLElement, Column, \ - ForeignKeyConstraint, CheckConstraint +from sqlalchemy.schema import Column from sqlalchemy import Integer -from sqlalchemy import types as sqltypes -from sqlalchemy.sql.visitors import traverse from .. import util -if util.sqla_09: - from sqlalchemy.sql.elements import quoted_name - - -class AlterTable(DDLElement): - - """Represent an ALTER TABLE statement. - - Only the string name and optional schema name of the table - is required, not a full Table object. - - """ - - def __init__(self, table_name, schema=None): - self.table_name = table_name - self.schema = schema - - -class RenameTable(AlterTable): - - def __init__(self, old_table_name, new_table_name, schema=None): - super(RenameTable, self).__init__(old_table_name, schema=schema) - self.new_table_name = new_table_name - - -class AlterColumn(AlterTable): - - def __init__(self, name, column_name, schema=None, - existing_type=None, - existing_nullable=None, - existing_server_default=None): - super(AlterColumn, self).__init__(name, schema=schema) - self.column_name = column_name - self.existing_type = sqltypes.to_instance(existing_type) \ - if existing_type is not None else None - self.existing_nullable = existing_nullable - self.existing_server_default = existing_server_default - - -class ColumnNullable(AlterColumn): - - def __init__(self, name, column_name, nullable, **kw): - super(ColumnNullable, self).__init__(name, column_name, - **kw) - self.nullable = nullable - - -class ColumnType(AlterColumn): - - def __init__(self, name, column_name, type_, **kw): - super(ColumnType, self).__init__(name, column_name, - **kw) - self.type_ = sqltypes.to_instance(type_) - - -class ColumnName(AlterColumn): - - def __init__(self, name, column_name, newname, **kw): - super(ColumnName, self).__init__(name, column_name, **kw) - self.newname = newname +# backwards compat +from ..util.sqla_compat import ( # noqa + _table_for_constraint, + _columns_for_constraint, _fk_spec, _is_type_bound, _find_columns) -class ColumnDefault(AlterColumn): - - def __init__(self, name, column_name, default, **kw): - super(ColumnDefault, self).__init__(name, column_name, **kw) - self.default = default - - -class AddColumn(AlterTable): - - def __init__(self, name, column, schema=None): - super(AddColumn, self).__init__(name, schema=schema) - self.column = column - - -class DropColumn(AlterTable): - - def __init__(self, name, column, schema=None): - super(DropColumn, self).__init__(name, schema=schema) - self.column = column +from ..operations import RenameTable, AddColumn, DropColumn, \ + ColumnNullable, ColumnDefault, ColumnType, ColumnName +if util.sqla_09: + from sqlalchemy.sql.elements import quoted_name @compiles(RenameTable) @@ -154,65 +80,6 @@ def visit_column_default(element, compiler, **kw): ) -def _table_for_constraint(constraint): - if isinstance(constraint, ForeignKeyConstraint): - return constraint.parent - else: - return constraint.table - - -def _columns_for_constraint(constraint): - if isinstance(constraint, ForeignKeyConstraint): - return [fk.parent for fk in constraint.elements] - elif isinstance(constraint, CheckConstraint): - return _find_columns(constraint.sqltext) - else: - return list(constraint.columns) - - -def _fk_spec(constraint): - if util.sqla_100: - source_columns = [ - constraint.columns[key].name for key in constraint.column_keys] - else: - source_columns = [ - element.parent.name for element in constraint.elements] - - source_table = constraint.parent.name - source_schema = constraint.parent.schema - target_schema = constraint.elements[0].column.table.schema - target_table = constraint.elements[0].column.table.name - target_columns = [element.column.name for element in constraint.elements] - - return ( - source_schema, source_table, - source_columns, target_schema, target_table, target_columns) - - -def _is_type_bound(constraint): - # this deals with SQLAlchemy #3260, don't copy CHECK constraints - # that will be generated by the type. - if util.sqla_100: - # new feature added for #3260 - return constraint._type_bound - else: - # old way, look at what we know Boolean/Enum to use - return ( - constraint._create_rule is not None and - isinstance( - getattr(constraint._create_rule, "target", None), - sqltypes.SchemaType) - ) - - -def _find_columns(clause): - """locate Column objects within the given expression.""" - - cols = set() - traverse(clause, {}, {'column': cols.add}) - return cols - - def quote_dotted(name, quote): """quote the elements of a dotted name""" diff --git a/alembic/operations/batch.py b/alembic/operations/batch.py index 9644a33..726df78 100644 --- a/alembic/operations/batch.py +++ b/alembic/operations/batch.py @@ -4,7 +4,7 @@ from sqlalchemy import types as sqltypes from sqlalchemy import schema as sql_schema from sqlalchemy.util import OrderedDict from .. import util -from ..ddl.base import _columns_for_constraint, _is_type_bound +from ..util.sqla_compat import _columns_for_constraint, _is_type_bound class BatchOperationsImpl(object): diff --git a/alembic/util/sqla_compat.py b/alembic/util/sqla_compat.py index 41badd4..d2025aa 100644 --- a/alembic/util/sqla_compat.py +++ b/alembic/util/sqla_compat.py @@ -1,5 +1,8 @@ import re from sqlalchemy import __version__ +from sqlalchemy.schema import ForeignKeyConstraint, CheckConstraint +from sqlalchemy import types as sqltypes +from sqlalchemy.sql.visitors import traverse def _safe_int(value): @@ -22,3 +25,61 @@ sqla_099 = _vers >= (0, 9, 9) sqla_100 = _vers >= (1, 0, 0) sqla_105 = _vers >= (1, 0, 5) + +def _table_for_constraint(constraint): + if isinstance(constraint, ForeignKeyConstraint): + return constraint.parent + else: + return constraint.table + + +def _columns_for_constraint(constraint): + if isinstance(constraint, ForeignKeyConstraint): + return [fk.parent for fk in constraint.elements] + elif isinstance(constraint, CheckConstraint): + return _find_columns(constraint.sqltext) + else: + return list(constraint.columns) + + +def _fk_spec(constraint): + if sqla_100: + source_columns = [ + constraint.columns[key].name for key in constraint.column_keys] + else: + source_columns = [ + element.parent.name for element in constraint.elements] + + source_table = constraint.parent.name + source_schema = constraint.parent.schema + target_schema = constraint.elements[0].column.table.schema + target_table = constraint.elements[0].column.table.name + target_columns = [element.column.name for element in constraint.elements] + + return ( + source_schema, source_table, + source_columns, target_schema, target_table, target_columns) + + +def _is_type_bound(constraint): + # this deals with SQLAlchemy #3260, don't copy CHECK constraints + # that will be generated by the type. + if sqla_100: + # new feature added for #3260 + return constraint._type_bound + else: + # old way, look at what we know Boolean/Enum to use + return ( + constraint._create_rule is not None and + isinstance( + getattr(constraint._create_rule, "target", None), + sqltypes.SchemaType) + ) + + +def _find_columns(clause): + """locate Column objects within the given expression.""" + + cols = set() + traverse(clause, {}, {'column': cols.add}) + return cols |