2525**Functions to work with SQLAlchemy schemas (schemata) directly, via SQLAlchemy
2626Core.**
2727
28+ Functions that have to work with specific dialect information are marked
29+ DIALECT-AWARE.
30+
2831"""
2932
3033import ast
6063)
6164from sqlalchemy .sql import sqltypes , text
6265from sqlalchemy .sql .ddl import DDLElement
63- from sqlalchemy .sql .sqltypes import BigInteger , TypeEngine
66+ from sqlalchemy .sql .sqltypes import (
67+ BigInteger ,
68+ Boolean ,
69+ Date ,
70+ DateTime ,
71+ Double ,
72+ Float ,
73+ Integer ,
74+ Numeric ,
75+ SmallInteger ,
76+ Text ,
77+ TypeEngine ,
78+ )
6479from sqlalchemy .sql .visitors import Visitable
6580
6681from cardinal_pythonlib .logs import get_brace_style_log_with_null_handler
86101MSSQL_DEFAULT_SCHEMA = "dbo"
87102POSTGRES_DEFAULT_SCHEMA = "public"
88103
104+ DATABRICKS_SQLCOLTYPE_TO_SQLALCHEMY_GENERIC = {
105+ # A bit nasty: https://github.com/databricks/databricks-sqlalchemy
106+ # Part of the reverse mapping is via
107+ # from databricks.sqlalchemy import DatabricksDialect
108+ # print(DatabricksDialect.colspecs)
109+ "BIGINT" : BigInteger ,
110+ "BOOLEAN" : Boolean ,
111+ "DATE" : Date ,
112+ "TIMESTAMP_NTZ" : DateTime ,
113+ "DOUBLE" : Double ,
114+ "FLOAT" : Float ,
115+ "INT" : Integer ,
116+ "DECIMAL" : Numeric ,
117+ "SMALLINT" : SmallInteger ,
118+ "STRING" : Text ,
119+ }
120+
89121
90122# =============================================================================
91123# Inspect tables (SQLAlchemy Core)
@@ -498,6 +530,8 @@ def add_index(
498530
499531 The table name is worked out from the :class:`Column` object.
500532
533+ DIALECT-AWARE.
534+
501535 Args:
502536 engine: SQLAlchemy :class:`Engine` object
503537 sqla_column: single column to index
@@ -733,6 +767,8 @@ def giant_text_sqltype(dialect: Dialect) -> str:
733767 Returns the SQL column type used to make very large text columns for a
734768 given dialect.
735769
770+ DIALECT-AWARE.
771+
736772 Args:
737773 dialect: a SQLAlchemy :class:`Dialect`
738774 Returns:
@@ -755,6 +791,9 @@ def giant_text_sqltype(dialect: Dialect) -> str:
755791 elif dname == SqlaDialectName .SQLITE :
756792 return "TEXT"
757793 # https://www.sqlite.org/datatype3.html
794+ elif dname == SqlaDialectName .DATABRICKS :
795+ return "STRING"
796+ # https://github.com/databricks/databricks-sqlalchemy
758797 else :
759798 raise ValueError (f"Unknown dialect: { dname } " )
760799
@@ -787,16 +826,40 @@ def _get_sqla_coltype_class_from_str(
787826 Returns the SQLAlchemy class corresponding to a particular SQL column
788827 type in a given dialect.
789828
829+ DIALECT-AWARE.
830+
790831 Performs an upper- and lower-case search.
791832 For example, the SQLite dialect uses upper case, and the
792833 MySQL dialect uses lower case.
834+
835+ For exploratory thinking, see
836+ dev_notes/convert_sql_string_coltype_to_sqlalchemy_type.py.
837+
838+ DISCUSSION AT: https://github.com/sqlalchemy/sqlalchemy/discussions/12230
793839 """
794- # noinspection PyUnresolvedReferences
795- ischema_names = dialect .ischema_names
796- try :
797- return ischema_names [coltype .upper ()]
798- except KeyError :
799- return ischema_names [coltype .lower ()]
840+ if hasattr (dialect , "ischema_names" ):
841+ # The built-in dialects all have this, even though it's an internal
842+ # detail.
843+ ischema_names = dialect .ischema_names
844+ try :
845+ return ischema_names [coltype .upper ()]
846+ except KeyError :
847+ return ischema_names [coltype .lower ()]
848+ elif dialect .name == SqlaDialectName .DATABRICKS :
849+ # Ugly hack.
850+ # Databricks is an example that doesn't have ischema_names.
851+ try :
852+ return DATABRICKS_SQLCOLTYPE_TO_SQLALCHEMY_GENERIC [coltype .upper ()]
853+ except KeyError :
854+ raise ValueError (
855+ f"Don't know how to convert SQL column type { coltype !r} "
856+ f"to SQLAlchemy dialect { dialect !r} "
857+ )
858+ else :
859+ raise ValueError (
860+ f"Don't know a generic way to convert SQL column types "
861+ f"(in text format) to SQLAlchemy dialect { dialect .name !r} . "
862+ )
800863
801864
802865def get_list_of_sql_string_literals_from_quoted_csv (x : str ) -> List [str ]:
@@ -830,6 +893,8 @@ def get_sqla_coltype_from_dialect_str(
830893 ``coltype.compile()`` or ``coltype.compile(dialect)``; see
831894 :class:`TypeEngine`.
832895
896+ DIALECT-AWARE.
897+
833898 Args:
834899 dialect: a SQLAlchemy :class:`Dialect` class
835900
@@ -999,6 +1064,8 @@ def convert_sqla_type_for_dialect(
9991064 """
10001065 Converts an SQLAlchemy column type from one SQL dialect to another.
10011066
1067+ DIALECT-AWARE.
1068+
10021069 Args:
10031070 coltype: SQLAlchemy column type in the source dialect
10041071
@@ -1024,9 +1091,7 @@ def convert_sqla_type_for_dialect(
10241091 """
10251092 assert coltype is not None
10261093
1027- # noinspection PyUnresolvedReferences
10281094 to_mysql = dialect .name == SqlaDialectName .MYSQL
1029- # noinspection PyUnresolvedReferences
10301095 to_mssql = dialect .name == SqlaDialectName .MSSQL
10311096 typeclass = type (coltype )
10321097
@@ -1201,10 +1266,10 @@ def does_sqlatype_require_index_len(
12011266
12021267
12031268# =============================================================================
1204- # hack_in_mssql_xml_type:
1269+ # hack_in_mssql_xml_type
1270+ # =============================================================================
12051271#
12061272# Removed, as mssql.base.ischema_names["xml"] is now defined.
1207- # =============================================================================
12081273
12091274
12101275# =============================================================================
0 commit comments