updated changeset documentation, added alter_metadata to all schema classes

This commit is contained in:
iElectric 2009-06-28 08:32:27 +00:00
parent 75e93aa410
commit 08e5d10786
3 changed files with 100 additions and 54 deletions

View File

@ -1,7 +1,7 @@
0.5.5 0.5.5
----- -----
- alter column constructs now accept `alter_metadata` parameter. If True, it will modify Column/Table objects according to changes. Otherwise, everything will be untouched. - alter, create, drop column / rename table / rename index constructs now accept `alter_metadata` parameter. If True, it will modify Column/Table objects according to changes. Otherwise, everything will be untouched.
- complete refactoring of :class:`~migrate.changeset.schema.ColumnDelta` (fixes issue 23) - complete refactoring of :class:`~migrate.changeset.schema.ColumnDelta` (fixes issue 23)
- added support for :ref:`firebird <firebird-d>` - added support for :ref:`firebird <firebird-d>`
- fixed bug when column.alter(server_default='string') was not properly set - fixed bug when column.alter(server_default='string') was not properly set

View File

@ -5,7 +5,7 @@
Database changeset Database changeset
****************** ******************
.. currentmodule:: migrate.changeset .. currentmodule:: migrate.changeset.schema
Importing :mod:`migrate.changeset` adds some new methods to existing Importing :mod:`migrate.changeset` adds some new methods to existing
SA objects, as well as creating functions of its own. Most operations SA objects, as well as creating functions of its own. Most operations
@ -21,6 +21,10 @@ Changeset operations can be used independently of SQLAlchemy Migrate's
For more information, see the generated documentation for For more information, see the generated documentation for
:mod:`migrate.changeset`. :mod:`migrate.changeset`.
.. note::
alter_metadata keyword defaults to True.
Column Column
====== ======
@ -33,7 +37,7 @@ Given a standard SQLAlchemy table::
.. _column-create: .. _column-create:
Create a column:: :meth:`Create a column <ChangesetColumn.create>`::
col = Column('col1', String) col = Column('col1', String)
col.create(table) col.create(table)
@ -43,14 +47,14 @@ Create a column::
.. _column-drop: .. _column-drop:
Drop a column:: :meth:`Drop a column <ChangesetColumn.drop>`::
col.drop() col.drop()
.. _column-alter: .. _column-alter:
Alter a column:: :meth:`Alter a column <ChangesetColumn.alter>`::
col.alter(name='col2') col.alter(name='col2')
@ -75,9 +79,9 @@ Alter a column::
Table Table
===== =====
SQLAlchemy supports `table create/drop`_ SQLAlchemy supports `table create/drop`_.
Rename a table:: :meth:`Rename a table <ChangesetTable.rename>`::
table.rename('newtablename') table.rename('newtablename')
@ -90,9 +94,9 @@ Rename a table::
Index Index
===== =====
SQLAlchemy supports `index create/drop`_ SQLAlchemy supports `index create/drop`_.
Rename an index, given an SQLAlchemy ``Index`` object:: :meth:`Rename an index <migrate.changeset.schema.ChangesetIndex.rename>`, given an SQLAlchemy ``Index`` object::
index.rename('newindexname') index.rename('newindexname')

View File

