from sqlalchemy import MetaData, Table, Column, String, literal_column, \
text
from sqlalchemy import schema, create_engine
-import logging
+from sqlalchemy.util import importlater
+import logging
+base = importlater("alembic.ddl", "base")
log = logging.getLogger(__name__)
class ContextMeta(type):
nullable=util.NO_VALUE,
server_default=util.NO_VALUE,
name=util.NO_VALUE,
- type=util.NO_VALUE
+ type=util.NO_VALUE,
+ schema=None,
):
if nullable is not util.NO_VALUE:
- self._exec(base.ColumnNullable(table_name, column_name, nullable))
+ self._exec(base.ColumnNullable(table_name, column_name, nullable, schema=schema))
if server_default is not util.NO_VALUE:
self._exec(base.ColumnDefault(
- table_name, column_name, server_default
+ table_name, column_name, server_default,
+ schema=schema
))
# ... etc
+ def add_column(self, table_name, column):
+ self._exec(base.AddColumn(table_name, column))
+
+ def drop_column(self, table_name, column):
+ self._exec(base.DropColumn(table_name, column))
+
def add_constraint(self, const):
self._exec(schema.AddConstraint(const))
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
+
@compiles(AddColumn)
def visit_add_column(element, compiler, **kw):
return "%s %s" % (
add_column(compiler, element.column, **kw)
)
+@compiles(DropColumn)
+def visit_drop_column(element, compiler, **kw):
+ return "%s %s" % (
+ alter_table(compiler, element.table_name, element.schema),
+ drop_column(compiler, element.column.name, **kw)
+ )
+
@compiles(ColumnNullable)
def visit_column_nullable(element, compiler, **kw):
return "%s %s %s" % (
__all__ = [
'alter_column',
+ 'add_column',
'create_foreign_key',
'create_table',
'drop_table',
'get_bind',
'execute']
-def alter_column(table_name, column_name,
- nullable=util.NO_VALUE,
- server_default=util.NO_VALUE,
- name=util.NO_VALUE,
- type_=util.NO_VALUE
-):
- """Issue ALTER COLUMN using the current change context."""
-
- context.alter_column(table_name, column_name,
- nullable=nullable,
- server_default=server_default,
- name=name,
- type_=type_
- )
-
-
def _foreign_key_constraint(name, source, referent, local_cols, remote_cols):
m = schema.MetaData()
t1 = schema.Table(source, m,
_ensure_table_for_fk(m, f)
return t
+def _column(name, type_, **kw):
+ return schema.Column(name, type_, **kw)
+
def _ensure_table_for_fk(metadata, fk):
"""create a placeholder Table object for the referent of a
ForeignKey.
if not rel_t.c.contains_column(cname):
rel_t.append_column(schema.Column(cname, NULLTYPE))
+
+def alter_column(table_name, column_name,
+ nullable=util.NO_VALUE,
+ server_default=util.NO_VALUE,
+ name=util.NO_VALUE,
+ type_=util.NO_VALUE
+):
+ """Issue ALTER COLUMN using the current change context."""
+
+ get_context().alter_column(table_name, column_name,
+ nullable=nullable,
+ server_default=server_default,
+ name=name,
+ type_=type_
+ )
+
+def add_column(table_name, column_name,
+ type_, **kw):
+ c = _column(column_name, type_, **kw)
+ t = _table(table_name, c)
+ get_context().add_column(
+ table_name,
+ c
+ )
+
+def drop_column(table_name, column_name):
+ get_context().drop_column(
+ table_name,
+ _column(column_name, NULLTYPE)
+ )
+
+
def create_foreign_key(name, source, referent, local_cols, remote_cols):
get_context().add_constraint(
_foreign_key_constraint(source, referent,
import os
import itertools
from sqlalchemy import create_engine
+from alembic import context
staging_directory = os.path.join(os.path.dirname(__file__), 'scratch')
os.mkdir(staging_directory)
return Config(os.path.join(staging_directory, 'test_alembic.ini'))
+class _op_fixture(context.DefaultContext):
+ def __init__(self):
+ # TODO: accept dialect here.
+ context._context = self
+ self.assertion = []
+
+ def _exec(self, construct):
+ self.assertion.append(
+ unicode(construct.compile())
+ )
+
+ def assert_(self, sql):
+ # TODO: make this more flexible about
+ # whitespace and such
+ eq_("\n".join(self.assertion), sql)
+
def _sqlite_testing_config():
cfg = _testing_config()
dir_ = os.path.join(staging_directory, 'scripts')
from sqlalchemy.types import String, Integer, DateTime
from alembic.ddl.base import AddColumn, ColumnNullable, ColumnType, ColumnName
+# TODO: should these all just go to test_op ?
def test_add_column():
assert_compiled(
--- /dev/null
+"""Test against the builders in the op.* module."""
+
+from tests import _op_fixture
+from alembic import op
+from sqlalchemy import Integer
+
+def test_add_column():
+ context = _op_fixture()
+ op.add_column('t1', 'c1', Integer, nullable=False)
+ context.assert_("ALTER TABLE t1 ADD COLUMN c1 INTEGER NOT NULL")
+
+
+def test_drop_column():
+ context = _op_fixture()
+ op.drop_column('t1', 'c1')
+ context.assert_("ALTER TABLE t1 DROP COLUMN c1")
MetaData, Table
from sqlalchemy import Integer
+# TODO: should these all just go to test_op ?
+
def test_foreign_key():
fk = op._foreign_key_constraint('fk_test', 't1', 't2',
['foo', 'bar'], ['bat', 'hoho'])
)
-def test_table():
+def test_table_schema_fk():
tb = op._table("some_table",
Column('id', Integer, primary_key=True),
Column('foo_id', Integer, ForeignKey('foo.id')),
"FOREIGN KEY(foo_id) REFERENCES foo (id))"
)
+def test_table_two_fk():
tb = op._table("some_table",
Column('id', Integer, primary_key=True),
Column('foo_id', Integer, ForeignKey('foo.id')),
"FOREIGN KEY(foo_bar) REFERENCES foo (bar))"
)
- m = MetaData()
- foo = Table('foo', m, Column('id', Integer, primary_key=True))
- tb = op._table("some_table",
- Column('id', Integer, primary_key=True),
- Column('foo_id', Integer, ForeignKey('foo.id')),
- )
- assert_compiled(
- CreateTable(tb),
- "CREATE TABLE some_table ("
- "id INTEGER NOT NULL, "
- "foo_id INTEGER, "
- "PRIMARY KEY (id), "
- "FOREIGN KEY(foo_id) REFERENCES foo (id))"
- )
\ No newline at end of file