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

219 statements  

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

1# -*- coding: utf-8 -*- 

2# 

3# Copyright 2019 Google LLC 

4# 

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

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

7# You may obtain a copy of the License at 

8# 

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

10# 

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

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

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

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

15# limitations under the License. 

16 

17"""Define resources for the BigQuery Routines API.""" 

18 

19from typing import Any, Dict, Optional 

20 

21import google.cloud._helpers # type: ignore 

22from google.cloud.bigquery import _helpers 

23from google.cloud.bigquery.standard_sql import StandardSqlDataType 

24from google.cloud.bigquery.standard_sql import StandardSqlTableType 

25 

26 

27class RoutineType: 

28 """The fine-grained type of the routine. 

29 

30 https://cloud.google.com/bigquery/docs/reference/rest/v2/routines#routinetype 

31 

32 .. versionadded:: 2.22.0 

33 """ 

34 

35 ROUTINE_TYPE_UNSPECIFIED = "ROUTINE_TYPE_UNSPECIFIED" 

36 SCALAR_FUNCTION = "SCALAR_FUNCTION" 

37 PROCEDURE = "PROCEDURE" 

38 TABLE_VALUED_FUNCTION = "TABLE_VALUED_FUNCTION" 

39 

40 

41class Routine(object): 

42 """Resource representing a user-defined routine. 

43 

44 See 

45 https://cloud.google.com/bigquery/docs/reference/rest/v2/routines 

46 

47 Args: 

48 routine_ref (Union[str, google.cloud.bigquery.routine.RoutineReference]): 

49 A pointer to a routine. If ``routine_ref`` is a string, it must 

50 included a project ID, dataset ID, and routine ID, each separated 

51 by ``.``. 

52 ``**kwargs`` (Dict): 

53 Initial property values. 

54 """ 

55 

56 _PROPERTY_TO_API_FIELD = { 

57 "arguments": "arguments", 

58 "body": "definitionBody", 

59 "created": "creationTime", 

60 "etag": "etag", 

61 "imported_libraries": "importedLibraries", 

62 "language": "language", 

63 "modified": "lastModifiedTime", 

64 "reference": "routineReference", 

65 "return_type": "returnType", 

66 "return_table_type": "returnTableType", 

67 "type_": "routineType", 

68 "description": "description", 

69 "determinism_level": "determinismLevel", 

70 } 

71 

72 def __init__(self, routine_ref, **kwargs) -> None: 

73 if isinstance(routine_ref, str): 

74 routine_ref = RoutineReference.from_string(routine_ref) 

75 

76 self._properties = {"routineReference": routine_ref.to_api_repr()} 

77 for property_name in kwargs: 

78 setattr(self, property_name, kwargs[property_name]) 

79 

80 @property 

81 def reference(self): 

82 """google.cloud.bigquery.routine.RoutineReference: Reference 

83 describing the ID of this routine. 

84 """ 

85 return RoutineReference.from_api_repr( 

86 self._properties[self._PROPERTY_TO_API_FIELD["reference"]] 

87 ) 

88 

89 @property 

90 def path(self): 

91 """str: URL path for the routine's APIs.""" 

92 return self.reference.path 

93 

94 @property 

95 def project(self): 

96 """str: ID of the project containing the routine.""" 

97 return self.reference.project 

98 

99 @property 

100 def dataset_id(self): 

101 """str: ID of dataset containing the routine.""" 

102 return self.reference.dataset_id 

103 

104 @property 

105 def routine_id(self): 

106 """str: The routine ID.""" 

107 return self.reference.routine_id 

108 

109 @property 

110 def etag(self): 

111 """str: ETag for the resource (:data:`None` until set from the 

112 server). 

113 

114 Read-only. 

115 """ 

116 return self._properties.get(self._PROPERTY_TO_API_FIELD["etag"]) 

117 

118 @property 

119 def type_(self): 

