cloudquery-plugin-sdk 0.1.55__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cloudquery/sdk/__init__.py +0 -0
- cloudquery/sdk/internal/__init__.py +0 -0
- cloudquery/sdk/internal/checkpoint.py +199 -0
- cloudquery/sdk/internal/memdb/__init__.py +1 -0
- cloudquery/sdk/internal/memdb/memdb.py +221 -0
- cloudquery/sdk/internal/servers/__init__.py +0 -0
- cloudquery/sdk/internal/servers/discovery_v1/__init__.py +0 -0
- cloudquery/sdk/internal/servers/discovery_v1/discovery.py +11 -0
- cloudquery/sdk/internal/servers/plugin_v3/__init__.py +1 -0
- cloudquery/sdk/internal/servers/plugin_v3/plugin.py +156 -0
- cloudquery/sdk/message/__init__.py +14 -0
- cloudquery/sdk/message/read.py +6 -0
- cloudquery/sdk/message/sync.py +31 -0
- cloudquery/sdk/message/write.py +24 -0
- cloudquery/sdk/plugin/__init__.py +1 -0
- cloudquery/sdk/plugin/plugin.py +102 -0
- cloudquery/sdk/py.typed +0 -0
- cloudquery/sdk/scalar/__init__.py +15 -0
- cloudquery/sdk/scalar/binary.py +35 -0
- cloudquery/sdk/scalar/bool.py +48 -0
- cloudquery/sdk/scalar/date32.py +39 -0
- cloudquery/sdk/scalar/date64.py +39 -0
- cloudquery/sdk/scalar/float.py +49 -0
- cloudquery/sdk/scalar/int.py +56 -0
- cloudquery/sdk/scalar/json.py +27 -0
- cloudquery/sdk/scalar/list.py +56 -0
- cloudquery/sdk/scalar/scalar.py +30 -0
- cloudquery/sdk/scalar/scalar_factory.py +64 -0
- cloudquery/sdk/scalar/string.py +31 -0
- cloudquery/sdk/scalar/timestamp.py +41 -0
- cloudquery/sdk/scalar/uint.py +58 -0
- cloudquery/sdk/scalar/uuid.py +43 -0
- cloudquery/sdk/scalar/vector.py +43 -0
- cloudquery/sdk/scheduler/__init__.py +3 -0
- cloudquery/sdk/scheduler/scheduler.py +267 -0
- cloudquery/sdk/scheduler/table_resolver.py +48 -0
- cloudquery/sdk/schema/__init__.py +16 -0
- cloudquery/sdk/schema/arrow.py +11 -0
- cloudquery/sdk/schema/column.py +77 -0
- cloudquery/sdk/schema/resource.py +29 -0
- cloudquery/sdk/schema/table.py +332 -0
- cloudquery/sdk/serve/__init__.py +1 -0
- cloudquery/sdk/serve/plugin.py +407 -0
- cloudquery/sdk/stateclient/__init__.py +1 -0
- cloudquery/sdk/stateclient/keys.py +44 -0
- cloudquery/sdk/stateclient/stateclient.py +278 -0
- cloudquery/sdk/transformers/__init__.py +2 -0
- cloudquery/sdk/transformers/openapi.py +49 -0
- cloudquery/sdk/transformers/transformers.py +13 -0
- cloudquery/sdk/types/__init__.py +2 -0
- cloudquery/sdk/types/json.py +26 -0
- cloudquery/sdk/types/uuid.py +28 -0
- cloudquery_plugin_sdk-0.1.55.dist-info/METADATA +50 -0
- cloudquery_plugin_sdk-0.1.55.dist-info/RECORD +57 -0
- cloudquery_plugin_sdk-0.1.55.dist-info/WHEEL +5 -0
- cloudquery_plugin_sdk-0.1.55.dist-info/licenses/LICENSE +353 -0
- cloudquery_plugin_sdk-0.1.55.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import List, Generator
|
|
3
|
+
|
|
4
|
+
from cloudquery.sdk import message
|
|
5
|
+
from cloudquery.sdk.schema import Table
|
|
6
|
+
|
|
7
|
+
MIGRATE_MODE_STRINGS = ["safe", "force"]
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class TableOptions:
|
|
12
|
+
tables: List[str] = None
|
|
13
|
+
skip_tables: List[str] = None
|
|
14
|
+
skip_dependent_tables: bool = False
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class BackendOptions:
|
|
19
|
+
connection: str = None
|
|
20
|
+
table_name: str = None
|
|
21
|
+
# set when the CLI persists state sent as checkpoints on the sync stream
|
|
22
|
+
supports_checkpoints: bool = False
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class SyncOptions:
|
|
27
|
+
deterministic_cq_id: bool = False
|
|
28
|
+
skip_dependent_tables: bool = False
|
|
29
|
+
skip_tables: List[str] = None
|
|
30
|
+
tables: List[str] = None
|
|
31
|
+
backend_options: BackendOptions = None
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass
|
|
35
|
+
class BuildTarget:
|
|
36
|
+
os: str = None
|
|
37
|
+
arch: str = None
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class Options:
|
|
42
|
+
dockerfile: str = None
|
|
43
|
+
build_targets: List[BuildTarget] = None
|
|
44
|
+
team: str = None
|
|
45
|
+
kind: str = None
|
|
46
|
+
json_schema: str = None
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class Plugin:
|
|
50
|
+
def __init__(self, name: str, version: str, opts: Options = None) -> None:
|
|
51
|
+
self._name = name
|
|
52
|
+
self._version = version
|
|
53
|
+
self._opts = Options() if opts is None else opts
|
|
54
|
+
if self._opts.dockerfile is None:
|
|
55
|
+
self._opts.dockerfile = "Dockerfile"
|
|
56
|
+
if self._opts.build_targets is None:
|
|
57
|
+
self._opts.build_targets = [
|
|
58
|
+
BuildTarget("linux", "amd64"),
|
|
59
|
+
BuildTarget("linux", "arm64"),
|
|
60
|
+
]
|
|
61
|
+
|
|
62
|
+
def init(self, spec: bytes, no_connection: bool = False) -> None:
|
|
63
|
+
pass
|
|
64
|
+
|
|
65
|
+
def set_logger(self, logger) -> None:
|
|
66
|
+
pass
|
|
67
|
+
|
|
68
|
+
def name(self) -> str:
|
|
69
|
+
return self._name
|
|
70
|
+
|
|
71
|
+
def version(self) -> str:
|
|
72
|
+
return self._version
|
|
73
|
+
|
|
74
|
+
def team(self) -> str:
|
|
75
|
+
return self._opts.team
|
|
76
|
+
|
|
77
|
+
def kind(self) -> str:
|
|
78
|
+
return self._opts.kind
|
|
79
|
+
|
|
80
|
+
def json_schema(self) -> str:
|
|
81
|
+
return self._opts.json_schema
|
|
82
|
+
|
|
83
|
+
def dockerfile(self) -> str:
|
|
84
|
+
return self._opts.dockerfile
|
|
85
|
+
|
|
86
|
+
def build_targets(self) -> List[BuildTarget]:
|
|
87
|
+
return self._opts.build_targets
|
|
88
|
+
|
|
89
|
+
def get_tables(self, options: TableOptions) -> List[Table]:
|
|
90
|
+
raise NotImplementedError()
|
|
91
|
+
|
|
92
|
+
def sync(self, options: SyncOptions) -> Generator[message.SyncMessage, None, None]:
|
|
93
|
+
raise NotImplementedError()
|
|
94
|
+
|
|
95
|
+
def write(self, writer: Generator[message.WriteMessage, None, None]) -> None:
|
|
96
|
+
raise NotImplementedError()
|
|
97
|
+
|
|
98
|
+
def read(self, table: Table) -> Generator[message.ReadMessage, None, None]:
|
|
99
|
+
raise NotImplementedError()
|
|
100
|
+
|
|
101
|
+
def close(self) -> None:
|
|
102
|
+
raise NotImplementedError()
|
cloudquery/sdk/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from .scalar import Scalar, ScalarInvalidTypeError, NULL_VALUE
|
|
2
|
+
from .scalar_factory import ScalarFactory
|
|
3
|
+
from .vector import Vector
|
|
4
|
+
|
|
5
|
+
from .binary import Binary
|
|
6
|
+
from .bool import Bool
|
|
7
|
+
from .date32 import Date32
|
|
8
|
+
from .date64 import Date64
|
|
9
|
+
from .float import Float
|
|
10
|
+
from .int import Int
|
|
11
|
+
from .list import List
|
|
12
|
+
from .string import String
|
|
13
|
+
from .timestamp import Timestamp
|
|
14
|
+
from .uint import Uint
|
|
15
|
+
from .uuid import UUID
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from cloudquery.sdk.scalar import Scalar, ScalarInvalidTypeError
|
|
2
|
+
from .scalar import NULL_VALUE
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Binary(Scalar):
|
|
6
|
+
def __eq__(self, scalar: Scalar) -> bool:
|
|
7
|
+
if scalar is None:
|
|
8
|
+
return False
|
|
9
|
+
if isinstance(scalar, Binary):
|
|
10
|
+
return self._value == scalar._value and self._valid == scalar._valid
|
|
11
|
+
return False
|
|
12
|
+
|
|
13
|
+
@property
|
|
14
|
+
def value(self):
|
|
15
|
+
return self._value
|
|
16
|
+
|
|
17
|
+
def set(self, value: any):
|
|
18
|
+
if value is None:
|
|
19
|
+
return
|
|
20
|
+
|
|
21
|
+
if isinstance(value, Binary):
|
|
22
|
+
self._valid = value.is_valid
|
|
23
|
+
self._value = value.value
|
|
24
|
+
return
|
|
25
|
+
|
|
26
|
+
if isinstance(value, bytes):
|
|
27
|
+
self._valid = True
|
|
28
|
+
self._value = value
|
|
29
|
+
elif isinstance(value, str):
|
|
30
|
+
self._valid = True
|
|
31
|
+
self._value = value.encode()
|
|
32
|
+
else:
|
|
33
|
+
raise ScalarInvalidTypeError(
|
|
34
|
+
f"Invalid type {type(value)} for Binary scalar"
|
|
35
|
+
)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from cloudquery.sdk.scalar import Scalar, ScalarInvalidTypeError, NULL_VALUE
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def parse_string_to_bool(input_string):
|
|
6
|
+
true_strings = ["true", "t", "yes", "y", "1"]
|
|
7
|
+
false_strings = ["false", "f", "no", "n", "0"]
|
|
8
|
+
|
|
9
|
+
lower_input = input_string.lower()
|
|
10
|
+
|
|
11
|
+
if lower_input in true_strings:
|
|
12
|
+
return True
|
|
13
|
+
if lower_input in false_strings:
|
|
14
|
+
return False
|
|
15
|
+
else:
|
|
16
|
+
raise ScalarInvalidTypeError(f"Invalid boolean string: {input_string}")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Bool(Scalar):
|
|
20
|
+
def __eq__(self, scalar: Scalar) -> bool:
|
|
21
|
+
if scalar is None:
|
|
22
|
+
return False
|
|
23
|
+
if isinstance(scalar, Bool):
|
|
24
|
+
return self._value == scalar._value and self._valid == scalar._valid
|
|
25
|
+
return False
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def value(self):
|
|
29
|
+
return self._value
|
|
30
|
+
|
|
31
|
+
def set(self, value: Any):
|
|
32
|
+
if value is None:
|
|
33
|
+
self._valid = False
|
|
34
|
+
return
|
|
35
|
+
|
|
36
|
+
if isinstance(value, Bool):
|
|
37
|
+
self._valid = value.is_valid
|
|
38
|
+
self._value = value.value
|
|
39
|
+
return
|
|
40
|
+
|
|
41
|
+
if isinstance(value, bool):
|
|
42
|
+
self._value = value
|
|
43
|
+
elif isinstance(value, str):
|
|
44
|
+
self._value = parse_string_to_bool(value)
|
|
45
|
+
else:
|
|
46
|
+
raise ScalarInvalidTypeError(f"Invalid type {type(value)} for Bool scalar")
|
|
47
|
+
|
|
48
|
+
self._valid = True
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from cloudquery.sdk.scalar import Scalar, ScalarInvalidTypeError, NULL_VALUE
|
|
2
|
+
from datetime import datetime, time
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Date32(Scalar):
|
|
7
|
+
def __eq__(self, scalar: Scalar) -> bool:
|
|
8
|
+
if scalar is None:
|
|
9
|
+
return False
|
|
10
|
+
if isinstance(scalar, Date32):
|
|
11
|
+
return self._value == scalar._value and self._valid == scalar._valid
|
|
12
|
+
return False
|
|
13
|
+
|
|
14
|
+
@property
|
|
15
|
+
def value(self):
|
|
16
|
+
return self._value
|
|
17
|
+
|
|
18
|
+
def set(self, value: Any):
|
|
19
|
+
if value is None:
|
|
20
|
+
self._valid = False
|
|
21
|
+
return
|
|
22
|
+
|
|
23
|
+
if isinstance(value, Date32):
|
|
24
|
+
self._valid = value.is_valid
|
|
25
|
+
self._value = value.value
|
|
26
|
+
return
|
|
27
|
+
|
|
28
|
+
if isinstance(value, datetime):
|
|
29
|
+
self._value = value
|
|
30
|
+
elif isinstance(value, str):
|
|
31
|
+
self._value = datetime.strptime(value, "%Y-%m-%d")
|
|
32
|
+
elif isinstance(value, time):
|
|
33
|
+
self._value = datetime.combine(datetime.today(), value)
|
|
34
|
+
else:
|
|
35
|
+
raise ScalarInvalidTypeError(
|
|
36
|
+
f"Invalid type {type(value)} for Date32 scalar"
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
self._valid = True
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from cloudquery.sdk.scalar import Scalar, ScalarInvalidTypeError, NULL_VALUE
|
|
2
|
+
from datetime import datetime, time
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Date64(Scalar):
|
|
7
|
+
def __eq__(self, scalar: Scalar) -> bool:
|
|
8
|
+
if scalar is None:
|
|
9
|
+
return False
|
|
10
|
+
if isinstance(scalar, Date64):
|
|
11
|
+
return self._value == scalar._value and self._valid == scalar._valid
|
|
12
|
+
return False
|
|
13
|
+
|
|
14
|
+
@property
|
|
15
|
+
def value(self):
|
|
16
|
+
return self._value
|
|
17
|
+
|
|
18
|
+
def set(self, value: Any):
|
|
19
|
+
if value is None:
|
|
20
|
+
self._valid = False
|
|
21
|
+
return
|
|
22
|
+
|
|
23
|
+
if isinstance(value, Date64):
|
|
24
|
+
self._valid = value.is_valid
|
|
25
|
+
self._value = value.value
|
|
26
|
+
return
|
|
27
|
+
|
|
28
|
+
if isinstance(value, datetime):
|
|
29
|
+
self._value = value
|
|
30
|
+
elif isinstance(value, str):
|
|
31
|
+
self._value = datetime.strptime(value, "%Y-%m-%d")
|
|
32
|
+
elif isinstance(value, time):
|
|
33
|
+
self._value = datetime.combine(datetime.today(), value)
|
|
34
|
+
else:
|
|
35
|
+
raise ScalarInvalidTypeError(
|
|
36
|
+
f"Invalid type {type(value)} for Date64 scalar"
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
self._valid = True
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from cloudquery.sdk.scalar import Scalar, ScalarInvalidTypeError
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Float(Scalar):
|
|
5
|
+
def __init__(self, valid: bool = False, value: any = None, bitwidth: int = 64):
|
|
6
|
+
super().__init__(valid, value)
|
|
7
|
+
self._bitwidth = bitwidth
|
|
8
|
+
|
|
9
|
+
def __eq__(self, scalar: Scalar) -> bool:
|
|
10
|
+
if scalar is None:
|
|
11
|
+
return False
|
|
12
|
+
if isinstance(scalar, Float) and self._bitwidth == scalar.bitwidth:
|
|
13
|
+
return self._value == scalar._value and self._valid == scalar._valid
|
|
14
|
+
return False
|
|
15
|
+
|
|
16
|
+
@property
|
|
17
|
+
def bitwidth(self):
|
|
18
|
+
return self._bitwidth
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def value(self):
|
|
22
|
+
return self._value
|
|
23
|
+
|
|
24
|
+
def set(self, value: any):
|
|
25
|
+
if value is None:
|
|
26
|
+
self._valid = False
|
|
27
|
+
return
|
|
28
|
+
|
|
29
|
+
if isinstance(value, Float) and value.bitwidth == self._bitwidth:
|
|
30
|
+
self._valid = value.is_valid
|
|
31
|
+
self._value = value.value
|
|
32
|
+
return
|
|
33
|
+
|
|
34
|
+
if isinstance(value, int):
|
|
35
|
+
self._value = float(value)
|
|
36
|
+
elif isinstance(value, float):
|
|
37
|
+
self._value = value
|
|
38
|
+
elif isinstance(value, str):
|
|
39
|
+
try:
|
|
40
|
+
self._value = float(value)
|
|
41
|
+
except ValueError as e:
|
|
42
|
+
raise ScalarInvalidTypeError(
|
|
43
|
+
f"Invalid value for Float{self._bitwidth} scalar"
|
|
44
|
+
) from e
|
|
45
|
+
else:
|
|
46
|
+
raise ScalarInvalidTypeError(
|
|
47
|
+
f"Invalid type {type(value)} for Float{self._bitwidth} scalar"
|
|
48
|
+
)
|
|
49
|
+
self._valid = True
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
from cloudquery.sdk.scalar import Scalar, ScalarInvalidTypeError
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Int(Scalar):
|
|
5
|
+
def __init__(self, valid: bool = False, value: any = None, bitwidth: int = 64):
|
|
6
|
+
self._bitwidth = bitwidth
|
|
7
|
+
self._min = -(2 ** (bitwidth - 1))
|
|
8
|
+
self._max = 2 ** (bitwidth - 1)
|
|
9
|
+
super().__init__(valid, value)
|
|
10
|
+
|
|
11
|
+
def __eq__(self, scalar: Scalar) -> bool:
|
|
12
|
+
if scalar is None:
|
|
13
|
+
return False
|
|
14
|
+
if isinstance(scalar, Int) and self._bitwidth == scalar.bitwidth:
|
|
15
|
+
return self._value == scalar._value and self._valid == scalar._valid
|
|
16
|
+
return False
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def bitwidth(self):
|
|
20
|
+
return self._bitwidth
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def value(self):
|
|
24
|
+
return self._value
|
|
25
|
+
|
|
26
|
+
def set(self, value: any):
|
|
27
|
+
if value is None:
|
|
28
|
+
self._valid = False
|
|
29
|
+
return
|
|
30
|
+
|
|
31
|
+
if isinstance(value, Int) and value.bitwidth == self._bitwidth:
|
|
32
|
+
self._valid = value.is_valid
|
|
33
|
+
self._value = value.value
|
|
34
|
+
return
|
|
35
|
+
|
|
36
|
+
if isinstance(value, int):
|
|
37
|
+
val = value
|
|
38
|
+
elif isinstance(value, float):
|
|
39
|
+
val = int(value)
|
|
40
|
+
elif isinstance(value, str):
|
|
41
|
+
try:
|
|
42
|
+
val = int(value)
|
|
43
|
+
except ValueError as e:
|
|
44
|
+
raise ScalarInvalidTypeError(
|
|
45
|
+
f"Invalid type for Int{self._bitwidth} scalar"
|
|
46
|
+
) from e
|
|
47
|
+
else:
|
|
48
|
+
raise ScalarInvalidTypeError(
|
|
49
|
+
f"Invalid type {type(value)} for Int{self._bitwidth} scalar"
|
|
50
|
+
)
|
|
51
|
+
if val < self._min or val >= self._max:
|
|
52
|
+
raise ScalarInvalidTypeError(
|
|
53
|
+
f"Invalid Int{self._bitwidth} scalar with value {val}"
|
|
54
|
+
)
|
|
55
|
+
self._value = val
|
|
56
|
+
self._valid = True
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from cloudquery.sdk.scalar import Scalar, ScalarInvalidTypeError
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class JSON(Scalar):
|
|
6
|
+
def __eq__(self, scalar: Scalar) -> bool:
|
|
7
|
+
if scalar is None:
|
|
8
|
+
return False
|
|
9
|
+
if isinstance(scalar, JSON):
|
|
10
|
+
return self._value == scalar._value and self._valid == scalar._valid
|
|
11
|
+
return False
|
|
12
|
+
|
|
13
|
+
@property
|
|
14
|
+
def value(self):
|
|
15
|
+
return self._value
|
|
16
|
+
|
|
17
|
+
def set(self, value: any):
|
|
18
|
+
if value is None:
|
|
19
|
+
return
|
|
20
|
+
|
|
21
|
+
if isinstance(value, (str, bytes)):
|
|
22
|
+
# test if it is a valid json
|
|
23
|
+
json.loads(value)
|
|
24
|
+
self._value = value
|
|
25
|
+
else:
|
|
26
|
+
self._value = json.dumps(value)
|
|
27
|
+
self._valid = True
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
from cloudquery.sdk.scalar import Scalar, ScalarInvalidTypeError
|
|
2
|
+
from .scalar import NULL_VALUE
|
|
3
|
+
from .vector import Vector
|
|
4
|
+
from typing import Any, Type
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class List(Scalar):
|
|
8
|
+
def __init__(self, scalar_type: Type[Scalar]):
|
|
9
|
+
super().__init__(False, None)
|
|
10
|
+
self._value = Vector(scalar_type)
|
|
11
|
+
self._type = scalar_type
|
|
12
|
+
|
|
13
|
+
def __eq__(self, other: "List") -> bool:
|
|
14
|
+
if (not isinstance(other, self.__class__)) or self._valid != other._valid:
|
|
15
|
+
return False
|
|
16
|
+
return self._value == other._value
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def type(self):
|
|
20
|
+
return self._type
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def value(self):
|
|
24
|
+
return self._value
|
|
25
|
+
|
|
26
|
+
def set(self, value: Any):
|
|
27
|
+
if value is None:
|
|
28
|
+
self._valid = False
|
|
29
|
+
self._value = Vector()
|
|
30
|
+
return
|
|
31
|
+
|
|
32
|
+
if isinstance(value, self._type):
|
|
33
|
+
if not value.is_valid:
|
|
34
|
+
self._valid = False
|
|
35
|
+
self._value = Vector()
|
|
36
|
+
return
|
|
37
|
+
return self.set([value.value])
|
|
38
|
+
|
|
39
|
+
if isinstance(value, (list, tuple)):
|
|
40
|
+
self._value = Vector()
|
|
41
|
+
for item in value:
|
|
42
|
+
scalar = self._type()
|
|
43
|
+
scalar.set(item)
|
|
44
|
+
self._value.append(scalar)
|
|
45
|
+
self._valid = True
|
|
46
|
+
return
|
|
47
|
+
|
|
48
|
+
raise ScalarInvalidTypeError(f"Invalid type {type(value)} for List")
|
|
49
|
+
|
|
50
|
+
def __str__(self) -> str:
|
|
51
|
+
if not self._valid:
|
|
52
|
+
return NULL_VALUE
|
|
53
|
+
return f"[{', '.join(str(v) for v in self._value)}]"
|
|
54
|
+
|
|
55
|
+
def __len__(self):
|
|
56
|
+
return len(self.value.data)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
|
|
3
|
+
NULL_VALUE = "null"
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ScalarInvalidTypeError(Exception):
|
|
7
|
+
pass
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Scalar:
|
|
11
|
+
def __init__(self, valid: bool = False, value: any = None):
|
|
12
|
+
self._valid = valid
|
|
13
|
+
self._value = None
|
|
14
|
+
self.set(value)
|
|
15
|
+
|
|
16
|
+
@property
|
|
17
|
+
def is_valid(self) -> bool:
|
|
18
|
+
return self._valid
|
|
19
|
+
|
|
20
|
+
def __str__(self) -> str:
|
|
21
|
+
return str(self._value) if self._valid else NULL_VALUE
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
@abstractmethod
|
|
25
|
+
def value(self):
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
@abstractmethod
|
|
29
|
+
def set(self, value: any):
|
|
30
|
+
pass
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
from functools import partial
|
|
2
|
+
|
|
3
|
+
import pyarrow as pa
|
|
4
|
+
|
|
5
|
+
from cloudquery.sdk.types import UUIDType, JSONType
|
|
6
|
+
from .binary import Binary
|
|
7
|
+
from .bool import Bool
|
|
8
|
+
from .date32 import Date32
|
|
9
|
+
from .date64 import Date64
|
|
10
|
+
from .float import Float
|
|
11
|
+
from .int import Int
|
|
12
|
+
from .json import JSON
|
|
13
|
+
from .list import List
|
|
14
|
+
from .scalar import ScalarInvalidTypeError
|
|
15
|
+
from .string import String
|
|
16
|
+
from .timestamp import Timestamp
|
|
17
|
+
from .uint import Uint
|
|
18
|
+
from .uuid import UUID
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class ScalarFactory:
|
|
22
|
+
def __init__(self):
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
def new_scalar(self, dt: pa.DataType):
|
|
26
|
+
dt_id = dt.id
|
|
27
|
+
type_id__map = {
|
|
28
|
+
pa.types.lib.Type_INT64: partial(Int, bitwidth=64),
|
|
29
|
+
pa.types.lib.Type_INT32: partial(Int, bitwidth=32),
|
|
30
|
+
pa.types.lib.Type_INT16: partial(Int, bitwidth=16),
|
|
31
|
+
pa.types.lib.Type_INT8: partial(Int, bitwidth=8),
|
|
32
|
+
pa.types.lib.Type_UINT64: partial(Uint, bitwidth=64),
|
|
33
|
+
pa.types.lib.Type_UINT32: partial(Uint, bitwidth=32),
|
|
34
|
+
pa.types.lib.Type_UINT16: partial(Uint, bitwidth=16),
|
|
35
|
+
pa.types.lib.Type_UINT8: partial(Uint, bitwidth=8),
|
|
36
|
+
pa.types.lib.Type_BINARY: Binary,
|
|
37
|
+
pa.types.lib.Type_LARGE_BINARY: Binary,
|
|
38
|
+
pa.types.lib.Type_FIXED_SIZE_BINARY: Binary,
|
|
39
|
+
pa.types.lib.Type_BOOL: Bool,
|
|
40
|
+
pa.types.lib.Type_DATE64: Date64,
|
|
41
|
+
pa.types.lib.Type_DATE32: Date32,
|
|
42
|
+
pa.types.lib.Type_DOUBLE: partial(Float, bitwidth=64),
|
|
43
|
+
pa.types.lib.Type_FLOAT: partial(Float, bitwidth=32),
|
|
44
|
+
pa.types.lib.Type_HALF_FLOAT: partial(Float, bitwidth=16),
|
|
45
|
+
pa.types.lib.Type_LIST: List,
|
|
46
|
+
pa.types.lib.Type_LARGE_LIST: List,
|
|
47
|
+
pa.types.lib.Type_FIXED_SIZE_LIST: List,
|
|
48
|
+
pa.types.lib.Type_STRING: String,
|
|
49
|
+
pa.types.lib.Type_LARGE_STRING: String,
|
|
50
|
+
pa.types.lib.Type_TIMESTAMP: Timestamp,
|
|
51
|
+
}
|
|
52
|
+
# Built-in Types
|
|
53
|
+
if dt_id in type_id__map:
|
|
54
|
+
scalar_type = type_id__map[dt_id]
|
|
55
|
+
if scalar_type == List:
|
|
56
|
+
item = self.new_scalar(dt.field(0).type)
|
|
57
|
+
return scalar_type(type(item))
|
|
58
|
+
return scalar_type()
|
|
59
|
+
# Extension Types - Can't do the same trick as above as they don't have `id`s and they are not hashable. :(
|
|
60
|
+
if dt == UUIDType():
|
|
61
|
+
return UUID()
|
|
62
|
+
if dt == JSONType():
|
|
63
|
+
return JSON()
|
|
64
|
+
raise ScalarInvalidTypeError(f"Invalid type {dt} for scalar")
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from cloudquery.sdk.scalar import Scalar, ScalarInvalidTypeError
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class String(Scalar):
|
|
5
|
+
def __eq__(self, scalar: Scalar) -> bool:
|
|
6
|
+
if scalar is None:
|
|
7
|
+
return False
|
|
8
|
+
if isinstance(scalar, String):
|
|
9
|
+
return self._value == scalar._value and self._valid == scalar._valid
|
|
10
|
+
return False
|
|
11
|
+
|
|
12
|
+
@property
|
|
13
|
+
def value(self):
|
|
14
|
+
return self._value
|
|
15
|
+
|
|
16
|
+
def set(self, value: any):
|
|
17
|
+
if value is None:
|
|
18
|
+
return
|
|
19
|
+
|
|
20
|
+
if isinstance(value, String):
|
|
21
|
+
self._valid = value._valid
|
|
22
|
+
self._value = value.value
|
|
23
|
+
return
|
|
24
|
+
|
|
25
|
+
if isinstance(value, str):
|
|
26
|
+
self._valid = True
|
|
27
|
+
self._value = value
|
|
28
|
+
else:
|
|
29
|
+
raise ScalarInvalidTypeError(
|
|
30
|
+
f"Invalid type {type(value)} for String scalar"
|
|
31
|
+
)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from cloudquery.sdk.scalar import Scalar, ScalarInvalidTypeError, NULL_VALUE
|
|
2
|
+
from datetime import datetime, time
|
|
3
|
+
from typing import Any
|
|
4
|
+
import pandas as pd
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Timestamp(Scalar):
|
|
8
|
+
def __eq__(self, scalar: Scalar) -> bool:
|
|
9
|
+
if scalar is None:
|
|
10
|
+
return False
|
|
11
|
+
if isinstance(scalar, Timestamp):
|
|
12
|
+
return self._value == scalar._value and self._valid == scalar._valid
|
|
13
|
+
return False
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def value(self):
|
|
17
|
+
return self._value
|
|
18
|
+
|
|
19
|
+
def set(self, value: Any):
|
|
20
|
+
if value is None:
|
|
21
|
+
return
|
|
22
|
+
|
|
23
|
+
if isinstance(value, Timestamp):
|
|
24
|
+
self._valid = value.is_valid
|
|
25
|
+
self._value = value.value
|
|
26
|
+
return
|
|
27
|
+
|
|
28
|
+
if isinstance(value, pd.Timestamp):
|
|
29
|
+
self._value = value
|
|
30
|
+
elif isinstance(value, datetime):
|
|
31
|
+
self._value = pd.to_datetime(value)
|
|
32
|
+
elif isinstance(value, str):
|
|
33
|
+
self._value = pd.to_datetime(value)
|
|
34
|
+
elif isinstance(value, time):
|
|
35
|
+
self._value = pd.to_datetime(datetime.combine(datetime.today(), value))
|
|
36
|
+
else:
|
|
37
|
+
raise ScalarInvalidTypeError(
|
|
38
|
+
f"Invalid type {type(value)} for Timestamp scalar"
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
self._valid = True
|