]> git.ipfire.org Git - thirdparty/sqlalchemy/alembic.git/commitdiff
Apply subtype repr logic to JSON/JSONB
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 22 Feb 2017 21:59:09 +0000 (16:59 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 22 Feb 2017 22:37:12 +0000 (17:37 -0500)
Fixed bug where Postgresql JSON/JSONB types rendered on SQLAlchemy
1.1 would render the "astext_type" argument which defaults to
the ``Text()`` type without the module prefix, similarly to the
issue with ARRAY fixed in :ticket:`85`.

Also modifies the ARRAY approach from :ticket:`85` to be
regular expression based for safer targeting of the inner
repr() type.

Change-Id: I66d51301f4bf5b747b5e8da26a83cbff075d71b2
Fixes: #411
alembic/ddl/postgresql.py
docs/build/changelog.rst
tests/test_postgresql.py

index 36d9738b01c43f23f75269bc26869ad2b666f411..9d77acecbcf48d20de2ef6e3dfbcce73d4104bdf 100644 (file)
@@ -189,11 +189,36 @@ class PostgresqlImpl(DefaultImpl):
 
         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)
+    def _render_type_w_subtype(self, type_, autogen_context, attrname, regexp):
+        outer_repr = repr(type_)
+        inner_type = getattr(type_, attrname, None)
+        if inner_type is None:
+            return False
+
+        inner_repr = repr(inner_type)
+
+        inner_repr = re.sub(r'([\(\)])', r'\\\1', inner_repr)
+        sub_type = render._repr_type(getattr(type_, attrname), autogen_context)
+        outer_type = re.sub(
+            regexp + inner_repr,
+            r"\1%s" % sub_type, outer_repr)
         return "%s.%s" % ("postgresql", outer_type)
 
+    def _render_ARRAY_type(self, type_, autogen_context):
+        return self._render_type_w_subtype(
+            type_, autogen_context, 'item_type', r'(.+?\()'
+        )
+
+    def _render_JSON_type(self, type_, autogen_context):
+        return self._render_type_w_subtype(
+            type_, autogen_context, 'astext_type', r'(.+?\(.*astext_type=)'
+        )
+
+    def _render_JSONB_type(self, type_, autogen_context):
+        return self._render_type_w_subtype(
+            type_, autogen_context, 'astext_type', r'(.+?\(.*astext_type=)'
+        )
+
 
 class PostgresqlColumnType(AlterColumn):
 
index 23193ff4f78fc294508d26d773d41ed11f2f34c7..55524481fc6484d39789d36b9843f94a9b985a03 100644 (file)
@@ -24,6 +24,15 @@ Changelog
       flag does **not** support alteration of a column's "autoincrement" status,
       as this is not portable across backends.
 
+    .. change:: 411
+      :tags: bug, postgresql
+      :tickets: 411
+
+      Fixed bug where Postgresql JSON/JSONB types rendered on SQLAlchemy
+      1.1 would render the "astext_type" argument which defaults to
+      the ``Text()`` type without the module prefix, similarly to the
+      issue with ARRAY fixed in :ticket:`85`.
+
     .. change:: 85
       :tags: bug, postgresql
       :tickets: 85
index 1666e5033288c4d37ab3b24fffd6b0acf8c0f123..e8608b74b48550fc5da2afd8e0fe6bdcb9748bf1 100644 (file)
@@ -30,6 +30,10 @@ from sqlalchemy import Boolean
 from sqlalchemy.sql import false
 
 
+if util.sqla_09:
+    from sqlalchemy.dialects.postgresql import JSON, JSONB
+
+
 class PostgresqlOpTest(TestBase):
 
     def test_rename_table_postgresql(self):
@@ -732,3 +736,33 @@ unique=False, """
             "where=sa.text(!U'x != 2'), using='gist', name='t_excl_x')"
             ")"
         )
+
+    @config.requirements.sqlalchemy_09
+    def test_json_type(self):
+        if config.requirements.sqlalchemy_110.enabled:
+            eq_ignore_whitespace(
+                autogenerate.render._repr_type(
+                    JSON(), self.autogen_context),
+                "postgresql.JSON(astext_type=sa.Text())"
+            )
+        else:
+            eq_ignore_whitespace(
+                autogenerate.render._repr_type(
+                    JSON(), self.autogen_context),
+                "postgresql.JSON()"
+            )
+
+    @config.requirements.sqlalchemy_09
+    def test_jsonb_type(self):
+        if config.requirements.sqlalchemy_110.enabled:
+            eq_ignore_whitespace(
+                autogenerate.render._repr_type(
+                    JSONB(), self.autogen_context),
+                "postgresql.JSONB(astext_type=sa.Text())"
+            )
+        else:
+            eq_ignore_whitespace(
+                autogenerate.render._repr_type(
+                    JSONB(), self.autogen_context),
+                "postgresql.JSONB()"
+            )