120 """str: The fine-grained type of the routine. 

121 

122 See: 

123 https://cloud.google.com/bigquery/docs/reference/rest/v2/routines#RoutineType 

124 """ 

125 return self._properties.get(self._PROPERTY_TO_API_FIELD["type_"]) 

126 

127 @type_.setter 

128 def type_(self, value): 

129 self._properties[self._PROPERTY_TO_API_FIELD["type_"]] = value 

130 

131 @property 

132 def created(self): 

133 """Optional[datetime.datetime]: Datetime at which the routine was 

134 created (:data:`None` until set from the server). 

135 

136 Read-only. 

137 """ 

138 value = self._properties.get(self._PROPERTY_TO_API_FIELD["created"]) 

139 if value is not None and value != 0: 

140 # value will be in milliseconds. 

141 return google.cloud._helpers._datetime_from_microseconds( 

142 1000.0 * float(value) 

143 ) 

144 

145 @property 

146 def modified(self): 

147 """Optional[datetime.datetime]: Datetime at which the routine was 

148 last modified (:data:`None` until set from the server). 

149 

150 Read-only. 

151 """ 

152 value = self._properties.get(self._PROPERTY_TO_API_FIELD["modified"]) 

153 if value is not None and value != 0: 

154 # value will be in milliseconds. 

155 return google.cloud._helpers._datetime_from_microseconds( 

156 1000.0 * float(value) 

157 ) 

158 

159 @property 

160 def language(self): 

161 """Optional[str]: The language of the routine. 

162 

163 Defaults to ``SQL``. 

164 """ 

165 return self._properties.get(self._PROPERTY_TO_API_FIELD["language"]) 

166 

167 @language.setter 

168 def language(self, value): 

169 self._properties[self._PROPERTY_TO_API_FIELD["language"]] = value 

170 

171 @property 

172 def arguments(self): 

173 """List[google.cloud.bigquery.routine.RoutineArgument]: Input/output 

174 argument of a function or a stored procedure. 

175 

176 In-place modification is not supported. To set, replace the entire 

177 property value with the modified list of 

178 :class:`~google.cloud.bigquery.routine.RoutineArgument` objects. 

179 """ 

180 resources = self._properties.get(self._PROPERTY_TO_API_FIELD["arguments"], []) 

181 return [RoutineArgument.from_api_repr(resource) for resource in resources] 

182 

183 @arguments.setter 

184 def arguments(self, value): 

185 if not value: 

186 resource = [] 

187 else: 

188 resource = [argument.to_api_repr() for argument in value] 

189 self._properties[self._PROPERTY_TO_API_FIELD["arguments"]] = resource 

190 

191 @property 

192 def return_type(self): 

193 """google.cloud.bigquery.StandardSqlDataType: Return type of 

194 the routine. 

195 

196 If absent, the return type is inferred from 

197 :attr:`~google.cloud.bigquery.routine.Routine.body` at query time in 

198 each query that references this routine. If present, then the 

199 evaluated result will be cast to the specified returned type at query 

200 time. 

201 

202 See: 

203 https://cloud.google.com/bigquery/docs/reference/rest/v2/routines#Routine.FIELDS.return_type 

204 """ 

205 resource = self._properties.get(self._PROPERTY_TO_API_FIELD["return_type"]) 

206 if not resource: 

207 return resource 

208 

209 return StandardSqlDataType.from_api_repr(resource) 

210 

211 @return_type.setter 

212 def return_type(self, value: StandardSqlDataType): 

213 resource = None if not value else value.to_api_repr() 

214 self._properties[self._PROPERTY_TO_API_FIELD["return_type"]] = resource 

215 

216 @property 

217 def return_table_type(self) -> Optional[StandardSqlTableType]: 

218 """The return type of a Table Valued Function (TVF) routine. 

219 

220 .. versionadded:: 2.22.0 

221 """ 

