Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
sarus-flask-auth / sarus_flask_auth / dialects / MSJDBCDialect.py
Size: Mime:
""" Copyright (C) Sarus Technologies SAS - All Rights Reserved
Unauthorized copying of this file, via any medium is strictly prohibited
Proprietary and confidential
Write to contact@sarus.tech for more information about purchasing a licence
"""
import datetime

from sqlalchemy import exc
from sqlalchemy.dialects.mssql.base import MSDialect
from sqlalchemy.sql import text
from sqlalchemy_jdbcapi.base import BaseDialect

from sarus_flask_auth.dialects import JARS_LIST

MS_2012_VERSION = (11,)


class MSJDBCDialect(BaseDialect, MSDialect):  # pragma: no cover
    jdbc_db_name = "sqlserver"
    jdbc_driver_name = "com.microsoft.sqlserver.jdbc.SQLServerDriver"
    supports_statement_cache = True

    def initialize(self, connection):
        super(MSDialect, self).initialize(connection)
        self._setup_version_attributes()
        self._setup_supports_nvarchar_max(connection)

    def create_connect_args(self, url):
        if url is None:
            return

        # JDBC driver expects the connection_string like this:
        # "jdbc:sqlserver://{server}:{port};database={db};
        # user=...;password=...;..."
        # here we translate the the connection string to the driver style
        # string
        # "synapse_jdbc" -> "jdbc:sqlserver"
        s: str = str(url)
        # get jdbc url
        jdbc_url: str = s.split("//", 1)[-1]
        if not jdbc_url.startswith("jdbc"):
            jdbc_url = f"jdbc:{self.jdbc_db_name}://{jdbc_url}"
        kwargs = {
            "jclassname": self.jdbc_driver_name,
            "url": jdbc_url,
            # pass driver args via JVM System settings
            "jars": JARS_LIST,
        }
        return ((), kwargs)

    def _setup_version_attributes(self):
        self.server_version_info = MS_2012_VERSION
        self.supports_multivalues_insert = True
        if self.deprecate_large_types is None:
            self.deprecate_large_types = True
        self._supports_offset_fetch = True

    def _setup_supports_nvarchar_max(self, connection):
        try:
            connection.scalar(
                text("SELECT CAST('test max support' AS NVARCHAR(max))")
            )
        except exc.DBAPIError:
            self._supports_nvarchar_max = False
        else:
            self._supports_nvarchar_max = True

    def on_connect(self):
        """
        We change jaydebeapi driver data types
        see https://github.com/baztian/jaydebeapi
        """

        def _to_datetime(rs, col):
            """
            Force to return timestamps as datetime.datetime,
            not strings
            """
            java_val = rs.getTimestamp(col)
            if not java_val:
                return
            datetype_value = datetime.datetime.strptime(
                str(java_val)[:19], "%Y-%m-%d %H:%M:%S"
            )
            datetype_value.replace(
                microsecond=int(str(java_val.getNanos())[:6])
            )
            return datetype_value

        # replace dbapi type converters with the local ones
        # see
        # http://download.oracle.com/javase/8/docs/api/java/sql/Types.html
        # for possible keys
        self.dbapi._DEFAULT_CONVERTERS.update(
            {
                "TIMESTAMP": _to_datetime,
            }
        )

        return