Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/google/cloud/bigquery/standard_sql.py: 35%

162 statements  

« prev     ^ index     » next       coverage.py v7.2.2, created at 2023-03-26 06:07 +0000

1# Copyright 2021 Google LLC 

2 

3# Licensed under the Apache License, Version 2.0 (the "License"); 

4# you may not use this file except in compliance with the License. 

5# You may obtain a copy of the License at 

6 

7# https://www.apache.org/licenses/LICENSE-2.0 

8 

9# Unless required by applicable law or agreed to in writing, software 

10# distributed under the License is distributed on an "AS IS" BASIS, 

11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

12# See the License for the specific language governing permissions and 

13# limitations under the License. 

14 

15import copy 

16import typing 

17from typing import Any, Dict, Iterable, List, Optional 

18 

19from google.cloud.bigquery.enums import StandardSqlTypeNames 

20 

21 

22class StandardSqlDataType: 

23 """The type of a variable, e.g., a function argument. 

24 

25 See: 

26 https://cloud.google.com/bigquery/docs/reference/rest/v2/StandardSqlDataType 

27 

28 Examples: 

29 

30 .. code-block:: text 

31 

32 INT64: {type_kind="INT64"} 

33 ARRAY: {type_kind="ARRAY", array_element_type="STRING"} 

34 STRUCT<x STRING, y ARRAY>: { 

35 type_kind="STRUCT", 

36 struct_type={ 

37 fields=[ 

38 {name="x", type={type_kind="STRING"}}, 

39 { 

40 name="y", 

41 type={type_kind="ARRAY", array_element_type="DATE"} 

42 } 

43 ] 

44 } 

45 } 

46 

47 Args: 

48 type_kind: 

49 The top level type of this field. Can be any standard SQL data type, 

50 e.g. INT64, DATE, ARRAY. 

51 array_element_type: 

52 The type of the array's elements, if type_kind is ARRAY. 

53 struct_type: 

54 The fields of this struct, in order, if type_kind is STRUCT. 

55 """ 

56 

57 def __init__( 

58 self, 

59 type_kind: Optional[ 

60 StandardSqlTypeNames 

61 ] = StandardSqlTypeNames.TYPE_KIND_UNSPECIFIED, 

62 array_element_type: Optional["StandardSqlDataType"] = None, 

63 struct_type: Optional["StandardSqlStructType"] = None, 

64 ): 

65 self._properties: Dict[str, Any] = {} 

66 

67 self.type_kind = type_kind 

68 self.array_element_type = array_element_type 

69 self.struct_type = struct_type 

70 

71 @property 

72 def type_kind(self) -> Optional[StandardSqlTypeNames]: 

73 """The top level type of this field. 

74 

75 Can be any standard SQL data type, e.g. INT64, DATE, ARRAY. 

76 """ 

77 kind = self._properties["typeKind"] 

78 return StandardSqlTypeNames[kind] # pytype: disable=missing-parameter 

79 

80 @type_kind.setter 

81 def type_kind(self, value: Optional[StandardSqlTypeNames]): 

82 if not value: 

83 kind = StandardSqlTypeNames.TYPE_KIND_UNSPECIFIED.value 

84 else: 

85 kind = value.value 

86 self._properties["typeKind"] = kind 

87 

88 @property 

89 def array_element_type(self) -> Optional["StandardSqlDataType"]: 

90 """The type of the array's elements, if type_kind is ARRAY.""" 

91 element_type = self._properties.get("arrayElementType") 

92 

93 if element_type is None: 

94 return None 

95 

96 result = StandardSqlDataType() 

97 result._properties = element_type # We do not use a copy on purpose. 

98 return result 

99 

100 @array_element_type.setter 

101 def array_element_type(self, value: Optional["StandardSqlDataType"]): 

102 element_type = None if value is None else value.to_api_repr() 

103 

104 if element_type is None: 

105 self._properties.pop("arrayElementType", None) 

106 else: 

107 self._properties["arrayElementType"] = element_type 

108 

109 @property 

110 def struct_type(self) -> Optional["StandardSqlStructType"]: 

111 """The fields of this struct, in order, if type_kind is STRUCT.""" 

112 struct_info = self._properties.get("structType") 

113 

114 if struct_info is None: 