@ -25,72 +25,72 @@ __all__ = [
DEFAULT_ALTER_METADATA = True DEFAULT_ALTER_METADATA = True
def create_column(column, table=None, *p, **k): def create_column(column, table=None, *p, **kw):
"""Create a column, given the table """Create a column, given the table.
API to :meth:`ChangesetColumn.create` API to :meth:`ChangesetColumn.create`.
""" """
if table is not None: if table is not None:
return table.create_column(column, *p, **k) return table.create_column(column, *p, **kw)
return column.create(*p, **k) return column.create(*p, **kw)
def drop_column(column, table=None, *p, **k): def drop_column(column, table=None, *p, **kw):
"""Drop a column, given the table """Drop a column, given the table.
API to :meth:`ChangesetColumn.drop` API to :meth:`ChangesetColumn.drop`.
""" """
if table is not None: if table is not None:
return table.drop_column(column, *p, **k) return table.drop_column(column, *p, **kw)
return column.drop(*p, **k) return column.drop(*p, **kw)
def rename_table(table, name, engine=None): def rename_table(table, name, engine=None, **kw):
"""Rename a table. """Rename a table.
If Table instance is given, engine is not used. If Table instance is given, engine is not used.
API to :meth:`ChangesetTable.rename` API to :meth:`ChangesetTable.rename`.
:param table: Table to be renamed :param table: Table to be renamed.
:param name: new name :param name: New name for Table.
:param engine: Engine instance :param engine: Engine instance.
:type table: string or Table instance :type table: string or Table instance
:type name: string :type name: string
:type engine: obj :type engine: obj
""" """
table = _to_table(table, engine) table = _to_table(table, engine)
table.rename(name) table.rename(name, **kw)
def rename_index(index, name, table=None, engine=None): def rename_index(index, name, table=None, engine=None, **kw):
"""Rename an index. """Rename an index.
If Index and Table object instances are given, If Index instance is given,
table and engine are not used. table and engine are not used.
API to :meth:`ChangesetIndex.rename` API to :meth:`ChangesetIndex.rename`.
:param index: Index to be renamed :param index: Index to be renamed.
:param name: new name :param name: New name for index.
:param table: Table to which Index is reffered :param table: Table to which Index is reffered.
:param engine: Engine instance :param engine: Engine instance.
:type index: string or Index instance :type index: string or Index instance
:type name: string :type name: string
:type table: string or Table instance :type table: string or Table instance
:type engine: obj :type engine: obj
""" """
index = _to_index(index, table, engine) index = _to_index(index, table, engine)
index.rename(name) index.rename(name, **kw)
def alter_column(*p, **k): def alter_column(*p, **k):
"""Alter a column. """Alter a column.
Direct API to :class:`ColumnDelta` Direct API to :class:`ColumnDelta`.
:param table: Table or table name (will issue reflection) :param table: Table or table name (will issue reflection).
:param engine: Will be used for reflection :param engine: Will be used for reflection.
:param alter_metadata: Defaults to True. It will alter changes also to objects. :param alter_metadata: Defaults to True. It will alter changes also to objects.
:returns: :class:`Columndelta` instance :returns: :class:`Columndelta` instance
""" """
@ -378,19 +378,30 @@ class ColumnDelta(DictMixin, sqlalchemy.schema.SchemaItem):
class ChangesetTable(object): class ChangesetTable(object):
"""Changeset extensions to SQLAlchemy tables.""" """Changeset extensions to SQLAlchemy tables."""
def create_column(self, column, **kw): def create_column(self, column, *p, **kw):
"""Creates a column. """Creates a column.
The column parameter may be a column definition or the name of The column parameter may be a column definition or the name of
a column in this table. a column in this table.
API to :meth:`ChangesetColumn.create`
:param column: Column to be created
:type column: Column instance or string
""" """
if not isinstance(column, sqlalchemy.Column): if not isinstance(column, sqlalchemy.Column):
# It's a column name # It's a column name
column = getattr(self.c, str(column)) column = getattr(self.c, str(column))
column.create(table=self) column.create(table=self, *p, **kw)
def drop_column(self, column, **kw): def drop_column(self, column, *p, **kw):
"""Drop a column, given its name or definition.""" """Drop a column, given its name or definition.
API to :meth:`ChangesetColumn.drop`
:param column: Column to be droped
:type column: Column instance or string
"""
if not isinstance(column, sqlalchemy.Column): if not isinstance(column, sqlalchemy.Column):
# It's a column name # It's a column name
try: try:
@ -400,23 +411,27 @@ class ChangesetTable(object):
# its entire definition to drop the column, just its # its entire definition to drop the column, just its
# name, so create a dummy column with the same name. # name, so create a dummy column with the same name.
column = sqlalchemy.Column(str(column)) column = sqlalchemy.Column(str(column))
column.drop(table=self) column.drop(table=self, *p, **kw)
def rename(self, name, *args, **kwargs): def rename(self, name, *args, **kwargs):
"""Rename this table. """Rename this table.
This changes both the database name and the name of this :param name: New name of the table.
Python object :type name: string
:param alter_metadata: If True, table will be removed from metadata
:type alter_metadata: bool
""" """
self.alter_metadata = kwargs.pop('alter_metadata', DEFAULT_ALTER_METADATA)
engine = self.bind engine = self.bind
self.new_name = name self.new_name = name
visitorcallable = get_engine_visitor(engine, 'schemachanger') visitorcallable = get_engine_visitor(engine, 'schemachanger')
run_single_visitor(engine, visitorcallable, self, *args, **kwargs) run_single_visitor(engine, visitorcallable, self, *args, **kwargs)
# Fix metadata registration # Fix metadata registration
self.name = name if self.alter_metadata:
self.deregister() self.name = name
self._set_parent(self.metadata) self.deregister()
self._set_parent(self.metadata)
def _meta_key(self): def _meta_key(self):
return sqlalchemy.schema._get_table_key(self.name, self.schema) return sqlalchemy.schema._get_table_key(self.name, self.schema)
@ -430,7 +445,7 @@ class ChangesetTable(object):
class ChangesetColumn(object): class ChangesetColumn(object):
"""Changeset extensions to SQLAlchemy columns""" """Changeset extensions to SQLAlchemy columns."""
def alter(self, *p, **k): def alter(self, *p, **k):
"""Alter a column's definition: ``ALTER TABLE ALTER COLUMN``. """Alter a column's definition: ``ALTER TABLE ALTER COLUMN``.
@ -442,7 +457,8 @@ class ChangesetColumn(object):
col.alter(Column('myint', Integer, DefaultClause('foobar'))) col.alter(Column('myint', Integer, DefaultClause('foobar')))
col.alter('myint', Integer, server_default='foobar', nullable=False) col.alter('myint', Integer, server_default='foobar', nullable=False)
col.alter(DefaultClause('foobar'), name='myint', type=Integer, nullable=False) col.alter(DefaultClause('foobar'), name='myint', type=Integer,\
nullable=False)
Column name, type, server_default, and nullable may be changed Column name, type, server_default, and nullable may be changed
here. here.
@ -461,14 +477,29 @@ class ChangesetColumn(object):
Assumes the given table exists. ``ALTER TABLE ADD COLUMN``, Assumes the given table exists. ``ALTER TABLE ADD COLUMN``,
for most databases. for most databases.
:param table: Table instance to create on.
:param index_name: Creates :class:`ChangesetIndex` on this column.
:param unique_name: Creates :class:\
`~migrate.changeset.constraint.UniqueConstraint` on this column.
:param primary_key_name: Creates :class:\
`~migrate.changeset.constraint.PrimaryKeyConstraint` on this column.
:param alter_metadata: If True, column will be added to table object.
:type table: Table instance
:type index_name: string
:type unique_name: string
:type primary_key_name: string
:type alter_metadata: bool
""" """
self.alter_metadata = kwargs.pop('alter_metadata', DEFAULT_ALTER_METADATA)
self.index_name = index_name self.index_name = index_name
self.unique_name = unique_name self.unique_name = unique_name
self.primary_key_name = primary_key_name self.primary_key_name = primary_key_name
for cons in ('index_name', 'unique_name', 'primary_key_name'): for cons in ('index_name', 'unique_name', 'primary_key_name'):
self._check_sanity_constraints(cons) self._check_sanity_constraints(cons)
self.add_to_table(table) if self.alter_metadata:
self.add_to_table(table)
engine = self.table.bind engine = self.table.bind
visitorcallable = get_engine_visitor(engine, 'columngenerator') visitorcallable = get_engine_visitor(engine, 'columngenerator')
engine._run_visitor(visitorcallable, self, *args, **kwargs) engine._run_visitor(visitorcallable, self, *args, **kwargs)
@ -478,13 +509,20 @@ class ChangesetColumn(object):
"""Drop this column from the database, leaving its table intact. """Drop this column from the database, leaving its table intact.
``ALTER TABLE DROP COLUMN``, for most databases. ``ALTER TABLE DROP COLUMN``, for most databases.
:param alter_metadata: If True, column will be removed from table object.
:type alter_metadata: bool
""" """
self.alter_metadata = kwargs.pop('alter_metadata', DEFAULT_ALTER_METADATA)
if table is not None: if table is not None:
self.table = table self.table = table
engine = self.table.bind engine = self.table.bind
self.remove_from_table(self.table, unset_table=False) if self.alter_metadata:
self.remove_from_table(self.table, unset_table=False)
visitorcallable = get_engine_visitor(engine, 'columndropper') visitorcallable = get_engine_visitor(engine, 'columndropper')
engine._run_visitor(visitorcallable, self, *args, **kwargs) engine._run_visitor(visitorcallable, self, *args, **kwargs)
if self.alter_metadata:
self.table = None
return self return self
def add_to_table(self, table): def add_to_table(self, table):
@ -515,7 +553,7 @@ class ChangesetColumn(object):
*[c.copy(**kw) for c in self.constraints]) *[c.copy(**kw) for c in self.constraints])
def _check_sanity_constraints(self, name): def _check_sanity_constraints(self, name):
"""Check if constraints names are correct"""
obj = getattr(self, name) obj = getattr(self, name)
if (getattr(self, name[:-5]) and not obj): if (getattr(self, name[:-5]) and not obj):
raise InvalidConstraintError("Column.create() accepts index_name," raise InvalidConstraintError("Column.create() accepts index_name,"
@ -533,14 +571,18 @@ class ChangesetIndex(object):
def rename(self, name, *args, **kwargs): def rename(self, name, *args, **kwargs):
"""Change the name of an index. """Change the name of an index.
This changes both the Python object name and the database :param name: New name of the Index.
name. :type name: string
:param alter_metadata: If True, Index object will be altered.
:type alter_metadata: bool
""" """
self.alter_metadata = kwargs.pop('alter_metadata', DEFAULT_ALTER_METADATA)
engine = self.table.bind engine = self.table.bind
self.new_name = name self.new_name = name
visitorcallable = get_engine_visitor(engine, 'schemachanger') visitorcallable = get_engine_visitor(engine, 'schemachanger')
engine._run_visitor(visitorcallable, self, *args, **kwargs) engine._run_visitor(visitorcallable, self, *args, **kwargs)
self.name = name if self.alter_metadata:
self.name = name
class ChangesetDefaultClause(object): class ChangesetDefaultClause(object):