Coverage for python/felis/db/sqltypes.py: 63%
67 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-28 10:01 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-28 10:01 +0000
1# This file is part of felis.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <https://www.gnu.org/licenses/>.
22import builtins
23from collections.abc import Mapping
24from typing import Any, Union
26from sqlalchemy import Float, SmallInteger, types
27from sqlalchemy.dialects import mysql, oracle, postgresql
28from sqlalchemy.ext.compiler import compiles
30MYSQL = "mysql"
31ORACLE = "oracle"
32POSTGRES = "postgresql"
33SQLITE = "sqlite"
36class TINYINT(SmallInteger):
37 """The non-standard TINYINT type."""
39 __visit_name__ = "TINYINT"
42class DOUBLE(Float):
43 """The non-standard DOUBLE type."""
45 __visit_name__ = "DOUBLE"
48@compiles(TINYINT)
49def compile_tinyint(type_: Any, compiler: Any, **kw: Any) -> str:
50 return "TINYINT"
53@compiles(DOUBLE)
54def compile_double(type_: Any, compiler: Any, **kw: Any) -> str:
55 return "DOUBLE"
58_TypeMap = Mapping[str, Union[types.TypeEngine, type[types.TypeEngine]]]
60boolean_map: _TypeMap = {MYSQL: mysql.BIT(1), ORACLE: oracle.NUMBER(1), POSTGRES: postgresql.BOOLEAN()}
62byte_map: _TypeMap = {
63 MYSQL: mysql.TINYINT(),
64 ORACLE: oracle.NUMBER(3),
65 POSTGRES: postgresql.SMALLINT(),
66}
68short_map: _TypeMap = {
69 MYSQL: mysql.SMALLINT(),
70 ORACLE: oracle.NUMBER(5),
71 POSTGRES: postgresql.SMALLINT(),
72}
74# Skip Oracle
75int_map: _TypeMap = {
76 MYSQL: mysql.INTEGER(),
77 POSTGRES: postgresql.INTEGER(),
78}
80long_map: _TypeMap = {
81 MYSQL: mysql.BIGINT(),
82 ORACLE: oracle.NUMBER(38, 0),
83 POSTGRES: postgresql.BIGINT(),
84}
86float_map: _TypeMap = {
87 MYSQL: mysql.FLOAT(),
88 ORACLE: oracle.BINARY_FLOAT(),
89 POSTGRES: postgresql.FLOAT(),
90}
92double_map: _TypeMap = {
93 MYSQL: mysql.DOUBLE(),
94 ORACLE: oracle.BINARY_DOUBLE(),
95 POSTGRES: postgresql.DOUBLE_PRECISION(),
96}
98char_map: _TypeMap = {
99 MYSQL: mysql.CHAR,
100 ORACLE: oracle.CHAR,
101 POSTGRES: postgresql.CHAR,
102}
104string_map: _TypeMap = {
105 MYSQL: mysql.VARCHAR,
106 ORACLE: oracle.VARCHAR2,
107 POSTGRES: postgresql.VARCHAR,
108}
110unicode_map: _TypeMap = {
111 MYSQL: mysql.NVARCHAR,
112 ORACLE: oracle.NVARCHAR2,
113 POSTGRES: postgresql.VARCHAR,
114}
116text_map: _TypeMap = {
117 MYSQL: mysql.LONGTEXT,
118 ORACLE: oracle.CLOB,
119 POSTGRES: postgresql.TEXT,
120}
122binary_map: _TypeMap = {
123 MYSQL: mysql.LONGBLOB,
124 ORACLE: oracle.BLOB,
125 POSTGRES: postgresql.BYTEA,
126}
129def boolean(**kwargs: Any) -> types.TypeEngine:
130 return _vary(types.BOOLEAN(), boolean_map, kwargs)
133def byte(**kwargs: Any) -> types.TypeEngine:
134 return _vary(TINYINT(), byte_map, kwargs)
137def short(**kwargs: Any) -> types.TypeEngine:
138 return _vary(types.SMALLINT(), short_map, kwargs)
141def int(**kwargs: Any) -> types.TypeEngine:
142 return _vary(types.INTEGER(), int_map, kwargs)
145def long(**kwargs: Any) -> types.TypeEngine:
146 return _vary(types.BIGINT(), long_map, kwargs)
149def float(**kwargs: Any) -> types.TypeEngine:
150 return _vary(types.FLOAT(), float_map, kwargs)
153def double(**kwargs: Any) -> types.TypeEngine:
154 return _vary(DOUBLE(), double_map, kwargs)
157def char(length: builtins.int, **kwargs: Any) -> types.TypeEngine:
158 return _vary(types.CHAR(length), char_map, kwargs, length)
161def string(length: builtins.int, **kwargs: Any) -> types.TypeEngine:
162 return _vary(types.VARCHAR(length), string_map, kwargs, length)
165def unicode(length: builtins.int, **kwargs: Any) -> types.TypeEngine:
166 return _vary(types.NVARCHAR(length), unicode_map, kwargs, length)
169def text(length: builtins.int, **kwargs: Any) -> types.TypeEngine:
170 return _vary(types.CLOB(length), text_map, kwargs, length)
173def binary(length: builtins.int, **kwargs: Any) -> types.TypeEngine:
174 return _vary(types.BLOB(length), binary_map, kwargs, length)
177def timestamp(**kwargs: Any) -> types.TypeEngine:
178 return types.TIMESTAMP()
181def _vary(
182 type_: types.TypeEngine,
183 variant_map: _TypeMap,
184 overrides: _TypeMap,
185 *args: Any,
186) -> types.TypeEngine:
187 variants: dict[str, Union[types.TypeEngine, type[types.TypeEngine]]] = dict(variant_map)
188 variants.update(overrides)
189 for dialect, variant in variants.items():
190 # If this is a class and not an instance, instantiate
191 if isinstance(variant, type):
192 variant = variant(*args)
193 type_ = type_.with_variant(variant, dialect)
194 return type_