115 return None 

116 

117 result = StandardSqlStructType() 

118 result._properties = struct_info # We do not use a copy on purpose. 

119 return result 

120 

121 @struct_type.setter 

122 def struct_type(self, value: Optional["StandardSqlStructType"]): 

123 struct_type = None if value is None else value.to_api_repr() 

124 

125 if struct_type is None: 

126 self._properties.pop("structType", None) 

127 else: 

128 self._properties["structType"] = struct_type 

129 

130 def to_api_repr(self) -> Dict[str, Any]: 

131 """Construct the API resource representation of this SQL data type.""" 

132 return copy.deepcopy(self._properties) 

133 

134 @classmethod 

135 def from_api_repr(cls, resource: Dict[str, Any]): 

136 """Construct an SQL data type instance given its API representation.""" 

137 type_kind = resource.get("typeKind") 

138 if type_kind not in StandardSqlTypeNames.__members__: 

139 type_kind = StandardSqlTypeNames.TYPE_KIND_UNSPECIFIED 

140 else: 

141 # Convert string to an enum member. 

142 type_kind = StandardSqlTypeNames[ # pytype: disable=missing-parameter 

143 typing.cast(str, type_kind) 

144 ] 

145 

146 array_element_type = None 

147 if type_kind == StandardSqlTypeNames.ARRAY: 

148 element_type = resource.get("arrayElementType") 

149 if element_type: 

150 array_element_type = cls.from_api_repr(element_type) 

151 

152 struct_type = None 

153 if type_kind == StandardSqlTypeNames.STRUCT: 

154 struct_info = resource.get("structType") 

155 if struct_info: 

156 struct_type = StandardSqlStructType.from_api_repr(struct_info) 

157 

158 return cls(type_kind, array_element_type, struct_type) 

159 

160 def __eq__(self, other): 

161 if not isinstance(other, StandardSqlDataType): 

162 return NotImplemented 

163 else: 

164 return ( 

165 self.type_kind == other.type_kind 

166 and self.array_element_type == other.array_element_type 

167 and self.struct_type == other.struct_type 

168 ) 

169 

170 def __str__(self): 

171 result = f"{self.__class__.__name__}(type_kind={self.type_kind!r}, ...)" 

172 return result 

173 

174 

175class StandardSqlField: 

176 """A field or a column. 

177 

178 See: 

179 https://cloud.google.com/bigquery/docs/reference/rest/v2/StandardSqlField 

180 

181 Args: 

182 name: 

183 The name of this field. Can be absent for struct fields. 

184 type: 

185 The type of this parameter. Absent if not explicitly specified. 

186 

187 For example, CREATE FUNCTION statement can omit the return type; in this 

188 case the output parameter does not have this "type" field). 

189 """ 

190 

191 def __init__( 

192 self, name: Optional[str] = None, type: Optional[StandardSqlDataType] = None 

193 ): 

194 type_repr = None if type is None else type.to_api_repr() 

195 self._properties = {"name": name, "type": type_repr} 

196 

197 @property 

198 def name(self) -> Optional[str]: 

199 """The name of this field. Can be absent for struct fields.""" 

200 return typing.cast(Optional[str], self._properties["name"]) 

201 

202 @name.setter 

203 def name(self, value: Optional[str]): 

204 self._properties["name"] = value 

205 

206 @property 

207 def type(self) -> Optional[StandardSqlDataType]: 

208 """The type of this parameter. Absent if not explicitly specified. 

209 

210 For example, CREATE FUNCTION statement can omit the return type; in this 

211 case the output parameter does not have this "type" field). 

212 """ 

213 type_info = self._properties["type"] 

214 

215 if type_info is None: 

216 return None 

217 

218 result = StandardSqlDataType() 

219 # We do not use a properties copy on purpose. 

220 result._properties = typing.cast(Dict[str, Any], type_info) 

221 

222 return result 

223 

224 @type.setter 

225 def type(self, value: Optional[StandardSqlDataType]): 

226 value_repr = None if value is None else value.to_api_repr() 

227 self._properties["type"] = value_repr 

228 

229 def to_api_repr(self) -> Dict[str, Any]: 

230 """Construct the API resource representation of this SQL field.""" 

231 return copy.deepcopy(self._properties) 

232 

