]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
fixup: try_cast v2
authorNick Crews <nicholas.b.crews@gmail.com>
Tue, 9 May 2023 18:51:42 +0000 (10:51 -0800)
committerNick Crews <nicholas.b.crews@gmail.com>
Tue, 9 May 2023 18:51:42 +0000 (10:51 -0800)
- update changelog entry
- don't deprecate accessing try_cast from mssql. Revert my test change
  to be consistent.
- re-export try_cast from the root place in mssql/__init__.py
- Move visit_try_cast() to base compiler

Still not sure exactly about where the test should live,
since it only should work for mssql, so I'm not sure how to
add it to the generic tests but
specify it to run only for mssql.

doc/build/changelog/unreleased_20/9752.rst
lib/sqlalchemy/dialects/mssql/__init__.py
lib/sqlalchemy/dialects/mssql/base.py
lib/sqlalchemy/sql/compiler.py
test/dialect/mssql/test_compiler.py

index 519c75f0702bd596499e39f9c16d507446e4501f..0c095fcedcda2f1bc340d3a35f5da300dd654bf2 100644 (file)
@@ -3,12 +3,12 @@
     :tickets: 9752
 
 
-    Added new :func:`.try_cast` factory function and corresponding
-    :class:`.TryCast` SQL Element, which implements a cast where
+    Generalized the MSSQL :func:`.try_cast` function to any dialect.
+    This implements a cast where
     un-castable values are returned as NULL, instead of raising an error.
+    Now this function can be taken advantage of by third party dialects
+    that also support this function, such as
 
-    This is currently implemented as ``TRY_CAST`` in Microsoft SQL Server.
-    and could be implemented in other backends:
-    * ``SAFE_CAST`` in Google BigQuery, and
-    * ``TRY_CAST`` in DuckDB.
-    * ``TRY_CAST`` in Snowflake.
+    * ``SAFE_CAST`` in Google BigQuery
+    * ``TRY_CAST`` in DuckDB
+    * ``TRY_CAST`` in Snowflake
index 3bbfad344cfce8d9ddbce1a77442e76e4c74a363..997896a5046225ecef63b2afd54fb4979bcb99ba 100644 (file)
@@ -6,7 +6,7 @@
 # the MIT License: https://www.opensource.org/licenses/mit-license.php
 # mypy: ignore-errors
 
-
+from ...sql._elements_constructors import try_cast
 from . import base  # noqa
 from . import pymssql  # noqa
 from . import pyodbc  # noqa
@@ -39,7 +39,6 @@ from .base import TEXT
 from .base import TIME
 from .base import TIMESTAMP
 from .base import TINYINT
-from .base import try_cast
 from .base import UNIQUEIDENTIFIER
 from .base import VARBINARY
 from .base import VARCHAR
index e37f92af33edeb5e7ec2bffac0d5e740ddbfe092..6c019d290796654d298a803dde36fb8deb4b19f9 100644 (file)
@@ -939,6 +939,7 @@ from ...sql import quoted_name
 from ...sql import roles
 from ...sql import sqltypes
 from ...sql import util as sql_util
+from ...sql._elements_constructors import try_cast
 from ...sql._typing import is_sql_compiler
 from ...sql.compiler import InsertmanyvaluesSentinelOpts
 from ...sql.elements import TryCast
@@ -1604,15 +1605,6 @@ class SQL_VARIANT(sqltypes.TypeEngine):
     __visit_name__ = "SQL_VARIANT"
 
 
-def try_cast(*arg, **kw):
-    util.warn_deprecated(
-        "`sqlalchemy.dialects.mssql.base.try_cast` is deprecated. "
-        "Use directly from sqlalchemy instead, i.e. `sa.try_cast(...)`",
-        "2.1",
-    )
-    return TryCast(*arg, **kw)
-
-
 # old names.
 MSDateTime = _MSDateTime
 MSDate = _MSDate
@@ -2153,12 +2145,6 @@ class MSSQLCompiler(compiler.SQLCompiler):
         else:
             return ""
 
-    def visit_try_cast(self, element, **kw):
-        return "TRY_CAST (%s AS %s)" % (
-            self.process(element.clause, **kw),
-            self.process(element.typeclause, **kw),
-        )
-
     def translate_select_structure(self, select_stmt, **kwargs):
         """Look for ``LIMIT`` and OFFSET in a select statement, and if
         so tries to wrap it in a subquery with ``row_number()`` criterion.
index 554a84112060884ba21bb73121d5fdd8437a33df..4299377044d0e8e1d38cfa0f9081c86684695ddb 100644 (file)
@@ -2777,6 +2777,12 @@ class SQLCompiler(Compiled):
             cast.typeclause._compiler_dispatch(self, **kwargs),
         )
 
+    def visit_try_cast(self, cast, **kwargs):
+        return "TRY_CAST(%s AS %s)" % (
+            cast.clause._compiler_dispatch(self, **kwargs),
+            cast.typeclause._compiler_dispatch(self, **kwargs),
+        )
+
     def _format_frame_clause(self, range_, **kw):
 
         return "%s AND %s" % (
index 3dbd436d3c40c920412cdc6633369cf03034e3be..b4b6862c24120acc3094543e72ea78d82d5c84b4 100644 (file)
@@ -26,7 +26,6 @@ from sqlalchemy import UniqueConstraint
 from sqlalchemy import update
 from sqlalchemy.dialects import mssql
 from sqlalchemy.dialects.mssql import base as mssql_base
-from sqlalchemy.dialects.mssql.base import try_cast
 from sqlalchemy.sql import column
 from sqlalchemy.sql import quoted_name
 from sqlalchemy.sql import table
@@ -1478,15 +1477,10 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL):
         metadata = MetaData()
         t1 = Table("t1", metadata, Column("id", Integer, primary_key=True))
 
-        def call(func):
-            self.assert_compile(
-                select(func(t1.c.id, Integer)),
-                "SELECT TRY_CAST (t1.id AS INTEGER) AS id FROM t1",
-            )
-
-        with testing.expect_deprecated(".*try_cast.*"):
-            call(mssql_base.try_cast)
-        call(try_cast)
+        self.assert_compile(
+            select(try_cast(t1.c.id, Integer)),
+            "SELECT TRY_CAST (t1.id AS INTEGER) AS id FROM t1",
+        )
 
     @testing.combinations(
         ("no_persisted", "", "ignore"),