Skip to content

Commit a63ce6e

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 6db4702 commit a63ce6e

File tree

3 files changed

+49
-30
lines changed

3 files changed

+49
-30
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

+38-25
Original file line numberDiff line numberDiff line change
@@ -36,41 +36,54 @@
3636
from .type import FloatVector, ObjectArray, ObjectType
3737

3838
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),
39+
"boolean": sqltypes.BOOLEAN,
40+
"short": sqltypes.SMALLINT,
41+
"smallint": sqltypes.SMALLINT,
42+
"timestamp": sqltypes.TIMESTAMP,
43+
"timestamp with time zone": sqltypes.TIMESTAMP(timezone=False),
44+
"timestamp without time zone": sqltypes.TIMESTAMP(timezone=True),
4445
"object": ObjectType,
45-
"integer": sqltypes.Integer,
46-
"long": sqltypes.NUMERIC,
47-
"bigint": sqltypes.NUMERIC,
46+
"object_array": ObjectArray, # TODO: Can this also be improved to use `sqltypes.ARRAY`?
47+
"integer": sqltypes.INTEGER,
48+
"long": sqltypes.BIGINT,
49+
"bigint": sqltypes.BIGINT,
50+
"float": sqltypes.FLOAT,
4851
"double": sqltypes.DECIMAL,
4952
"double precision": sqltypes.DECIMAL,
50-
"object_array": ObjectArray,
51-
"float": sqltypes.Float,
52-
"real": sqltypes.Float,
53-
"string": sqltypes.String,
54-
"text": sqltypes.String,
53+
"real": sqltypes.REAL,
54+
"string": sqltypes.VARCHAR,
55+
"text": sqltypes.VARCHAR,
5556
"float_vector": FloatVector,
5657
}
58+
5759
try:
5860
# SQLAlchemy >= 1.1
5961
from sqlalchemy.types import ARRAY
60-
TYPES_MAP["integer_array"] = ARRAY(sqltypes.Integer)
61-
TYPES_MAP["boolean_array"] = ARRAY(sqltypes.Boolean)
62-
TYPES_MAP["short_array"] = ARRAY(sqltypes.SmallInteger)
63-
TYPES_MAP["smallint_array"] = ARRAY(sqltypes.SmallInteger)
62+
TYPES_MAP["integer_array"] = ARRAY(sqltypes.INTEGER)
63+
TYPES_MAP["boolean_array"] = ARRAY(sqltypes.BOOLEAN)
64+
TYPES_MAP["short_array"] = ARRAY(sqltypes.SMALLINT)
65+
TYPES_MAP["smallint_array"] = ARRAY(sqltypes.SMALLINT)
66+
TYPES_MAP["timestamp_array"] = ARRAY(sqltypes.TIMESTAMP)
6467
TYPES_MAP["timestamp_array"] = ARRAY(sqltypes.TIMESTAMP(timezone=False))
6568
TYPES_MAP["timestamp with time zone_array"] = ARRAY(sqltypes.TIMESTAMP(timezone=True))
66-
TYPES_MAP["long_array"] = ARRAY(sqltypes.NUMERIC)
67-
TYPES_MAP["bigint_array"] = ARRAY(sqltypes.NUMERIC)
68-
TYPES_MAP["double_array"] = ARRAY(sqltypes.DECIMAL)
69-
TYPES_MAP["double precision_array"] = ARRAY(sqltypes.DECIMAL)
70-
TYPES_MAP["float_array"] = ARRAY(sqltypes.Float)
71-
TYPES_MAP["real_array"] = ARRAY(sqltypes.Float)
72-
TYPES_MAP["string_array"] = ARRAY(sqltypes.String)
73-
TYPES_MAP["text_array"] = ARRAY(sqltypes.String)
69+
TYPES_MAP["long_array"] = ARRAY(sqltypes.BIGINT)
70+
TYPES_MAP["bigint_array"] = ARRAY(sqltypes.BIGINT)
71+
TYPES_MAP["float_array"] = ARRAY(sqltypes.FLOAT)
72+
TYPES_MAP["real_array"] = ARRAY(sqltypes.REAL)
73+
TYPES_MAP["string_array"] = ARRAY(sqltypes.VARCHAR)
74+
TYPES_MAP["text_array"] = ARRAY(sqltypes.VARCHAR)
75+
except Exception:
76+
pass
77+
78+
try:
79+
# SQLAlchemy >= 2.0
80+
from sqlalchemy.types import DOUBLE, DOUBLE_PRECISION
81+
TYPES_MAP["real"] = DOUBLE
82+
TYPES_MAP["real_array"] = ARRAY(DOUBLE)
83+
TYPES_MAP["double"] = DOUBLE
84+
TYPES_MAP["double_array"] = ARRAY(DOUBLE)
85+
TYPES_MAP["double precision"] = DOUBLE_PRECISION
86+
TYPES_MAP["double precision_array"] = ARRAY(DOUBLE_PRECISION)
7487
except Exception:
7588
pass
7689

tests/integration.py

+9-3
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
import logging
3030

3131
from crate.client import connect
32-
from sqlalchemy_cratedb import SA_VERSION, SA_2_0
32+
from sqlalchemy_cratedb import SA_VERSION, SA_2_0, SA_1_4
3333
from tests.settings import crate_host
3434

3535
log = logging.getLogger()
@@ -184,16 +184,22 @@ def create_test_suite():
184184
'docs/crud.rst',
185185
'docs/working-with-types.rst',
186186
'docs/advanced-querying.rst',
187-
'docs/inspection-reflection.rst',
188187
]
189188

190-
# Don't run DataFrame integration tests on SQLAlchemy 1.3 and Python 3.7.
189+
# Don't run DataFrame integration tests on SQLAlchemy 1.4 and earlier, or Python 3.7.
191190
skip_dataframe = SA_VERSION < SA_2_0 or sys.version_info < (3, 8)
192191
if not skip_dataframe:
193192
sqlalchemy_integration_tests += [
194193
'docs/dataframe.rst',
195194
]
196195

196+
# Don't run reflection integration tests on SQLAlchemy 1.3 and earlier and Python 3.10 and 3.11.
197+
skip_reflection = SA_VERSION < SA_1_4 and (3, 10) <= sys.version_info < (3, 12)
198+
if not skip_reflection:
199+
sqlalchemy_integration_tests += [
200+
'docs/inspection-reflection.rst',
201+
]
202+
197203
s = doctest.DocFileSuite(
198204
*sqlalchemy_integration_tests,
199205
module_relative=False,

0 commit comments

Comments
 (0)