222 resource = self._properties.get( 

223 self._PROPERTY_TO_API_FIELD["return_table_type"] 

224 ) 

225 if not resource: 

226 return resource 

227 

228 return StandardSqlTableType.from_api_repr(resource) 

229 

230 @return_table_type.setter 

231 def return_table_type(self, value: Optional[StandardSqlTableType]): 

232 if not value: 

233 resource = None 

234 else: 

235 resource = value.to_api_repr() 

236 

237 self._properties[self._PROPERTY_TO_API_FIELD["return_table_type"]] = resource 

238 

239 @property 

240 def imported_libraries(self): 

241 """List[str]: The path of the imported JavaScript libraries. 

242 

243 The :attr:`~google.cloud.bigquery.routine.Routine.language` must 

244 equal ``JAVACRIPT``. 

245 

246 Examples: 

247 Set the ``imported_libraries`` to a list of Google Cloud Storage 

248 URIs. 

249 

250 .. code-block:: python 

251 

252 routine = bigquery.Routine("proj.dataset.routine_id") 

253 routine.imported_libraries = [ 

254 "gs://cloud-samples-data/bigquery/udfs/max-value.js", 

255 ] 

256 """ 

257 return self._properties.get( 

258 self._PROPERTY_TO_API_FIELD["imported_libraries"], [] 

259 ) 

260 

261 @imported_libraries.setter 

262 def imported_libraries(self, value): 

263 if not value: 

264 resource = [] 

265 else: 

266 resource = value 

267 self._properties[self._PROPERTY_TO_API_FIELD["imported_libraries"]] = resource 

268 

269 @property 

270 def body(self): 

271 """str: The body of the routine.""" 

272 return self._properties.get(self._PROPERTY_TO_API_FIELD["body"]) 

273 

274 @body.setter 

275 def body(self, value): 

276 self._properties[self._PROPERTY_TO_API_FIELD["body"]] = value 

277 

278 @property 

279 def description(self): 

280 """Optional[str]: Description of the routine (defaults to 

281 :data:`None`). 

282 """ 

283 return self._properties.get(self._PROPERTY_TO_API_FIELD["description"]) 

284 

285 @description.setter 

286 def description(self, value): 

287 self._properties[self._PROPERTY_TO_API_FIELD["description"]] = value 

288 

289 @property 

290 def determinism_level(self): 

291 """Optional[str]: (experimental) The determinism level of the JavaScript UDF 

292 if defined. 

293 """ 

294 return self._properties.get(self._PROPERTY_TO_API_FIELD["determinism_level"]) 

295 

296 @determinism_level.setter 

297 def determinism_level(self, value): 

298 self._properties[self._PROPERTY_TO_API_FIELD["determinism_level"]] = value 

299 

300 @classmethod 

301 def from_api_repr(cls, resource: dict) -> "Routine": 

302 """Factory: construct a routine given its API representation. 

303 

304 Args: 

305 resource (Dict[str, object]): 

306 Resource, as returned from the API. 

307 

308 Returns: 

309 google.cloud.bigquery.routine.Routine: 

310 Python object, as parsed from ``resource``. 

311 """ 

312 ref = cls(RoutineReference.from_api_repr(resource["routineReference"])) 

313 ref._properties = resource 

314 return ref 

315 

316 def to_api_repr(self) -> dict: 

317 """Construct the API resource representation of this routine. 

318 

319 Returns: 

320 Dict[str, object]: Routine represented as an API resource. 

321 """ 

322 return self._properties 

323 

324 def _build_resource(self, filter_fields): 

325 """Generate a resource for ``update``.""" 

326 return _helpers._build_resource_from_properties(self, filter_fields) 

327 

328 def __repr__(self): 

329 return "Routine('{}.{}.{}')".format( 

330 self.project, self.dataset_id, self.routine_id 

331 ) 

332 

333 

334class RoutineArgument(object): 

