]> git.ipfire.org Git - thirdparty/sqlalchemy/alembic.git/commitdiff
add type synonym for mysql.LONGTEXT / JSON
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 13 Nov 2021 15:27:30 +0000 (10:27 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 15 Nov 2021 02:32:08 +0000 (21:32 -0500)
Added a rule to the MySQL impl so that the translation between JSON /
LONGTEXT is accommodated by autogenerate, treating LONGTEXT from the server
as equivalent to an existing JSON in the model.

Change-Id: Ia8370d2269c4decea00aa94beafd3d9d861a1269
Fixes: #968
alembic/ddl/mysql.py
docs/build/unreleased/968.rst [new file with mode: 0644]
tests/requirements.py
tests/test_autogen_diffs.py

index 94895605d006bd8a6c2c259d06243679b4282739..c3d66bdf2ac6edc4029c5f79c46c40a4eb7b4495 100644 (file)
@@ -38,7 +38,10 @@ class MySQLImpl(DefaultImpl):
     __dialect__ = "mysql"
 
     transactional_ddl = False
-    type_synonyms = DefaultImpl.type_synonyms + ({"BOOL", "TINYINT"},)
+    type_synonyms = DefaultImpl.type_synonyms + (
+        {"BOOL", "TINYINT"},
+        {"JSON", "LONGTEXT"},
+    )
     type_arg_extract = [r"character set ([\w\-_]+)", r"collate ([\w\-_]+)"]
 
     def alter_column(  # type:ignore[override]
diff --git a/docs/build/unreleased/968.rst b/docs/build/unreleased/968.rst
new file mode 100644 (file)
index 0000000..be5440b
--- /dev/null
@@ -0,0 +1,7 @@
+.. change::
+    :tags: bug, mysql, autogenerate
+    :tickets: 968
+
+    Added a rule to the MySQL impl so that the translation between JSON /
+    LONGTEXT is accommodated by autogenerate, treating LONGTEXT from the server
+    as equivalent to an existing JSON in the model.
index 7770da9018208c090ee3df59f66b307bb2324578..258c730049a5832c9489afb89c6c88f5b191e95c 100644 (file)
@@ -1,3 +1,4 @@
+from sqlalchemy import exc as sqla_exc
 from sqlalchemy import text
 
 from alembic.testing import exclusions
@@ -300,6 +301,54 @@ class DefaultRequirements(SuiteRequirements):
         else:
             return False
 
+    @property
+    def json_type(self):
+        return exclusions.only_on(
+            [
+                lambda config: exclusions.against(config, "mysql")
+                and (
+                    (
+                        not config.db.dialect._is_mariadb
+                        and exclusions.against(config, "mysql >= 5.7")
+                    )
+                    or (
+                        config.db.dialect._mariadb_normalized_version_info
+                        >= (10, 2, 7)
+                    )
+                ),
+                "mariadb>=10.2.7",
+                "postgresql >= 9.3",
+                self._sqlite_json,
+                self._mssql_json,
+            ]
+        )
+
+    def _mssql_json(self, config):
+        if not sqla_compat.sqla_14:
+            return False
+        else:
+            return exclusions.against(config, "mssql")
+
+    def _sqlite_json(self, config):
+        if not sqla_compat.sqla_14:
+            return False
+        elif not exclusions.against(config, "sqlite >= 3.9"):
+            return False
+        else:
+            with config.db.connect() as conn:
+                try:
+                    return (
+                        conn.execute(
+                            text(
+                                """select json_extract('{"foo": "bar"}', """
+                                """'$."foo"')"""
+                            )
+                        ).scalar()
+                        == "bar"
+                    )
+                except sqla_exc.DBAPIError:
+                    return False
+
     @property
     def identity_columns(self):
         # TODO: in theory if these could come from SQLAlchemy dialects
index f790be54caedc35f72208605533c7ac36f81e08e..8657aebef5e18e18af1184fa444bd63543fe62a5 100644 (file)
@@ -15,6 +15,7 @@ from sqlalchemy import Index
 from sqlalchemy import inspect
 from sqlalchemy import INTEGER
 from sqlalchemy import Integer
+from sqlalchemy import JSON
 from sqlalchemy import LargeBinary
 from sqlalchemy import MetaData
 from sqlalchemy import Numeric
@@ -927,6 +928,8 @@ class CompareMetadataToInspectorTest(TestBase):
         (String(32),),
         (LargeBinary(),),
         (Unicode(32),),
+        (JSON(), config.requirements.json_type),
+        (mysql.LONGTEXT(), config.requirements.mysql),
         (Enum("one", "two", "three", name="the_enum"),),
     )
     def test_introspected_columns_match_metadata_columns(self, cola):
@@ -965,7 +968,7 @@ class CompareMetadataToInspectorTest(TestBase):
             mysql.VARCHAR(200, charset="latin1"),
             mysql.VARCHAR(200, charset="utf-8"),
             True,
-            config.requirements.mysql + config.requirements.sqlalchemy_13,
+            config.requirements.mysql,
         ),
         (
             String(255, collation="utf8_bin"),
@@ -977,7 +980,7 @@ class CompareMetadataToInspectorTest(TestBase):
             String(255, collation="utf8_bin"),
             String(255, collation="latin1_bin"),
             True,
-            config.requirements.mysql + config.requirements.sqlalchemy_13,
+            config.requirements.mysql,
         ),
     )
     def test_string_comparisons(self, cola, colb, expect_changes):