structure saas with tools
This commit is contained in:
@@ -0,0 +1,389 @@
|
||||
# Copyright 2021 Google LLC
|
||||
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import copy
|
||||
import typing
|
||||
from typing import Any, Dict, Iterable, List, Optional
|
||||
|
||||
from google.cloud.bigquery.enums import StandardSqlTypeNames
|
||||
|
||||
|
||||
class StandardSqlDataType:
|
||||
"""The type of a variable, e.g., a function argument.
|
||||
|
||||
See:
|
||||
https://cloud.google.com/bigquery/docs/reference/rest/v2/StandardSqlDataType
|
||||
|
||||
Examples:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
INT64: {type_kind="INT64"}
|
||||
ARRAY: {type_kind="ARRAY", array_element_type="STRING"}
|
||||
STRUCT<x STRING, y ARRAY>: {
|
||||
type_kind="STRUCT",
|
||||
struct_type={
|
||||
fields=[
|
||||
{name="x", type={type_kind="STRING"}},
|
||||
{
|
||||
name="y",
|
||||
type={type_kind="ARRAY", array_element_type="DATE"}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
RANGE: {type_kind="RANGE", range_element_type="DATETIME"}
|
||||
|
||||
Args:
|
||||
type_kind:
|
||||
The top level type of this field. Can be any standard SQL data type,
|
||||
e.g. INT64, DATE, ARRAY.
|
||||
array_element_type:
|
||||
The type of the array's elements, if type_kind is ARRAY.
|
||||
struct_type:
|
||||
The fields of this struct, in order, if type_kind is STRUCT.
|
||||
range_element_type:
|
||||
The type of the range's elements, if type_kind is RANGE.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
type_kind: Optional[
|
||||
StandardSqlTypeNames
|
||||
] = StandardSqlTypeNames.TYPE_KIND_UNSPECIFIED,
|
||||
array_element_type: Optional["StandardSqlDataType"] = None,
|
||||
struct_type: Optional["StandardSqlStructType"] = None,
|
||||
range_element_type: Optional["StandardSqlDataType"] = None,
|
||||
):
|
||||
self._properties: Dict[str, Any] = {}
|
||||
|
||||
self.type_kind = type_kind
|
||||
self.array_element_type = array_element_type
|
||||
self.struct_type = struct_type
|
||||
self.range_element_type = range_element_type
|
||||
|
||||
@property
|
||||
def type_kind(self) -> Optional[StandardSqlTypeNames]:
|
||||
"""The top level type of this field.
|
||||
|
||||
Can be any standard SQL data type, e.g. INT64, DATE, ARRAY.
|
||||
"""
|
||||
kind = self._properties["typeKind"]
|
||||
return StandardSqlTypeNames[kind] # pytype: disable=missing-parameter
|
||||
|
||||
@type_kind.setter
|
||||
def type_kind(self, value: Optional[StandardSqlTypeNames]):
|
||||
if not value:
|
||||
kind = StandardSqlTypeNames.TYPE_KIND_UNSPECIFIED.value
|
||||
else:
|
||||
kind = value.value
|
||||
self._properties["typeKind"] = kind
|
||||
|
||||
@property
|
||||
def array_element_type(self) -> Optional["StandardSqlDataType"]:
|
||||
"""The type of the array's elements, if type_kind is ARRAY."""
|
||||
element_type = self._properties.get("arrayElementType")
|
||||
|
||||
if element_type is None:
|
||||
return None
|
||||
|
||||
result = StandardSqlDataType()
|
||||
result._properties = element_type # We do not use a copy on purpose.
|
||||
return result
|
||||
|
||||
@array_element_type.setter
|
||||
def array_element_type(self, value: Optional["StandardSqlDataType"]):
|
||||
element_type = None if value is None else value.to_api_repr()
|
||||
|
||||
if element_type is None:
|
||||
self._properties.pop("arrayElementType", None)
|
||||
else:
|
||||
self._properties["arrayElementType"] = element_type
|
||||
|
||||
@property
|
||||
def struct_type(self) -> Optional["StandardSqlStructType"]:
|
||||
"""The fields of this struct, in order, if type_kind is STRUCT."""
|
||||
struct_info = self._properties.get("structType")
|
||||
|
||||
if struct_info is None:
|
||||
return None
|
||||
|
||||
result = StandardSqlStructType()
|
||||
result._properties = struct_info # We do not use a copy on purpose.
|
||||
return result
|
||||
|
||||
@struct_type.setter
|
||||
def struct_type(self, value: Optional["StandardSqlStructType"]):
|
||||
struct_type = None if value is None else value.to_api_repr()
|
||||
|
||||
if struct_type is None:
|
||||
self._properties.pop("structType", None)
|
||||
else:
|
||||
self._properties["structType"] = struct_type
|
||||
|
||||
@property
|
||||
def range_element_type(self) -> Optional["StandardSqlDataType"]:
|
||||
"""The type of the range's elements, if type_kind = "RANGE". Must be
|
||||
one of DATETIME, DATE, or TIMESTAMP."""
|
||||
range_element_info = self._properties.get("rangeElementType")
|
||||
|
||||
if range_element_info is None:
|
||||
return None
|
||||
|
||||
result = StandardSqlDataType()
|
||||
result._properties = range_element_info # We do not use a copy on purpose.
|
||||
return result
|
||||
|
||||
@range_element_type.setter
|
||||
def range_element_type(self, value: Optional["StandardSqlDataType"]):
|
||||
range_element_type = None if value is None else value.to_api_repr()
|
||||
|
||||
if range_element_type is None:
|
||||
self._properties.pop("rangeElementType", None)
|
||||
else:
|
||||
self._properties["rangeElementType"] = range_element_type
|
||||
|
||||
def to_api_repr(self) -> Dict[str, Any]:
|
||||
"""Construct the API resource representation of this SQL data type."""
|
||||
return copy.deepcopy(self._properties)
|
||||
|
||||
@classmethod
|
||||
def from_api_repr(cls, resource: Dict[str, Any]):
|
||||
"""Construct an SQL data type instance given its API representation."""
|
||||
type_kind = resource.get("typeKind")
|
||||
if type_kind not in StandardSqlTypeNames.__members__:
|
||||
type_kind = StandardSqlTypeNames.TYPE_KIND_UNSPECIFIED
|
||||
else:
|
||||
# Convert string to an enum member.
|
||||
type_kind = StandardSqlTypeNames[ # pytype: disable=missing-parameter
|
||||
typing.cast(str, type_kind)
|
||||
]
|
||||
|
||||
array_element_type = None
|
||||
if type_kind == StandardSqlTypeNames.ARRAY:
|
||||
element_type = resource.get("arrayElementType")
|
||||
if element_type:
|
||||
array_element_type = cls.from_api_repr(element_type)
|
||||
|
||||
struct_type = None
|
||||
if type_kind == StandardSqlTypeNames.STRUCT:
|
||||
struct_info = resource.get("structType")
|
||||
if struct_info:
|
||||
struct_type = StandardSqlStructType.from_api_repr(struct_info)
|
||||
|
||||
range_element_type = None
|
||||
if type_kind == StandardSqlTypeNames.RANGE:
|
||||
range_element_info = resource.get("rangeElementType")
|
||||
if range_element_info:
|
||||
range_element_type = cls.from_api_repr(range_element_info)
|
||||
|
||||
return cls(type_kind, array_element_type, struct_type, range_element_type)
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, StandardSqlDataType):
|
||||
return NotImplemented
|
||||
else:
|
||||
return (
|
||||
self.type_kind == other.type_kind
|
||||
and self.array_element_type == other.array_element_type
|
||||
and self.struct_type == other.struct_type
|
||||
and self.range_element_type == other.range_element_type
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
result = f"{self.__class__.__name__}(type_kind={self.type_kind!r}, ...)"
|
||||
return result
|
||||
|
||||
|
||||
class StandardSqlField:
|
||||
"""A field or a column.
|
||||
|
||||
See:
|
||||
https://cloud.google.com/bigquery/docs/reference/rest/v2/StandardSqlField
|
||||
|
||||
Args:
|
||||
name:
|
||||
The name of this field. Can be absent for struct fields.
|
||||
type:
|
||||
The type of this parameter. Absent if not explicitly specified.
|
||||
|
||||
For example, CREATE FUNCTION statement can omit the return type; in this
|
||||
case the output parameter does not have this "type" field).
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, name: Optional[str] = None, type: Optional[StandardSqlDataType] = None
|
||||
):
|
||||
type_repr = None if type is None else type.to_api_repr()
|
||||
self._properties = {"name": name, "type": type_repr}
|
||||
|
||||
@property
|
||||
def name(self) -> Optional[str]:
|
||||
"""The name of this field. Can be absent for struct fields."""
|
||||
return typing.cast(Optional[str], self._properties["name"])
|
||||
|
||||
@name.setter
|
||||
def name(self, value: Optional[str]):
|
||||
self._properties["name"] = value
|
||||
|
||||
@property
|
||||
def type(self) -> Optional[StandardSqlDataType]:
|
||||
"""The type of this parameter. Absent if not explicitly specified.
|
||||
|
||||
For example, CREATE FUNCTION statement can omit the return type; in this
|
||||
case the output parameter does not have this "type" field).
|
||||
"""
|
||||
type_info = self._properties["type"]
|
||||
|
||||
if type_info is None:
|
||||
return None
|
||||
|
||||
result = StandardSqlDataType()
|
||||
# We do not use a properties copy on purpose.
|
||||
result._properties = typing.cast(Dict[str, Any], type_info)
|
||||
|
||||
return result
|
||||
|
||||
@type.setter
|
||||
def type(self, value: Optional[StandardSqlDataType]):
|
||||
value_repr = None if value is None else value.to_api_repr()
|
||||
self._properties["type"] = value_repr
|
||||
|
||||
def to_api_repr(self) -> Dict[str, Any]:
|
||||
"""Construct the API resource representation of this SQL field."""
|
||||
return copy.deepcopy(self._properties)
|
||||
|
||||
@classmethod
|
||||
def from_api_repr(cls, resource: Dict[str, Any]):
|
||||
"""Construct an SQL field instance given its API representation."""
|
||||
result = cls(
|
||||
name=resource.get("name"),
|
||||
type=StandardSqlDataType.from_api_repr(resource.get("type", {})),
|
||||
)
|
||||
return result
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, StandardSqlField):
|
||||
return NotImplemented
|
||||
else:
|
||||
return self.name == other.name and self.type == other.type
|
||||
|
||||
|
||||
class StandardSqlStructType:
|
||||
"""Type of a struct field.
|
||||
|
||||
See:
|
||||
https://cloud.google.com/bigquery/docs/reference/rest/v2/StandardSqlDataType#StandardSqlStructType
|
||||
|
||||
Args:
|
||||
fields: The fields in this struct.
|
||||
"""
|
||||
|
||||
def __init__(self, fields: Optional[Iterable[StandardSqlField]] = None):
|
||||
if fields is None:
|
||||
fields = []
|
||||
self._properties = {"fields": [field.to_api_repr() for field in fields]}
|
||||
|
||||
@property
|
||||
def fields(self) -> List[StandardSqlField]:
|
||||
"""The fields in this struct."""
|
||||
result = []
|
||||
|
||||
for field_resource in self._properties.get("fields", []):
|
||||
field = StandardSqlField()
|
||||
field._properties = field_resource # We do not use a copy on purpose.
|
||||
result.append(field)
|
||||
|
||||
return result
|
||||
|
||||
@fields.setter
|
||||
def fields(self, value: Iterable[StandardSqlField]):
|
||||
self._properties["fields"] = [field.to_api_repr() for field in value]
|
||||
|
||||
def to_api_repr(self) -> Dict[str, Any]:
|
||||
"""Construct the API resource representation of this SQL struct type."""
|
||||
return copy.deepcopy(self._properties)
|
||||
|
||||
@classmethod
|
||||
def from_api_repr(cls, resource: Dict[str, Any]) -> "StandardSqlStructType":
|
||||
"""Construct an SQL struct type instance given its API representation."""
|
||||
fields = (
|
||||
StandardSqlField.from_api_repr(field_resource)
|
||||
for field_resource in resource.get("fields", [])
|
||||
)
|
||||
return cls(fields=fields)
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, StandardSqlStructType):
|
||||
return NotImplemented
|
||||
else:
|
||||
return self.fields == other.fields
|
||||
|
||||
|
||||
class StandardSqlTableType:
|
||||
"""A table type.
|
||||
|
||||
See:
|
||||
https://cloud.google.com/workflows/docs/reference/googleapis/bigquery/v2/Overview#StandardSqlTableType
|
||||
|
||||
Args:
|
||||
columns: The columns in this table type.
|
||||
"""
|
||||
|
||||
def __init__(self, columns: Iterable[StandardSqlField]):
|
||||
self._properties = {"columns": [col.to_api_repr() for col in columns]}
|
||||
|
||||
@property
|
||||
def columns(self) -> List[StandardSqlField]:
|
||||
"""The columns in this table type."""
|
||||
result = []
|
||||
|
||||
for column_resource in self._properties.get("columns", []):
|
||||
column = StandardSqlField()
|
||||
column._properties = column_resource # We do not use a copy on purpose.
|
||||
result.append(column)
|
||||
|
||||
return result
|
||||
|
||||
@columns.setter
|
||||
def columns(self, value: Iterable[StandardSqlField]):
|
||||
self._properties["columns"] = [col.to_api_repr() for col in value]
|
||||
|
||||
def to_api_repr(self) -> Dict[str, Any]:
|
||||
"""Construct the API resource representation of this SQL table type."""
|
||||
return copy.deepcopy(self._properties)
|
||||
|
||||
@classmethod
|
||||
def from_api_repr(cls, resource: Dict[str, Any]) -> "StandardSqlTableType":
|
||||
"""Construct an SQL table type instance given its API representation."""
|
||||
columns = []
|
||||
|
||||
for column_resource in resource.get("columns", []):
|
||||
type_ = column_resource.get("type")
|
||||
if type_ is None:
|
||||
type_ = {}
|
||||
|
||||
column = StandardSqlField(
|
||||
name=column_resource.get("name"),
|
||||
type=StandardSqlDataType.from_api_repr(type_),
|
||||
)
|
||||
columns.append(column)
|
||||
|
||||
return cls(columns=columns)
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, StandardSqlTableType):
|
||||
return NotImplemented
|
||||
else:
|
||||
return self.columns == other.columns
|
||||
Reference in New Issue
Block a user