335 """Input/output argument of a function or a stored procedure. 

336 

337 See: 

338 https://cloud.google.com/bigquery/docs/reference/rest/v2/routines#argument 

339 

340 Args: 

341 ``**kwargs`` (Dict): 

342 Initial property values. 

343 """ 

344 

345 _PROPERTY_TO_API_FIELD = { 

346 "data_type": "dataType", 

347 "kind": "argumentKind", 

348 # Even though it's not necessary for field mapping to map when the 

349 # property name equals the resource name, we add these here so that we 

350 # have an exhaustive list of all properties. 

351 "name": "name", 

352 "mode": "mode", 

353 } 

354 

355 def __init__(self, **kwargs) -> None: 

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

357 for property_name in kwargs: 

358 setattr(self, property_name, kwargs[property_name]) 

359 

360 @property 

361 def name(self): 

362 """Optional[str]: Name of this argument. 

363 

364 Can be absent for function return argument. 

365 """ 

366 return self._properties.get(self._PROPERTY_TO_API_FIELD["name"]) 

367 

368 @name.setter 

369 def name(self, value): 

370 self._properties[self._PROPERTY_TO_API_FIELD["name"]] = value 

371 

372 @property 

373 def kind(self): 

374 """Optional[str]: The kind of argument, for example ``FIXED_TYPE`` or 

375 ``ANY_TYPE``. 

376 

377 See: 

378 https://cloud.google.com/bigquery/docs/reference/rest/v2/routines#Argument.FIELDS.argument_kind 

379 """ 

380 return self._properties.get(self._PROPERTY_TO_API_FIELD["kind"]) 

381 

382 @kind.setter 

383 def kind(self, value): 

384 self._properties[self._PROPERTY_TO_API_FIELD["kind"]] = value 

385 

386 @property 

387 def mode(self): 

388 """Optional[str]: The input/output mode of the argument.""" 

389 return self._properties.get(self._PROPERTY_TO_API_FIELD["mode"]) 

390 

391 @mode.setter 

392 def mode(self, value): 

393 self._properties[self._PROPERTY_TO_API_FIELD["mode"]] = value 

394 

395 @property 

396 def data_type(self): 

397 """Optional[google.cloud.bigquery.StandardSqlDataType]: Type 

398 of a variable, e.g., a function argument. 

399 

400 See: 

401 https://cloud.google.com/bigquery/docs/reference/rest/v2/routines#Argument.FIELDS.data_type 

402 """ 

403 resource = self._properties.get(self._PROPERTY_TO_API_FIELD["data_type"]) 

404 if not resource: 

405 return resource 

406 

407 return StandardSqlDataType.from_api_repr(resource) 

408 

409 @data_type.setter 

410 def data_type(self, value): 

411 if value: 

412 resource = value.to_api_repr() 

413 else: 

414 resource = None 

415 self._properties[self._PROPERTY_TO_API_FIELD["data_type"]] = resource 

416 

417 @classmethod 

418 def from_api_repr(cls, resource: dict) -> "RoutineArgument": 

419 """Factory: construct a routine argument given its API representation. 

420 

421 Args: 

422 resource (Dict[str, object]): Resource, as returned from the API. 

423 

424 Returns: 

425 google.cloud.bigquery.routine.RoutineArgument: 

426 Python object, as parsed from ``resource``. 

427 """ 

428 ref = cls() 

429 ref._properties = resource 

430 return ref 

431 

432 def to_api_repr(self) -> dict: 

433 """Construct the API resource representation of this routine argument. 

434 

435 Returns: 

436 Dict[str, object]: Routine argument represented as an API resource. 

437 """ 

438 return self._properties 

439 

440 def __eq__(self, other): 

441 if not isinstance(other, RoutineArgument): 

442 return NotImplemented 

443 return self._properties == other._properties 

444 

445 def __ne__(self, other): 

446 return not self == other 

447 

448 def __repr__(self): 

