]> git.ipfire.org Git - thirdparty/sqlalchemy/alembic.git/commitdiff
- basic DDL methodology
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 24 Apr 2010 14:57:38 +0000 (10:57 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 24 Apr 2010 14:57:38 +0000 (10:57 -0400)
- need some framework to abstract operations to DDL instructions,
as we can't assume the number of executions per operation

alembic/ddl/base.py
alembic/ddl/op.py [new file with mode: 0644]
alembic/ddl/postgresql.py
alembic/op.py [new file with mode: 0644]
tests/__init__.py
tests/test_ddl.py [new file with mode: 0644]

index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ff86f1f6dbdfd19688c9d53f2cc06589445e3791 100644 (file)
@@ -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 (file)
index 0000000..462c9fd
--- /dev/null
@@ -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
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..91dadf5242c0e2674a459a736d5fd3bb06335bc3 100644 (file)
@@ -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 (file)
index 0000000..6211903
--- /dev/null
@@ -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
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..235a34951d4c7adb5ad6e101e0fd00362bec1aad 100644 (file)
@@ -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 (file)
index 0000000..105dc6a
--- /dev/null
@@ -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