Skip to content

Commit e6837c0

Browse files
committed
Types: Improve type mappings
- Consequently use upper-case type definitions from `sqlalchemy.types` - Add `timestamp without time zone` types (scalar and array) - On SQLAlchemy 2, map `real` and `double{_precision}` types to the newly introduced `sqltypes.{DOUBLE,DOUBLE_PRECISION}` types All of this is intended to improve reverse type lookups / reflections.
1 parent 435ec4e commit e6837c0

File tree

3 files changed

+52
-33
lines changed

3 files changed

+52
-33
lines changed

docs/inspection-reflection.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,10 @@ Create a SQLAlchemy table object:
8787
Reflect column data types from the table metadata:
8888

8989
>>> table.columns.get('name')
90-
Column('name', String(), table=<characters>)
90+
Column('name', VARCHAR(), table=<characters>)
9191

9292
>>> table.primary_key
93-
PrimaryKeyConstraint(Column('id', String(), table=<characters>, primary_key=True...
93+
PrimaryKeyConstraint(Column('id', VARCHAR(), table=<characters>, primary_key=True...
9494

9595

9696
CrateDialect

src/sqlalchemy_cratedb/dialect.py

+40-27
Original file line numberDiff line numberDiff line change
@@ -35,45 +35,58 @@
3535
from .sa_version import SA_1_4, SA_2_0, SA_VERSION
3636
from .type import FloatVector, ObjectArray, ObjectType
3737

38+
# For SQLAlchemy >= 1.1.
3839
TYPES_MAP = {
39-
"boolean": sqltypes.Boolean,
40-
"short": sqltypes.SmallInteger,
41-
"smallint": sqltypes.SmallInteger,
42-
"timestamp": sqltypes.TIMESTAMP(timezone=False),
43-
"timestamp with time zone": sqltypes.TIMESTAMP(timezone=True),
40+
"boolean": sqltypes.BOOLEAN,
41+
"short": sqltypes.SMALLINT,
42+
"smallint": sqltypes.SMALLINT,
43+
"timestamp": sqltypes.TIMESTAMP,
44+
"timestamp with time zone": sqltypes.TIMESTAMP(timezone=False),
45+
"timestamp without time zone": sqltypes.TIMESTAMP(timezone=True),
4446
"object": ObjectType,
45-
"integer": sqltypes.Integer,
46-
"long": sqltypes.NUMERIC,
47-
"bigint": sqltypes.NUMERIC,
47+
"object_array": ObjectArray, # TODO: Can this also be improved to use `sqltypes.ARRAY`?
48+
"integer": sqltypes.INTEGER,
49+
"long": sqltypes.BIGINT,
50+
"bigint": sqltypes.BIGINT,
51+
"float": sqltypes.FLOAT,
4852
"double": sqltypes.DECIMAL,
4953
"double precision": sqltypes.DECIMAL,
50-
"object_array": ObjectArray,
51-
"float": sqltypes.Float,
52-
"real": sqltypes.Float,
53-
"string": sqltypes.String,
54-
"text": sqltypes.String,
54+
"real": sqltypes.REAL,
55+
"string": sqltypes.VARCHAR,
56+
"text": sqltypes.VARCHAR,
5557
"float_vector": FloatVector,
5658
}
5759

58-
# Needed for SQLAlchemy >= 1.1.
59-
# TODO: Dissolve.
60+
# For SQLAlchemy >= 1.4.
6061
try:
6162
from sqlalchemy.types import ARRAY
6263

63-
TYPES_MAP["integer_array"] = ARRAY(sqltypes.Integer)
64-
TYPES_MAP["boolean_array"] = ARRAY(sqltypes.Boolean)
65-
TYPES_MAP["short_array"] = ARRAY(sqltypes.SmallInteger)
66-
TYPES_MAP["smallint_array"] = ARRAY(sqltypes.SmallInteger)
64+
TYPES_MAP["integer_array"] = ARRAY(sqltypes.INTEGER)
65+
TYPES_MAP["boolean_array"] = ARRAY(sqltypes.BOOLEAN)
66+
TYPES_MAP["short_array"] = ARRAY(sqltypes.SMALLINT)
67+
TYPES_MAP["smallint_array"] = ARRAY(sqltypes.SMALLINT)
68+
TYPES_MAP["timestamp_array"] = ARRAY(sqltypes.TIMESTAMP)
6769
TYPES_MAP["timestamp_array"] = ARRAY(sqltypes.TIMESTAMP(timezone=False))
6870
TYPES_MAP["timestamp with time zone_array"] = ARRAY(sqltypes.TIMESTAMP(timezone=True))
69-
TYPES_MAP["long_array"] = ARRAY(sqltypes.NUMERIC)
70-
TYPES_MAP["bigint_array"] = ARRAY(sqltypes.NUMERIC)
71-
TYPES_MAP["double_array"] = ARRAY(sqltypes.DECIMAL)
72-
TYPES_MAP["double precision_array"] = ARRAY(sqltypes.DECIMAL)
73-
TYPES_MAP["float_array"] = ARRAY(sqltypes.Float)
74-
TYPES_MAP["real_array"] = ARRAY(sqltypes.Float)
75-
TYPES_MAP["string_array"] = ARRAY(sqltypes.String)
76-
TYPES_MAP["text_array"] = ARRAY(sqltypes.String)
71+
TYPES_MAP["long_array"] = ARRAY(sqltypes.BIGINT)
72+
TYPES_MAP["bigint_array"] = ARRAY(sqltypes.BIGINT)
73+
TYPES_MAP["float_array"] = ARRAY(sqltypes.FLOAT)
74+
TYPES_MAP["real_array"] = ARRAY(sqltypes.REAL)
75+
TYPES_MAP["string_array"] = ARRAY(sqltypes.VARCHAR)
76+
TYPES_MAP["text_array"] = ARRAY(sqltypes.VARCHAR)
77+
except Exception: # noqa: S110
78+
pass
79+
80+
# For SQLAlchemy >= 2.0.
81+
try:
82+
from sqlalchemy.types import DOUBLE, DOUBLE_PRECISION
83+
84+
TYPES_MAP["real"] = DOUBLE
85+
TYPES_MAP["real_array"] = ARRAY(DOUBLE)
86+
TYPES_MAP["double"] = DOUBLE
87+
TYPES_MAP["double_array"] = ARRAY(DOUBLE)
88+
TYPES_MAP["double precision"] = DOUBLE_PRECISION
89+
TYPES_MAP["double precision_array"] = ARRAY(DOUBLE_PRECISION)
7790
except Exception: # noqa: S110
7891
pass
7992

tests/integration.py

+10-4
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
from crate.client import connect
3232

33-
from sqlalchemy_cratedb.sa_version import SA_2_0, SA_VERSION
33+
from sqlalchemy_cratedb.sa_version import SA_1_4, SA_2_0, SA_VERSION
3434
from tests.settings import crate_host
3535

3636
log = logging.getLogger()
@@ -179,16 +179,22 @@ def create_test_suite():
179179
"docs/crud.rst",
180180
"docs/working-with-types.rst",
181181
"docs/advanced-querying.rst",
182-
"docs/inspection-reflection.rst",
183182
]
184183

185-
# Don't run DataFrame integration tests on SQLAlchemy 1.3 and Python 3.7.
186-
skip_dataframe = SA_VERSION < SA_2_0 or sys.version_info < (3, 8) or sys.version_info >= (3, 13)
184+
# Don't run DataFrame integration tests on SQLAlchemy 1.4 and earlier, or Python 3.7.
185+
skip_dataframe = SA_VERSION < SA_2_0 or sys.version_info < (3, 8)
187186
if not skip_dataframe:
188187
sqlalchemy_integration_tests += [
189188
"docs/dataframe.rst",
190189
]
191190

191+
# Don't run reflection integration tests on SQLAlchemy 1.3 and earlier and Python 3.10 and 3.11.
192+
skip_reflection = SA_VERSION < SA_1_4 and (3, 10) <= sys.version_info < (3, 12)
193+
if not skip_reflection:
194+
sqlalchemy_integration_tests += [
195+
"docs/inspection-reflection.rst",
196+
]
197+
192198
s = doctest.DocFileSuite(
193199
*sqlalchemy_integration_tests,
194200
module_relative=False,

0 commit comments

Comments
 (0)