449 all_properties = [ 

450 "{}={}".format(property_name, repr(getattr(self, property_name))) 

451 for property_name in sorted(self._PROPERTY_TO_API_FIELD) 

452 ] 

453 return "RoutineArgument({})".format(", ".join(all_properties)) 

454 

455 

456class RoutineReference(object): 

457 """A pointer to a routine. 

458 

459 See: 

460 https://cloud.google.com/bigquery/docs/reference/rest/v2/routines#routinereference 

461 """ 

462 

463 def __init__(self): 

464 self._properties = {} 

465 

466 @property 

467 def project(self): 

468 """str: ID of the project containing the routine.""" 

469 return self._properties["projectId"] # pytype: disable=key-error 

470 

471 @property 

472 def dataset_id(self): 

473 """str: ID of dataset containing the routine.""" 

474 return self._properties["datasetId"] # pytype: disable=key-error 

475 

476 @property 

477 def routine_id(self): 

478 """str: The routine ID.""" 

479 return self._properties["routineId"] # pytype: disable=key-error 

480 

481 @property 

482 def path(self): 

483 """str: URL path for the routine's APIs.""" 

484 return "/projects/%s/datasets/%s/routines/%s" % ( 

485 self.project, 

486 self.dataset_id, 

487 self.routine_id, 

488 ) 

489 

490 @classmethod 

491 def from_api_repr(cls, resource: dict) -> "RoutineReference": 

492 """Factory: construct a routine reference given its API representation. 

493 

494 Args: 

495 resource (Dict[str, object]): 

496 Routine reference representation returned from the API. 

497 

498 Returns: 

499 google.cloud.bigquery.routine.RoutineReference: 

500 Routine reference parsed from ``resource``. 

501 """ 

502 ref = cls() 

503 ref._properties = resource 

504 return ref 

505 

506 @classmethod 

507 def from_string( 

508 cls, routine_id: str, default_project: str = None 

509 ) -> "RoutineReference": 

510 """Factory: construct a routine reference from routine ID string. 

511 

512 Args: 

513 routine_id (str): 

514 A routine ID in standard SQL format. If ``default_project`` 

515 is not specified, this must included a project ID, dataset 

516 ID, and routine ID, each separated by ``.``. 

517 default_project (Optional[str]): 

518 The project ID to use when ``routine_id`` does not 

519 include a project ID. 

520 

521 Returns: 

522 google.cloud.bigquery.routine.RoutineReference: 

523 Routine reference parsed from ``routine_id``. 

524 

525 Raises: 

526 ValueError: 

527 If ``routine_id`` is not a fully-qualified routine ID in 

528 standard SQL format. 

529 """ 

530 proj, dset, routine = _helpers._parse_3_part_id( 

531 routine_id, default_project=default_project, property_name="routine_id" 

532 ) 

533 return cls.from_api_repr( 

534 {"projectId": proj, "datasetId": dset, "routineId": routine} 

535 ) 

536 

537 def to_api_repr(self) -> dict: 

538 """Construct the API resource representation of this routine reference. 

539 

540 Returns: 

541 Dict[str, object]: Routine reference represented as an API resource. 

542 """ 

543 return self._properties 

544 

545 def __eq__(self, other): 

546 """Two RoutineReferences are equal if they point to the same routine.""" 

547 if not isinstance(other, RoutineReference): 

548 return NotImplemented 

549 return str(self) == str(other) 

550 

551 def __hash__(self): 

552 return hash(str(self)) 

553 

554 def __ne__(self, other): 

555 return not self == other 

556 

557 def __repr__(self): 

558 return "RoutineReference.from_string('{}')".format(str(self)) 

559 

560 def __str__(self): 

561 """String representation of the reference. 

562 

563 This is a fully-qualified ID, including the project ID and dataset ID. 

564 """ 

565 return "{}.{}.{}".format(self.project, self.dataset_id, self.routine_id)