233 @classmethod 

234 def from_api_repr(cls, resource: Dict[str, Any]): 

235 """Construct an SQL field instance given its API representation.""" 

236 result = cls( 

237 name=resource.get("name"), 

238 type=StandardSqlDataType.from_api_repr(resource.get("type", {})), 

239 ) 

240 return result 

241 

242 def __eq__(self, other): 

243 if not isinstance(other, StandardSqlField): 

244 return NotImplemented 

245 else: 

246 return self.name == other.name and self.type == other.type 

247 

248 

249class StandardSqlStructType: 

250 """Type of a struct field. 

251 

252 See: 

253 https://cloud.google.com/bigquery/docs/reference/rest/v2/StandardSqlDataType#StandardSqlStructType 

254 

255 Args: 

256 fields: The fields in this struct. 

257 """ 

258 

259 def __init__(self, fields: Optional[Iterable[StandardSqlField]] = None): 

260 if fields is None: 

261 fields = [] 

262 self._properties = {"fields": [field.to_api_repr() for field in fields]} 

263 

264 @property 

265 def fields(self) -> List[StandardSqlField]: 

266 """The fields in this struct.""" 

267 result = [] 

268 

269 for field_resource in self._properties.get("fields", []): 

270 field = StandardSqlField() 

271 field._properties = field_resource # We do not use a copy on purpose. 

272 result.append(field) 

273 

274 return result 

275 

276 @fields.setter 

277 def fields(self, value: Iterable[StandardSqlField]): 

278 self._properties["fields"] = [field.to_api_repr() for field in value] 

279 

280 def to_api_repr(self) -> Dict[str, Any]: 

281 """Construct the API resource representation of this SQL struct type.""" 

282 return copy.deepcopy(self._properties) 

283 

284 @classmethod 

285 def from_api_repr(cls, resource: Dict[str, Any]) -> "StandardSqlStructType": 

286 """Construct an SQL struct type instance given its API representation.""" 

287 fields = ( 

288 StandardSqlField.from_api_repr(field_resource) 

289 for field_resource in resource.get("fields", []) 

290 ) 

291 return cls(fields=fields) 

292 

293 def __eq__(self, other): 

294 if not isinstance(other, StandardSqlStructType): 

295 return NotImplemented 

296 else: 

297 return self.fields == other.fields 

298 

299 

300class StandardSqlTableType: 

301 """A table type. 

302 

303 See: 

304 https://cloud.google.com/workflows/docs/reference/googleapis/bigquery/v2/Overview#StandardSqlTableType 

305 

306 Args: 

307 columns: The columns in this table type. 

308 """ 

309 

310 def __init__(self, columns: Iterable[StandardSqlField]): 

311 self._properties = {"columns": [col.to_api_repr() for col in columns]} 

312 

313 @property 

314 def columns(self) -> List[StandardSqlField]: 

315 """The columns in this table type.""" 

316 result = [] 

317 

318 for column_resource in self._properties.get("columns", []): 

319 column = StandardSqlField() 

320 column._properties = column_resource # We do not use a copy on purpose. 

321 result.append(column) 

322 

323 return result 

324 

325 @columns.setter 

326 def columns(self, value: Iterable[StandardSqlField]): 

327 self._properties["columns"] = [col.to_api_repr() for col in value] 

328 

329 def to_api_repr(self) -> Dict[str, Any]: 

330 """Construct the API resource representation of this SQL table type.""" 

331 return copy.deepcopy(self._properties) 

332 

333 @classmethod 

334 def from_api_repr(cls, resource: Dict[str, Any]) -> "StandardSqlTableType": 

335 """Construct an SQL table type instance given its API representation.""" 

336 columns = [] 

337 

338 for column_resource in resource.get("columns", []): 

339 type_ = column_resource.get("type") 

340 if type_ is None: 

341 type_ = {} 

342 

343 column = StandardSqlField( 

344 name=column_resource.get("name"), 

345 type=StandardSqlDataType.from_api_repr(type_), 

346 ) 

347 columns.append(column) 

348 

349 return cls(columns=columns) 

350 

351 def __eq__(self, other): 

352 if not isinstance(other, StandardSqlTableType): 

353 return NotImplemented 

354 else: 

355 return self.columns == other.columns