]> git.ipfire.org Git - thirdparty/sqlalchemy/alembic.git/commitdiff
Fix postgresql automigration for ARRAY types
authorPaul <pbrackin@gmail.com>
Mon, 20 Feb 2017 20:20:17 +0000 (15:20 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 21 Feb 2017 21:28:51 +0000 (16:28 -0500)
Adds a new codepath into render._repr_type() that will consult
the dialect impl for specific types.  On the postgresql side,
the exisiting repr() is combined with a replace featuring
the full autogen render of the nested type.

Co-authored-by: Mike Bayer <mike_mp@zzzcomputing.com>
Fixes: #85
Change-Id: I8796bfeea27d48e6f8bb5ea4562bdc04961ba0d5
Pull-request: https://github.com/zzzeek/alembic/pull/38

alembic/autogenerate/render.py
alembic/ddl/impl.py
alembic/ddl/postgresql.py
docs/build/changelog.rst
tests/test_postgresql.py

index 476c1f9fa35c93e55d0fb343541c0eb9ad6bd751..6e10792a004786b98e0ac982eb88df93c1f44bd6 100644 (file)
@@ -566,13 +566,20 @@ def _repr_type(type_, autogen_context):
     if rendered is not False:
         return rendered
 
+    if hasattr(autogen_context.migration_context, 'impl'):
+        impl_rt = autogen_context.migration_context.impl.render_type(
+            type_, autogen_context)
+
     mod = type(type_).__module__
     imports = autogen_context.imports
     if mod.startswith("sqlalchemy.dialects"):
         dname = re.match(r"sqlalchemy\.dialects\.(\w+)", mod).group(1)
         if imports is not None:
             imports.add("from sqlalchemy.dialects import %s" % dname)
-        return "%s.%r" % (dname, type_)
+        if impl_rt:
+            return impl_rt
+        else:
+            return "%s.%r" % (dname, type_)
     elif mod.startswith("sqlalchemy."):
         prefix = _sqlalchemy_autogenerate_prefix(autogen_context)
         return "%s%r" % (prefix, type_)
index 52cc4702f90bcd63ca719334a84f4f3f991c69c4..0971c216f37b4822a26c8cb537011d71f6b54648 100644 (file)
@@ -320,6 +320,9 @@ class DefaultImpl(with_metaclass(ImplMeta)):
         """
         self.static_output("COMMIT" + self.command_terminator)
 
+    def render_type(self, type_obj, autogen_context):
+        return False
+
 
 def _string_compare(t1, t2):
     return \
index fa78e53fbba19143e745a58922ba5f1d5c23686b..ecf0dda13147f1cbaf200006992032e9422a4948 100644 (file)
@@ -6,6 +6,7 @@ from .base import compiles, alter_column, alter_table, format_table_name, \
     format_type, AlterColumn, RenameTable
 from .impl import DefaultImpl
 from sqlalchemy.dialects.postgresql import INTEGER, BIGINT
+from ..autogenerate import render
 from sqlalchemy import text, Numeric, Column
 from sqlalchemy import types as sqltypes
 
@@ -105,7 +106,6 @@ class PostgresqlImpl(DefaultImpl):
             **kw)
 
 
-
     def autogen_column_reflect(self, inspector, table, column_info):
         if column_info.get('default') and \
                 isinstance(column_info['type'], (INTEGER, BIGINT)):
@@ -171,6 +171,18 @@ class PostgresqlImpl(DefaultImpl):
                     )
                     metadata_indexes.discard(idx)
 
+    def render_type(self, type_, autogen_context):
+        if hasattr(self, '_render_%s_type' % type_.__visit_name__):
+            meth = getattr(self, '_render_%s_type' % type_.__visit_name__)
+            return meth(type_, autogen_context)
+
+        return False
+
+    def _render_ARRAY_type(self, type_, autogen_context):
+        sub_type = render._repr_type(type_.item_type, autogen_context)
+        outer_type = repr(type_).replace(repr(type_.item_type), sub_type)
+        return "%s.%s" % ("postgresql", outer_type)
+
 
 class PostgresqlColumnType(AlterColumn):
 
index 2ccdf6ce00c6436ef4637f630fc2237aaede4a5a..ca6834de99621c036db3e1b43a109196544cb3f2 100644 (file)
@@ -7,6 +7,15 @@ Changelog
     :version: 0.9.0
     :released:
 
+    .. change:: 85
+      :tags: bug, postgresql
+      :tickets: 85
+
+      Fixed bug where Postgresql ARRAY type would not render the import prefix
+      for the inner type; additionally, user-defined renderers take place
+      for the inner type as well as the outer type.  Pull request courtesy
+      Paul Brackin.
+
     .. change:: fk_schema_compare
       :tags: bug, operations
 
index 2a3378db14b79b4374fbdaf16bb868c03337fc7a..628357b9f124a9b376fbebcf5a6637ebc7e4a55c 100644 (file)
@@ -1,7 +1,7 @@
 
 from sqlalchemy import DateTime, MetaData, Table, Column, text, Integer, \
     String, Interval, Sequence, Numeric, BigInteger, Float, Numeric
-from sqlalchemy.dialects.postgresql import ARRAY, UUID
+from sqlalchemy.dialects.postgresql import ARRAY, UUID, BYTEA
 from sqlalchemy.engine.reflection import Inspector
 from alembic.operations import Operations
 from sqlalchemy.sql import table, column
@@ -602,3 +602,45 @@ unique=False, """
             'nullable=False)'
         )
 
+    @config.requirements.sqlalchemy_09
+    def test_array_type(self):
+
+        eq_ignore_whitespace(
+            autogenerate.render._repr_type(
+                ARRAY(Integer), self.autogen_context),
+            "postgresql.ARRAY(sa.Integer())"
+        )
+
+        eq_ignore_whitespace(
+            autogenerate.render._repr_type(
+                ARRAY(DateTime(timezone=True)), self.autogen_context),
+            "postgresql.ARRAY(sa.DateTime(timezone=True))"
+        )
+
+        eq_ignore_whitespace(
+            autogenerate.render._repr_type(
+                ARRAY(BYTEA, as_tuple=True, dimensions=2),
+                self.autogen_context),
+            "postgresql.ARRAY(postgresql.BYTEA(), as_tuple=True, dimensions=2)"
+        )
+
+        assert 'from sqlalchemy.dialects import postgresql' in \
+            self.autogen_context.imports
+
+    @config.requirements.sqlalchemy_09
+    def test_array_type_user_defined_inner(self):
+        def repr_type(typestring, object_, autogen_context):
+            if typestring == 'type' and isinstance(object_, String):
+                return "foobar.MYVARCHAR"
+            else:
+                return False
+
+        self.autogen_context.opts.update(
+            render_item=repr_type
+        )
+
+        eq_ignore_whitespace(
+            autogenerate.render._repr_type(
+                ARRAY(String), self.autogen_context),
+            "postgresql.ARRAY(foobar.MYVARCHAR)"
+        )