Coverage for python/felis/db/sqltypes.py: 61%

66 statements  

« prev     ^ index     » next       coverage.py v7.2.1, created at 2023-03-12 20:29 -0700

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/>. 

21 

22import builtins 

23from collections.abc import Mapping, MutableMapping 

24from typing import Any 

25 

26from sqlalchemy import Float, SmallInteger, types 

27from sqlalchemy.dialects import mysql, oracle, postgresql 

28from sqlalchemy.ext.compiler import compiles 

29 

30MYSQL = "mysql" 

31ORACLE = "oracle" 

32POSTGRES = "postgresql" 

33SQLITE = "sqlite" 

34 

35 

36class TINYINT(SmallInteger): 

37 """The non-standard TINYINT type.""" 

38 

39 __visit_name__ = "TINYINT" 

40 

41 

42class DOUBLE(Float): 

43 """The non-standard DOUBLE type.""" 

44 

45 __visit_name__ = "DOUBLE" 

46 

47 

48@compiles(TINYINT) 

49def compile_tinyint(type_: Any, compiler: Any, **kw: Any) -> str: 

50 return "TINYINT" 

51 

52 

53@compiles(DOUBLE) 

54def compile_double(type_: Any, compiler: Any, **kw: Any) -> str: 

55 return "DOUBLE" 

56 

57 

58boolean_map = {MYSQL: mysql.BIT(1), ORACLE: oracle.NUMBER(1), POSTGRES: postgresql.BOOLEAN()} 

59 

60byte_map = { 

61 MYSQL: mysql.TINYINT(), 

62 ORACLE: oracle.NUMBER(3), 

63 POSTGRES: postgresql.SMALLINT(), 

64} 

65 

66short_map = { 

67 MYSQL: mysql.SMALLINT(), 

68 ORACLE: oracle.NUMBER(5), 

69 POSTGRES: postgresql.SMALLINT(), 

70} 

71 

72# Skip Oracle 

73int_map = { 

74 MYSQL: mysql.INTEGER(), 

75 POSTGRES: postgresql.INTEGER(), 

76} 

77 

78long_map = { 

79 MYSQL: mysql.BIGINT(), 

80 ORACLE: oracle.NUMBER(38, 0), 

81 POSTGRES: postgresql.BIGINT(), 

82} 

83 

84float_map = { 

85 MYSQL: mysql.FLOAT(), 

86 ORACLE: oracle.BINARY_FLOAT(), 

87 POSTGRES: postgresql.FLOAT(), 

88} 

89 

90double_map = { 

91 MYSQL: mysql.DOUBLE(), 

92 ORACLE: oracle.BINARY_DOUBLE(), 

93 POSTGRES: postgresql.DOUBLE_PRECISION(), 

94} 

95 

96char_map = { 

97 MYSQL: mysql.CHAR, 

98 ORACLE: oracle.CHAR, 

99 POSTGRES: postgresql.CHAR, 

100} 

101 

102string_map = { 

103 MYSQL: mysql.VARCHAR, 

104 ORACLE: oracle.VARCHAR2, 

105 POSTGRES: postgresql.VARCHAR, 

106} 

107 

108unicode_map = { 

109 MYSQL: mysql.NVARCHAR, 

110 ORACLE: oracle.NVARCHAR2, 

111 POSTGRES: postgresql.VARCHAR, 

112} 

113 

114text_map = { 

115 MYSQL: mysql.LONGTEXT, 

116 ORACLE: oracle.CLOB, 

117 POSTGRES: postgresql.TEXT, 

118} 

119 

120binary_map = { 

121 MYSQL: mysql.LONGBLOB, 

122 ORACLE: oracle.BLOB, 

123 POSTGRES: postgresql.BYTEA, 

124} 

125 

126 

127def boolean(**kwargs: Any) -> types.TypeEngine: 

128 return _vary(types.BOOLEAN(), boolean_map.copy(), kwargs) 

129 

130 

131def byte(**kwargs: Any) -> types.TypeEngine: 

132 return _vary(TINYINT(), byte_map.copy(), kwargs) 

133 

134 

135def short(**kwargs: Any) -> types.TypeEngine: 

136 return _vary(types.SMALLINT(), short_map.copy(), kwargs) 

137 

138 

139def int(**kwargs: Any) -> types.TypeEngine: 

140 return _vary(types.INTEGER(), int_map.copy(), kwargs) 

141 

142 

143def long(**kwargs: Any) -> types.TypeEngine: 

144 return _vary(types.BIGINT(), long_map.copy(), kwargs) 

145 

146 

147def float(**kwargs: Any) -> types.TypeEngine: 

148 return _vary(types.FLOAT(), float_map.copy(), kwargs) 

149 

150 

151def double(**kwargs: Any) -> types.TypeEngine: 

152 return _vary(DOUBLE(), double_map.copy(), kwargs) 

153 

154 

155def char(length: builtins.int, **kwargs: Any) -> types.TypeEngine: 

156 return _vary(types.CHAR(length), char_map.copy(), kwargs, length) 

157 

158 

159def string(length: builtins.int, **kwargs: Any) -> types.TypeEngine: 

160 return _vary(types.VARCHAR(length), string_map.copy(), kwargs, length) 

161 

162 

163def unicode(length: builtins.int, **kwargs: Any) -> types.TypeEngine: 

164 return _vary(types.NVARCHAR(length), unicode_map.copy(), kwargs, length) 

165 

166 

167def text(length: builtins.int, **kwargs: Any) -> types.TypeEngine: 

168 return _vary(types.CLOB(length), text_map.copy(), kwargs, length) 

169 

170 

171def binary(length: builtins.int, **kwargs: Any) -> types.TypeEngine: 

172 return _vary(types.BLOB(length), binary_map.copy(), kwargs, length) 

173 

174 

175def timestamp(**kwargs: Any) -> types.TypeEngine: 

176 return types.TIMESTAMP() 

177 

178 

179def _vary( 

180 type_: types.TypeEngine, 

181 variant_map: MutableMapping[str, types.TypeEngine], 

182 overrides: Mapping[str, types.TypeEngine], 

183 *args: Any, 

184) -> types.TypeEngine: 

185 for dialect, variant in overrides.items(): 

186 variant_map[dialect] = variant 

187 for dialect, variant in variant_map.items(): 

188 # If this is a class and not an instance, instantiate 

189 if isinstance(variant, type): 

190 variant = variant(*args) 

191 type_ = type_.with_variant(variant, dialect) 

192 return type_