From: Mike Bayer Date: Sat, 24 Apr 2010 14:57:38 +0000 (-0400) Subject: - basic DDL methodology X-Git-Tag: rel_0_1_0~116 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9a4694655a1714aad06d60ffd7080c80f8700829;p=thirdparty%2Fsqlalchemy%2Falembic.git - basic DDL methodology - need some framework to abstract operations to DDL instructions, as we can't assume the number of executions per operation --- diff --git a/alembic/ddl/base.py b/alembic/ddl/base.py index e69de29b..ff86f1f6 100644 --- a/alembic/ddl/base.py +++ b/alembic/ddl/base.py @@ -0,0 +1,89 @@ +import functools +from sqlalchemy.ext.compiler import compiles +from sqlalchemy.schema import DDLElement + +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 AlterColumn(AlterTable): + def __init__(self, name, column_name, schema=None): + super(AlterColumn, self).__init__(name, schema=schema) + self.column_name = column_name + +class ColumnNullable(AlterColumn): + def __init__(self, name, column_name, nullable, schema=None): + super(ColumnNullable, self).__init__(name, column_name, schema=schema) + self.nullable = nullable + +class ColumnType(AlterColumn): + def __init__(self, name, column_name, type_, schema=None): + super(ColumnType, self).__init__(name, column_name, schema=schema) + self.type_ = type_ + +class ColumnName(AlterColumn): + def __init__(self, name, column_name, newname, schema=None): + super(ColumnName, self).__init__(name, column_name, schema=schema) + self.newname = newname + +class ColumnDefault(AlterColumn): + def __init__(self, name, column_name, default, schema=None): + super(ColumnDefault, self).__init__(name, column_name, schema=schema) + self.default = default + +class AddColumn(AlterTable): + def __init__(self, name, column, schema=None): + super(AddColumn, self).__init__(name, schema=schema) + self.column = column + +@compiles(AddColumn) +def visit_add_column(element, compiler, **kw): + return "%s %s" % ( + alter_table(compiler, element.table_name, element.schema), + add_column(compiler, element.column, **kw) + ) + +@compiles(ColumnNullable) +def visit_column_nullable(element, compiler, **kw): + return "%s %s %s" % ( + alter_table(compiler, element.table_name, element.schema), + alter_column(compiler, element.column_name), + "NULL" if element.nullable else "NOT NULL" + ) + +def quote_dotted(name, quote): + """quote the elements of a dotted name""" + + result = '.'.join([quote(x) for x in name.split('.')]) + return result + +def format_table_name(compiler, name, schema): + quote = functools.partial(compiler.preparer.quote, force=None) + if schema: + return quote_dotted(schema, quote) + "." + quote(name) + else: + return quote(name) + +def format_column_name(compiler, name): + return compiler.preparer.quote(name, None) + +def alter_table(compiler, name, schema): + return "ALTER TABLE %s" % format_table_name(compiler, name, schema) + +def drop_column(compiler, name): + return 'DROP COLUMN %s' % format_column_name(compiler, name) + +def alter_column(compiler, name): + return 'ALTER COLUMN %s' % format_column_name(compiler, name) + +def add_column(compiler, column, **kw): + return "ADD COLUMN %s" % compiler.get_column_specification(column, **kw) + + diff --git a/alembic/ddl/op.py b/alembic/ddl/op.py new file mode 100644 index 00000000..462c9fd8 --- /dev/null +++ b/alembic/ddl/op.py @@ -0,0 +1,13 @@ +def alter_column(table_name, column_name, + nullable=NO_VALUE, + server_default=NO_VALUE, + name=NO_VALUE, + type=NO_VALUE +): + + if nullable is not NO_VALUE: + ColumnNullable(table_name, column_name, nullable) + if server_default is not NO_VALUE: + ColumnDefault(table_name, column_name, server_default) + + # ... etc \ No newline at end of file diff --git a/alembic/ddl/postgresql.py b/alembic/ddl/postgresql.py index e69de29b..91dadf52 100644 --- a/alembic/ddl/postgresql.py +++ b/alembic/ddl/postgresql.py @@ -0,0 +1 @@ +"ALTER TABLE foo ADD COLUMN bat integer NOT NULL DEFAULT 7;" \ No newline at end of file diff --git a/alembic/op.py b/alembic/op.py new file mode 100644 index 00000000..6211903b --- /dev/null +++ b/alembic/op.py @@ -0,0 +1,13 @@ +from sqlalchemy import util + +NO_VALUE = util.symbol("NO_VALUE") + +def alter_column(table_name, column_name, + nullable=NO_VALUE, + server_default=NO_VALUE, + name=NO_VALUE, + type=NO_VALUE +): + """Issue ALTER COLUMN using the current change context.""" + + # TODO: dispatch to ddl.op \ No newline at end of file diff --git a/tests/__init__.py b/tests/__init__.py index e69de29b..235a3495 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -0,0 +1,15 @@ +from sqlalchemy.test.testing import eq_ +from sqlalchemy.util import defaultdict +from sqlalchemy.engine import url, default + +_dialects = defaultdict(lambda name:url.URL(drivername).get_dialect()()) +def _get_dialect(name): + if name is None: + return default.DefaultDialect() + else: + return _dialects[name] + + +def assert_compiled(element, assert_string, dialect=None): + dialect = _get_dialect(dialect) + eq_(unicode(element.compile(dialect=dialect)), assert_string) \ No newline at end of file diff --git a/tests/test_ddl.py b/tests/test_ddl.py new file mode 100644 index 00000000..105dc6a3 --- /dev/null +++ b/tests/test_ddl.py @@ -0,0 +1,28 @@ +from tests import assert_compiled +from sqlalchemy.schema import Column +from sqlalchemy.types import String, Integer, DateTime +from alembic.ddl.base import AddColumn, ColumnNullable, ColumnType, ColumnName + + +def test_add_column(): + assert_compiled( + AddColumn("footable", Column("foocol", String(50), nullable=False)), + "ALTER TABLE footable ADD COLUMN foocol VARCHAR(50) NOT NULL" + ) + assert_compiled( + AddColumn("footable", Column("foocol", String(50), server_default="12")), + "ALTER TABLE footable ADD COLUMN foocol VARCHAR(50) DEFAULT '12'" + ) + + +def test_column_nullable(): + assert_compiled( + ColumnNullable("footable", "foocol", True), + "ALTER TABLE footable ALTER COLUMN foocol NULL" + ) + + assert_compiled( + ColumnNullable("footable", "foocol", False), + "ALTER TABLE footable ALTER COLUMN foocol NOT NULL" + ) + \ No newline at end of file