vastdb 1.3.2__py3-none-any.whl → 1.3.3__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.
- vast_flatbuf/tabular/CreateViewRequest.py +104 -0
- vast_flatbuf/tabular/ListViewsResponse.py +89 -0
- vast_flatbuf/tabular/ObjectDetails.py +23 -1
- vastdb/_internal.py +70 -6
- vastdb/schema.py +1 -2
- vastdb/table.py +6 -2
- vastdb/tests/test_sanity.py +14 -10
- vastdb/tests/test_tables.py +83 -2
- {vastdb-1.3.2.dist-info → vastdb-1.3.3.dist-info}/METADATA +1 -1
- {vastdb-1.3.2.dist-info → vastdb-1.3.3.dist-info}/RECORD +13 -11
- {vastdb-1.3.2.dist-info → vastdb-1.3.3.dist-info}/LICENSE +0 -0
- {vastdb-1.3.2.dist-info → vastdb-1.3.3.dist-info}/WHEEL +0 -0
- {vastdb-1.3.2.dist-info → vastdb-1.3.3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# automatically generated by the FlatBuffers compiler, do not modify
|
|
2
|
+
|
|
3
|
+
# namespace: tabular
|
|
4
|
+
|
|
5
|
+
import flatbuffers
|
|
6
|
+
from flatbuffers.compat import import_numpy
|
|
7
|
+
np = import_numpy()
|
|
8
|
+
|
|
9
|
+
class CreateViewRequest(object):
|
|
10
|
+
__slots__ = ['_tab']
|
|
11
|
+
|
|
12
|
+
@classmethod
|
|
13
|
+
def GetRootAs(cls, buf, offset=0):
|
|
14
|
+
n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
|
|
15
|
+
x = CreateViewRequest()
|
|
16
|
+
x.Init(buf, n + offset)
|
|
17
|
+
return x
|
|
18
|
+
|
|
19
|
+
@classmethod
|
|
20
|
+
def GetRootAsCreateViewRequest(cls, buf, offset=0):
|
|
21
|
+
"""This method is deprecated. Please switch to GetRootAs."""
|
|
22
|
+
return cls.GetRootAs(buf, offset)
|
|
23
|
+
# CreateViewRequest
|
|
24
|
+
def Init(self, buf, pos):
|
|
25
|
+
self._tab = flatbuffers.table.Table(buf, pos)
|
|
26
|
+
|
|
27
|
+
# CreateViewRequest
|
|
28
|
+
def ViewMetadataArrowBuffer(self, j):
|
|
29
|
+
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
|
|
30
|
+
if o != 0:
|
|
31
|
+
a = self._tab.Vector(o)
|
|
32
|
+
return self._tab.Get(flatbuffers.number_types.Uint8Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 1))
|
|
33
|
+
return 0
|
|
34
|
+
|
|
35
|
+
# CreateViewRequest
|
|
36
|
+
def ViewMetadataArrowBufferAsNumpy(self):
|
|
37
|
+
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
|
|
38
|
+
if o != 0:
|
|
39
|
+
return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint8Flags, o)
|
|
40
|
+
return 0
|
|
41
|
+
|
|
42
|
+
# CreateViewRequest
|
|
43
|
+
def ViewMetadataArrowBufferLength(self):
|
|
44
|
+
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
|
|
45
|
+
if o != 0:
|
|
46
|
+
return self._tab.VectorLen(o)
|
|
47
|
+
return 0
|
|
48
|
+
|
|
49
|
+
# CreateViewRequest
|
|
50
|
+
def ViewMetadataArrowBufferIsNone(self):
|
|
51
|
+
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
|
|
52
|
+
return o == 0
|
|
53
|
+
|
|
54
|
+
# CreateViewRequest
|
|
55
|
+
def ViewDataArrowSchema(self, j):
|
|
56
|
+
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
|
|
57
|
+
if o != 0:
|
|
58
|
+
a = self._tab.Vector(o)
|
|
59
|
+
return self._tab.Get(flatbuffers.number_types.Uint8Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 1))
|
|
60
|
+
return 0
|
|
61
|
+
|
|
62
|
+
# CreateViewRequest
|
|
63
|
+
def ViewDataArrowSchemaAsNumpy(self):
|
|
64
|
+
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
|
|
65
|
+
if o != 0:
|
|
66
|
+
return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint8Flags, o)
|
|
67
|
+
return 0
|
|
68
|
+
|
|
69
|
+
# CreateViewRequest
|
|
70
|
+
def ViewDataArrowSchemaLength(self):
|
|
71
|
+
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
|
|
72
|
+
if o != 0:
|
|
73
|
+
return self._tab.VectorLen(o)
|
|
74
|
+
return 0
|
|
75
|
+
|
|
76
|
+
# CreateViewRequest
|
|
77
|
+
def ViewDataArrowSchemaIsNone(self):
|
|
78
|
+
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
|
|
79
|
+
return o == 0
|
|
80
|
+
|
|
81
|
+
def Start(builder): builder.StartObject(2)
|
|
82
|
+
def CreateViewRequestStart(builder):
|
|
83
|
+
"""This method is deprecated. Please switch to Start."""
|
|
84
|
+
return Start(builder)
|
|
85
|
+
def AddViewMetadataArrowBuffer(builder, viewMetadataArrowBuffer): builder.PrependUOffsetTRelativeSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(viewMetadataArrowBuffer), 0)
|
|
86
|
+
def CreateViewRequestAddViewMetadataArrowBuffer(builder, viewMetadataArrowBuffer):
|
|
87
|
+
"""This method is deprecated. Please switch to AddViewMetadataArrowBuffer."""
|
|
88
|
+
return AddViewMetadataArrowBuffer(builder, viewMetadataArrowBuffer)
|
|
89
|
+
def StartViewMetadataArrowBufferVector(builder, numElems): return builder.StartVector(1, numElems, 1)
|
|
90
|
+
def CreateViewRequestStartViewMetadataArrowBufferVector(builder, numElems):
|
|
91
|
+
"""This method is deprecated. Please switch to Start."""
|
|
92
|
+
return StartViewMetadataArrowBufferVector(builder, numElems)
|
|
93
|
+
def AddViewDataArrowSchema(builder, viewDataArrowSchema): builder.PrependUOffsetTRelativeSlot(1, flatbuffers.number_types.UOffsetTFlags.py_type(viewDataArrowSchema), 0)
|
|
94
|
+
def CreateViewRequestAddViewDataArrowSchema(builder, viewDataArrowSchema):
|
|
95
|
+
"""This method is deprecated. Please switch to AddViewDataArrowSchema."""
|
|
96
|
+
return AddViewDataArrowSchema(builder, viewDataArrowSchema)
|
|
97
|
+
def StartViewDataArrowSchemaVector(builder, numElems): return builder.StartVector(1, numElems, 1)
|
|
98
|
+
def CreateViewRequestStartViewDataArrowSchemaVector(builder, numElems):
|
|
99
|
+
"""This method is deprecated. Please switch to Start."""
|
|
100
|
+
return StartViewDataArrowSchemaVector(builder, numElems)
|
|
101
|
+
def End(builder): return builder.EndObject()
|
|
102
|
+
def CreateViewRequestEnd(builder):
|
|
103
|
+
"""This method is deprecated. Please switch to End."""
|
|
104
|
+
return End(builder)
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# automatically generated by the FlatBuffers compiler, do not modify
|
|
2
|
+
|
|
3
|
+
# namespace: tabular
|
|
4
|
+
|
|
5
|
+
import flatbuffers
|
|
6
|
+
from flatbuffers.compat import import_numpy
|
|
7
|
+
np = import_numpy()
|
|
8
|
+
|
|
9
|
+
class ListViewsResponse(object):
|
|
10
|
+
__slots__ = ['_tab']
|
|
11
|
+
|
|
12
|
+
@classmethod
|
|
13
|
+
def GetRootAs(cls, buf, offset=0):
|
|
14
|
+
n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
|
|
15
|
+
x = ListViewsResponse()
|
|
16
|
+
x.Init(buf, n + offset)
|
|
17
|
+
return x
|
|
18
|
+
|
|
19
|
+
@classmethod
|
|
20
|
+
def GetRootAsListViewsResponse(cls, buf, offset=0):
|
|
21
|
+
"""This method is deprecated. Please switch to GetRootAs."""
|
|
22
|
+
return cls.GetRootAs(buf, offset)
|
|
23
|
+
# ListViewsResponse
|
|
24
|
+
def Init(self, buf, pos):
|
|
25
|
+
self._tab = flatbuffers.table.Table(buf, pos)
|
|
26
|
+
|
|
27
|
+
# ListViewsResponse
|
|
28
|
+
def BucketName(self):
|
|
29
|
+
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
|
|
30
|
+
if o != 0:
|
|
31
|
+
return self._tab.String(o + self._tab.Pos)
|
|
32
|
+
return None
|
|
33
|
+
|
|
34
|
+
# ListViewsResponse
|
|
35
|
+
def SchemaName(self):
|
|
36
|
+
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
|
|
37
|
+
if o != 0:
|
|
38
|
+
return self._tab.String(o + self._tab.Pos)
|
|
39
|
+
return None
|
|
40
|
+
|
|
41
|
+
# ListViewsResponse
|
|
42
|
+
def Views(self, j):
|
|
43
|
+
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
|
|
44
|
+
if o != 0:
|
|
45
|
+
x = self._tab.Vector(o)
|
|
46
|
+
x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * 4
|
|
47
|
+
x = self._tab.Indirect(x)
|
|
48
|
+
from vast_flatbuf.tabular.ObjectDetails import ObjectDetails
|
|
49
|
+
obj = ObjectDetails()
|
|
50
|
+
obj.Init(self._tab.Bytes, x)
|
|
51
|
+
return obj
|
|
52
|
+
return None
|
|
53
|
+
|
|
54
|
+
# ListViewsResponse
|
|
55
|
+
def ViewsLength(self):
|
|
56
|
+
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
|
|
57
|
+
if o != 0:
|
|
58
|
+
return self._tab.VectorLen(o)
|
|
59
|
+
return 0
|
|
60
|
+
|
|
61
|
+
# ListViewsResponse
|
|
62
|
+
def ViewsIsNone(self):
|
|
63
|
+
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
|
|
64
|
+
return o == 0
|
|
65
|
+
|
|
66
|
+
def Start(builder): builder.StartObject(3)
|
|
67
|
+
def ListViewsResponseStart(builder):
|
|
68
|
+
"""This method is deprecated. Please switch to Start."""
|
|
69
|
+
return Start(builder)
|
|
70
|
+
def AddBucketName(builder, bucketName): builder.PrependUOffsetTRelativeSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(bucketName), 0)
|
|
71
|
+
def ListViewsResponseAddBucketName(builder, bucketName):
|
|
72
|
+
"""This method is deprecated. Please switch to AddBucketName."""
|
|
73
|
+
return AddBucketName(builder, bucketName)
|
|
74
|
+
def AddSchemaName(builder, schemaName): builder.PrependUOffsetTRelativeSlot(1, flatbuffers.number_types.UOffsetTFlags.py_type(schemaName), 0)
|
|
75
|
+
def ListViewsResponseAddSchemaName(builder, schemaName):
|
|
76
|
+
"""This method is deprecated. Please switch to AddSchemaName."""
|
|
77
|
+
return AddSchemaName(builder, schemaName)
|
|
78
|
+
def AddViews(builder, views): builder.PrependUOffsetTRelativeSlot(2, flatbuffers.number_types.UOffsetTFlags.py_type(views), 0)
|
|
79
|
+
def ListViewsResponseAddViews(builder, views):
|
|
80
|
+
"""This method is deprecated. Please switch to AddViews."""
|
|
81
|
+
return AddViews(builder, views)
|
|
82
|
+
def StartViewsVector(builder, numElems): return builder.StartVector(4, numElems, 4)
|
|
83
|
+
def ListViewsResponseStartViewsVector(builder, numElems):
|
|
84
|
+
"""This method is deprecated. Please switch to Start."""
|
|
85
|
+
return StartViewsVector(builder, numElems)
|
|
86
|
+
def End(builder): return builder.EndObject()
|
|
87
|
+
def ListViewsResponseEnd(builder):
|
|
88
|
+
"""This method is deprecated. Please switch to End."""
|
|
89
|
+
return End(builder)
|
|
@@ -60,7 +60,21 @@ class ObjectDetails(object):
|
|
|
60
60
|
return self._tab.Get(flatbuffers.number_types.Uint64Flags, o + self._tab.Pos)
|
|
61
61
|
return 0
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
# ObjectDetails
|
|
64
|
+
def NumPartitions(self):
|
|
65
|
+
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(14))
|
|
66
|
+
if o != 0:
|
|
67
|
+
return self._tab.Get(flatbuffers.number_types.Uint64Flags, o + self._tab.Pos)
|
|
68
|
+
return 0
|
|
69
|
+
|
|
70
|
+
# ObjectDetails
|
|
71
|
+
def SortingKeyEnabled(self):
|
|
72
|
+
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(16))
|
|
73
|
+
if o != 0:
|
|
74
|
+
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
|
|
75
|
+
return False
|
|
76
|
+
|
|
77
|
+
def Start(builder): builder.StartObject(7)
|
|
64
78
|
def ObjectDetailsStart(builder):
|
|
65
79
|
"""This method is deprecated. Please switch to Start."""
|
|
66
80
|
return Start(builder)
|
|
@@ -84,6 +98,14 @@ def AddSizeInBytes(builder, sizeInBytes): builder.PrependUint64Slot(4, sizeInByt
|
|
|
84
98
|
def ObjectDetailsAddSizeInBytes(builder, sizeInBytes):
|
|
85
99
|
"""This method is deprecated. Please switch to AddSizeInBytes."""
|
|
86
100
|
return AddSizeInBytes(builder, sizeInBytes)
|
|
101
|
+
def AddNumPartitions(builder, numPartitions): builder.PrependUint64Slot(5, numPartitions, 0)
|
|
102
|
+
def ObjectDetailsAddNumPartitions(builder, numPartitions):
|
|
103
|
+
"""This method is deprecated. Please switch to AddNumPartitions."""
|
|
104
|
+
return AddNumPartitions(builder, numPartitions)
|
|
105
|
+
def AddSortingKeyEnabled(builder, sortingKeyEnabled): builder.PrependBoolSlot(6, sortingKeyEnabled, 0)
|
|
106
|
+
def ObjectDetailsAddSortingKeyEnabled(builder, sortingKeyEnabled):
|
|
107
|
+
"""This method is deprecated. Please switch to AddSortingKeyEnabled."""
|
|
108
|
+
return AddSortingKeyEnabled(builder, sortingKeyEnabled)
|
|
87
109
|
def End(builder): return builder.EndObject()
|
|
88
110
|
def ObjectDetailsEnd(builder):
|
|
89
111
|
"""This method is deprecated. Please switch to End."""
|
vastdb/_internal.py
CHANGED
|
@@ -735,17 +735,57 @@ def _iter_nested_arrays(column: pa.Array) -> Iterator[pa.Array]:
|
|
|
735
735
|
yield from _iter_nested_arrays(column.values) # Note: Map is serialized in VAST as a List<Struct<K, V>>
|
|
736
736
|
|
|
737
737
|
|
|
738
|
-
|
|
738
|
+
class ValidateInList:
|
|
739
|
+
def __init__(self, *args):
|
|
740
|
+
self.candidates = [x.strip() for x in args]
|
|
739
741
|
|
|
742
|
+
def __call__(self, x):
|
|
743
|
+
x = x.strip()
|
|
744
|
+
if x not in self.candidates:
|
|
745
|
+
raise Exception(f'{x} is not in {self.candidates}')
|
|
746
|
+
return x
|
|
747
|
+
|
|
748
|
+
def __getitem__(self, x):
|
|
749
|
+
return self
|
|
750
|
+
|
|
751
|
+
|
|
752
|
+
_int_coding = (lambda x: str(int(x)), lambda x: int(x))
|
|
753
|
+
_prop_coding = {
|
|
754
|
+
"message.timestamp.type": ValidateInList('CreateTime', 'LogAppendTime'),
|
|
755
|
+
"retention.ms": _int_coding,
|
|
756
|
+
"message.timestamp.after.max.ms": _int_coding,
|
|
757
|
+
"message.timestamp.before.max.ms": _int_coding
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
|
|
761
|
+
def _encode_table_props(**kwargs):
|
|
762
|
+
if all([v is None for v in kwargs.values()]):
|
|
763
|
+
return None
|
|
764
|
+
else:
|
|
765
|
+
pairs = [(k.replace("_", ".").strip(), v) for k, v in kwargs.items() if v is not None]
|
|
766
|
+
return "$".join([f"{k}={_prop_coding[k][0](v)}" for k, v in pairs])
|
|
767
|
+
|
|
768
|
+
|
|
769
|
+
def _decode_table_props(s):
|
|
770
|
+
if s.strip() == '':
|
|
771
|
+
return {}
|
|
772
|
+
triplets = [(x.strip(), x.strip().replace(".", "_"), y.strip()) for x, y in [z.split('=') for z in s.strip().split("$")]]
|
|
773
|
+
return {y: _prop_coding[x][1](z) for x, y, z in triplets if z != ''}
|
|
740
774
|
|
|
741
|
-
def _parse_table_info(obj):
|
|
742
775
|
|
|
776
|
+
TableInfo = namedtuple('TableInfo', 'name properties handle num_rows size_in_bytes num_partitions')
|
|
777
|
+
|
|
778
|
+
|
|
779
|
+
def _parse_table_info(obj):
|
|
743
780
|
name = obj.Name().decode()
|
|
744
781
|
properties = obj.Properties().decode()
|
|
745
782
|
handle = obj.Handle().decode()
|
|
746
783
|
num_rows = obj.NumRows()
|
|
747
784
|
used_bytes = obj.SizeInBytes()
|
|
748
|
-
|
|
785
|
+
num_partitions = obj.NumPartitions()
|
|
786
|
+
if num_partitions != 0:
|
|
787
|
+
properties = _decode_table_props(properties)
|
|
788
|
+
return TableInfo(name, properties, handle, num_rows, used_bytes, num_partitions)
|
|
749
789
|
|
|
750
790
|
|
|
751
791
|
# Results that returns from tablestats
|
|
@@ -774,7 +814,13 @@ def _backoff_giveup(exc: Exception) -> bool:
|
|
|
774
814
|
return True # give up in case of other exceptions
|
|
775
815
|
|
|
776
816
|
|
|
817
|
+
class UnsupportedServer(NotImplementedError):
|
|
818
|
+
"""Raised when the response comes back from non-VAST DB server."""
|
|
819
|
+
pass
|
|
820
|
+
|
|
821
|
+
|
|
777
822
|
class VastdbApi:
|
|
823
|
+
VAST_SERVER_PREFIX = 'vast'
|
|
778
824
|
# we expect the vast version to be <major>.<minor>.<patch>.<protocol>
|
|
779
825
|
VAST_VERSION_REGEX = re.compile(r'^vast (\d+\.\d+\.\d+\.\d+)$')
|
|
780
826
|
|
|
@@ -829,6 +875,9 @@ class VastdbApi:
|
|
|
829
875
|
if server_header is None:
|
|
830
876
|
_logger.error("Response doesn't contain 'Server' header")
|
|
831
877
|
else:
|
|
878
|
+
if not server_header.startswith(self.VAST_SERVER_PREFIX):
|
|
879
|
+
raise UnsupportedServer(f'{self.url} is not a VAST DB server endpoint ("{server_header}")')
|
|
880
|
+
|
|
832
881
|
if m := self.VAST_VERSION_REGEX.match(server_header):
|
|
833
882
|
self.vast_version: Tuple[int, ...] = tuple(int(v) for v in m.group(1).split("."))
|
|
834
883
|
return
|
|
@@ -1049,8 +1098,9 @@ class VastdbApi:
|
|
|
1049
1098
|
|
|
1050
1099
|
return snapshots, is_truncated, marker
|
|
1051
1100
|
|
|
1052
|
-
def create_table(self, bucket, schema, name, arrow_schema, txid=0, client_tags=[], expected_retvals=[],
|
|
1053
|
-
topic_partitions=0, create_imports_table=False, use_external_row_ids_allocation=False
|
|
1101
|
+
def create_table(self, bucket, schema, name, arrow_schema=None, txid=0, client_tags=[], expected_retvals=[],
|
|
1102
|
+
topic_partitions=0, create_imports_table=False, use_external_row_ids_allocation=False,
|
|
1103
|
+
message_timestamp_type=None, retention_ms=None, message_timestamp_after_max_ms=None, message_timestamp_before_max_ms=None):
|
|
1054
1104
|
"""
|
|
1055
1105
|
Create a table, use the following request
|
|
1056
1106
|
POST /bucket/schema/table?table HTTP/1.1
|
|
@@ -1069,6 +1119,9 @@ class VastdbApi:
|
|
|
1069
1119
|
"""
|
|
1070
1120
|
headers = self._fill_common_headers(txid=txid, client_tags=client_tags)
|
|
1071
1121
|
|
|
1122
|
+
if arrow_schema is None:
|
|
1123
|
+
arrow_schema = pa.schema([])
|
|
1124
|
+
|
|
1072
1125
|
serialized_schema = arrow_schema.serialize()
|
|
1073
1126
|
headers['Content-Length'] = str(len(serialized_schema))
|
|
1074
1127
|
if use_external_row_ids_allocation:
|
|
@@ -1078,6 +1131,11 @@ class VastdbApi:
|
|
|
1078
1131
|
if create_imports_table:
|
|
1079
1132
|
url_params['sub-table'] = IMPORTED_OBJECTS_TABLE_NAME
|
|
1080
1133
|
|
|
1134
|
+
if topic_partitions > 0:
|
|
1135
|
+
table_props = _encode_table_props(message_timestamp_type=message_timestamp_type, retention_ms=retention_ms, message_timestamp_after_max_ms=message_timestamp_after_max_ms, message_timestamp_before_max_ms=message_timestamp_before_max_ms)
|
|
1136
|
+
if table_props is not None:
|
|
1137
|
+
url_params['table-props'] = table_props
|
|
1138
|
+
|
|
1081
1139
|
self._request(
|
|
1082
1140
|
method="POST",
|
|
1083
1141
|
url=self._url(bucket=bucket, schema=schema, table=name, command="table", url_params=url_params),
|
|
@@ -1106,7 +1164,8 @@ class VastdbApi:
|
|
|
1106
1164
|
return TableStatsResult(num_rows, size_in_bytes, is_external_rowid_alloc, tuple(endpoints))
|
|
1107
1165
|
|
|
1108
1166
|
def alter_table(self, bucket, schema, name, txid=0, client_tags=[], table_properties="",
|
|
1109
|
-
new_name="", expected_retvals=[]
|
|
1167
|
+
new_name="", expected_retvals=[],
|
|
1168
|
+
message_timestamp_type=None, retention_ms=None, message_timestamp_after_max_ms=None, message_timestamp_before_max_ms=None):
|
|
1110
1169
|
"""
|
|
1111
1170
|
PUT /mybucket/myschema/mytable?table HTTP/1.1
|
|
1112
1171
|
Content-Length: ContentLength
|
|
@@ -1118,6 +1177,11 @@ class VastdbApi:
|
|
|
1118
1177
|
"""
|
|
1119
1178
|
builder = flatbuffers.Builder(1024)
|
|
1120
1179
|
|
|
1180
|
+
if message_timestamp_type is not None or retention_ms is not None or message_timestamp_after_max_ms is not None or message_timestamp_before_max_ms is not None:
|
|
1181
|
+
table_properties = _encode_table_props(message_timestamp_type=message_timestamp_type, retention_ms=retention_ms, message_timestamp_after_max_ms=message_timestamp_after_max_ms, message_timestamp_before_max_ms=message_timestamp_before_max_ms)
|
|
1182
|
+
if table_properties is None:
|
|
1183
|
+
table_properties = ""
|
|
1184
|
+
|
|
1121
1185
|
properties = builder.CreateString(table_properties)
|
|
1122
1186
|
tabular_alter_table.Start(builder)
|
|
1123
1187
|
if len(table_properties):
|
vastdb/schema.py
CHANGED
|
@@ -146,5 +146,4 @@ class Schema:
|
|
|
146
146
|
|
|
147
147
|
|
|
148
148
|
def _parse_table_info(table_info, schema: "schema.Schema"):
|
|
149
|
-
|
|
150
|
-
return table.Table(name=table_info.name, schema=schema, handle=int(table_info.handle), stats=stats, _imports_table=False)
|
|
149
|
+
return table.Table(name=table_info.name, schema=schema, handle=int(table_info.handle), _imports_table=False)
|
vastdb/table.py
CHANGED
|
@@ -112,7 +112,6 @@ class Table:
|
|
|
112
112
|
name: str
|
|
113
113
|
schema: "schema.Schema"
|
|
114
114
|
handle: int
|
|
115
|
-
stats: TableStats
|
|
116
115
|
arrow_schema: pa.Schema = field(init=False, compare=False, repr=False)
|
|
117
116
|
_ibis_table: ibis.Schema = field(init=False, compare=False, repr=False)
|
|
118
117
|
_imports_table: bool
|
|
@@ -139,6 +138,11 @@ class Table:
|
|
|
139
138
|
"""Return bucket."""
|
|
140
139
|
return self.schema.bucket
|
|
141
140
|
|
|
141
|
+
@property
|
|
142
|
+
def stats(self):
|
|
143
|
+
"""Fetch table's statistics from server."""
|
|
144
|
+
return self.get_stats()
|
|
145
|
+
|
|
142
146
|
def columns(self) -> pa.Schema:
|
|
143
147
|
"""Return columns' metadata."""
|
|
144
148
|
fields = []
|
|
@@ -576,7 +580,7 @@ class Table:
|
|
|
576
580
|
def imports_table(self) -> Optional["Table"]:
|
|
577
581
|
"""Get the imports table of this table."""
|
|
578
582
|
self.tx._rpc.features.check_imports_table()
|
|
579
|
-
return Table(name=self.name, schema=self.schema, handle=int(self.handle),
|
|
583
|
+
return Table(name=self.name, schema=self.schema, handle=int(self.handle), _imports_table=True)
|
|
580
584
|
|
|
581
585
|
def __getitem__(self, col_name):
|
|
582
586
|
"""Allow constructing ibis-like column expressions from this table.
|
vastdb/tests/test_sanity.py
CHANGED
|
@@ -7,6 +7,7 @@ from itertools import cycle
|
|
|
7
7
|
import pytest
|
|
8
8
|
|
|
9
9
|
import vastdb.errors
|
|
10
|
+
from vastdb._internal import UnsupportedServer
|
|
10
11
|
|
|
11
12
|
log = logging.getLogger(__name__)
|
|
12
13
|
|
|
@@ -32,13 +33,14 @@ def test_bad_endpoint(session):
|
|
|
32
33
|
def test_version_extraction():
|
|
33
34
|
# A list of version and expected version parsed by API
|
|
34
35
|
TEST_CASES = [
|
|
35
|
-
(
|
|
36
|
-
("
|
|
37
|
-
("5
|
|
38
|
-
("5.2
|
|
39
|
-
("5.2.0
|
|
40
|
-
("5.2.0.10
|
|
41
|
-
("5.2.0.10
|
|
36
|
+
("nginx", UnsupportedServer), # non-vast server
|
|
37
|
+
("vast", NotImplementedError), # vast server without version in header
|
|
38
|
+
("vast 5", NotImplementedError), # major
|
|
39
|
+
("vast 5.2", NotImplementedError), # major.minor
|
|
40
|
+
("vast 5.2.0", NotImplementedError), # major.minor.patch
|
|
41
|
+
("vast 5.2.0.10", (5, 2, 0, 10)), # major.minor.patch.protocol
|
|
42
|
+
("vast 5.2.0.10 some other things", NotImplementedError), # suffix
|
|
43
|
+
("vast 5.2.0.10.20", NotImplementedError), # extra version
|
|
42
44
|
]
|
|
43
45
|
|
|
44
46
|
# Mock OPTIONS handle that cycles through the test cases response
|
|
@@ -53,8 +55,7 @@ def test_version_extraction():
|
|
|
53
55
|
self.end_headers()
|
|
54
56
|
|
|
55
57
|
def version_string(self):
|
|
56
|
-
|
|
57
|
-
return f"vast {version}" if version else "vast"
|
|
58
|
+
return next(self.versions_iterator)[0]
|
|
58
59
|
|
|
59
60
|
def log_message(self, format, *args):
|
|
60
61
|
log.debug(format, *args)
|
|
@@ -74,7 +75,10 @@ def test_version_extraction():
|
|
|
74
75
|
|
|
75
76
|
try:
|
|
76
77
|
for _, expected in TEST_CASES:
|
|
77
|
-
|
|
78
|
+
manager = contextlib.nullcontext()
|
|
79
|
+
if isinstance(expected, type) and issubclass(expected, NotImplementedError):
|
|
80
|
+
manager = pytest.raises(expected)
|
|
81
|
+
with manager:
|
|
78
82
|
s = vastdb.connect(endpoint=f"http://localhost:{httpd.server_port}", access="abc", secret="abc")
|
|
79
83
|
assert s.api.vast_version == expected
|
|
80
84
|
finally:
|
vastdb/tests/test_tables.py
CHANGED
|
@@ -452,8 +452,8 @@ def test_filters(session, clean_bucket_name):
|
|
|
452
452
|
assert select((t['a'] > 111) | (t['a'] < 333) | (t['a'] == 777)) == expected.filter((pc.field('a') > 111) | (pc.field('a') < 333) | (pc.field('a') == 777))
|
|
453
453
|
|
|
454
454
|
assert select(t['s'].isnull()) == expected.filter(pc.field('s').is_null())
|
|
455
|
-
assert select((t['s'].isnull()) | (t['s'] == 'bb'))
|
|
456
|
-
assert select((t['s'].isnull()) & (t['b'] == 3.5))
|
|
455
|
+
assert select((t['s'].isnull()) | (t['s'] == 'bb')) == expected.filter((pc.field('s').is_null()) | (pc.field('s') == 'bb'))
|
|
456
|
+
assert select((t['s'].isnull()) & (t['b'] == 3.5)) == expected.filter((pc.field('s').is_null()) & (pc.field('b') == 3.5))
|
|
457
457
|
|
|
458
458
|
assert select(~t['s'].isnull()) == expected.filter(~pc.field('s').is_null())
|
|
459
459
|
assert select(t['s'].contains('b')) == expected.filter(pc.field('s') == 'bb')
|
|
@@ -882,3 +882,84 @@ def test_starts_with(session, clean_bucket_name):
|
|
|
882
882
|
|
|
883
883
|
res = table.select(predicate=(table['s'].startswith('ab')) & (table['i'] > 3)).read_all()
|
|
884
884
|
assert res.to_pydict() == {'i': [4], 's': ['abd']}
|
|
885
|
+
|
|
886
|
+
|
|
887
|
+
def test_external_row_id(session, clean_bucket_name):
|
|
888
|
+
columns = [
|
|
889
|
+
('vastdb_rowid', pa.int64()),
|
|
890
|
+
('x', pa.float32()),
|
|
891
|
+
('y', pa.utf8()),
|
|
892
|
+
]
|
|
893
|
+
|
|
894
|
+
with session.transaction() as tx:
|
|
895
|
+
s = tx.bucket(clean_bucket_name).create_schema('s')
|
|
896
|
+
|
|
897
|
+
t = s.create_table('t1', pa.schema(columns))
|
|
898
|
+
assert not t.stats.is_external_rowid_alloc
|
|
899
|
+
t.insert(pa.record_batch(schema=pa.schema(columns), data=[[0], [1.5], ['ABC']]))
|
|
900
|
+
assert t.stats.is_external_rowid_alloc
|
|
901
|
+
|
|
902
|
+
t = s.create_table('t2', pa.schema(columns))
|
|
903
|
+
assert not t.stats.is_external_rowid_alloc
|
|
904
|
+
t.insert(pa.record_batch(schema=pa.schema(columns[1:]), data=[[1.5], ['ABC']]))
|
|
905
|
+
assert not t.stats.is_external_rowid_alloc
|
|
906
|
+
|
|
907
|
+
|
|
908
|
+
def test_multiple_contains_clauses(session, clean_bucket_name):
|
|
909
|
+
columns = pa.schema([
|
|
910
|
+
('theint', pa.int32()),
|
|
911
|
+
('thestring', pa.string()),
|
|
912
|
+
('theotherstring', pa.string()),
|
|
913
|
+
])
|
|
914
|
+
|
|
915
|
+
expected = pa.table(schema=columns, data=[
|
|
916
|
+
[111, 222, 333, 444, 555],
|
|
917
|
+
['abc', 'efg', 'hij', 'klm', 'nop'],
|
|
918
|
+
['abcd', 'bcde', 'cdef', 'defg', 'efgh'],
|
|
919
|
+
])
|
|
920
|
+
with (prepare_data(session, clean_bucket_name, 's', 't', expected) as t):
|
|
921
|
+
failed_preds = [
|
|
922
|
+
lambda t: (t["thestring"].contains("b") | t["theotherstring"].contains("a")),
|
|
923
|
+
lambda t: (~t["thestring"].contains("a")),
|
|
924
|
+
]
|
|
925
|
+
|
|
926
|
+
assert t.select(predicate=t["thestring"].contains("b")).read_all() == expected.filter(pc.match_substring(expected["thestring"], "b"))
|
|
927
|
+
assert (t.select(predicate=(t["thestring"].contains("b")) & (t["theotherstring"].startswith("a"))).read_all() ==
|
|
928
|
+
expected.filter(pc.and_(
|
|
929
|
+
pc.match_substring(expected["thestring"], "b"),
|
|
930
|
+
pc.starts_with(expected["thestring"], "a")
|
|
931
|
+
)))
|
|
932
|
+
assert (t.select(predicate=(t["thestring"].contains("b") & (t["thestring"].contains("y")))).read_all() ==
|
|
933
|
+
t.select(predicate=t["thestring"].contains("y") & (t["thestring"].contains("b"))).read_all())
|
|
934
|
+
|
|
935
|
+
assert (t.select(predicate=(t["thestring"].contains("o") & (t["theint"] > 500))).read_all() ==
|
|
936
|
+
pc.filter(expected, pc.and_(
|
|
937
|
+
pc.match_substring(expected["thestring"], "o"),
|
|
938
|
+
pc.greater(expected["theint"], 500)
|
|
939
|
+
)))
|
|
940
|
+
assert (t.select(predicate=((t["thestring"].contains("bc")) | (t["thestring"].contains("kl")) |
|
|
941
|
+
(t["thestring"] == "hi") | (t["thestring"].startswith("e")))).read_all() ==
|
|
942
|
+
expected.filter(
|
|
943
|
+
pc.or_(pc.or_(pc.match_substring(expected["thestring"], "bc"),
|
|
944
|
+
pc.match_substring(expected["thestring"], "kl")),
|
|
945
|
+
pc.or_(pc.equal(expected["thestring"], "hi"),
|
|
946
|
+
pc.starts_with(expected["thestring"], "e"))
|
|
947
|
+
)))
|
|
948
|
+
assert (t.select(predicate=((t["thestring"].contains("abc")) | (t["thestring"].contains("xyz")) |
|
|
949
|
+
(t["thestring"].startswith("z")) | (t["thestring"].isnull()))).read_all() ==
|
|
950
|
+
pc.filter(expected,
|
|
951
|
+
pc.or_(pc.or_(pc.match_substring(expected["thestring"], "abc"),
|
|
952
|
+
pc.match_substring(expected["thestring"], "xyz")),
|
|
953
|
+
pc.or_(pc.starts_with(expected["thestring"], "z"),
|
|
954
|
+
pc.is_null(expected["thestring"]))
|
|
955
|
+
)))
|
|
956
|
+
assert (t.select(predicate=((t["thestring"].contains("k")) & (t["theotherstring"].contains("h")) &
|
|
957
|
+
(t["theint"] > 500))).read_all() ==
|
|
958
|
+
pc.filter(expected, pc.and_(
|
|
959
|
+
pc.and_(pc.match_substring(expected["thestring"], "k"),
|
|
960
|
+
pc.match_substring(expected["theotherstring"], "h")),
|
|
961
|
+
pc.greater(expected["theint"], 500)
|
|
962
|
+
)))
|
|
963
|
+
for pred in failed_preds:
|
|
964
|
+
with pytest.raises(NotImplementedError):
|
|
965
|
+
t.select(predicate=pred(t)).read_all()
|
|
@@ -138,26 +138,28 @@ vast_flatbuf/tabular/Column.py,sha256=2iXTlN8pynb_Sf7n15k8n2uXP_8eoz2RqKrUbTBrIy
|
|
|
138
138
|
vast_flatbuf/tabular/ColumnType.py,sha256=_4-jMG08VR2zdn1ZH7F4aahYPxWsBSm7adUoVf-HFSU,151
|
|
139
139
|
vast_flatbuf/tabular/CreateProjectionRequest.py,sha256=POlK1DrYMAldNJscLIRL3j4jAT0Sv_fRzfvBXwZAAMw,2516
|
|
140
140
|
vast_flatbuf/tabular/CreateSchemaRequest.py,sha256=MrOfWaFu0Q1-mxLlGV8YMPajZ5kASyvowVSrKU-NPx8,1626
|
|
141
|
+
vast_flatbuf/tabular/CreateViewRequest.py,sha256=zagEVFrcWZLDY2exRHxr_uf-Yirchp7uYLk5b6Zvah8,4497
|
|
141
142
|
vast_flatbuf/tabular/GetProjectionTableStatsResponse.py,sha256=Bp-ln-0lcZEiUvp3vWYmnCP6t2UsZ5J-lezgkUUWhzo,3474
|
|
142
143
|
vast_flatbuf/tabular/GetTableStatsResponse.py,sha256=_UsKj6-VAvyDZ8Eku9fegQlRKV-T_0Dsb7qjulYoZus,4655
|
|
143
144
|
vast_flatbuf/tabular/ImportDataRequest.py,sha256=f1chKp5d5NUxfNjI8YI1o4MYInF8UDhIhpWkT3vG4Do,2450
|
|
144
145
|
vast_flatbuf/tabular/ListProjectionsResponse.py,sha256=secqrBsJY3ydbA28j09rmxzBqj-c1JNqaP7JMuib7nE,4240
|
|
145
146
|
vast_flatbuf/tabular/ListSchemasResponse.py,sha256=V8tbwcWAC96eNwuoqDNqCSb02BnMdq60TpyISuWTVMk,3036
|
|
146
147
|
vast_flatbuf/tabular/ListTablesResponse.py,sha256=V7jZAS8ryKY8s6o_QyjWzgan-rsGm17zjKEmi7K6qTM,3550
|
|
147
|
-
vast_flatbuf/tabular/
|
|
148
|
+
vast_flatbuf/tabular/ListViewsResponse.py,sha256=tn7mfW9afjWxMyBs3tsBcS_JA7uTAVNkFyaM7tctyns,3521
|
|
149
|
+
vast_flatbuf/tabular/ObjectDetails.py,sha256=yS16tYAu8BCYe7h_B4w7C9BDRVVxFMFg8_mkCyU7nOs,4697
|
|
148
150
|
vast_flatbuf/tabular/S3File.py,sha256=KC9c2oS5-JXwTTriUVFdjOvRG0B54Cq9kviSDZY3NI0,4450
|
|
149
151
|
vast_flatbuf/tabular/VipRange.py,sha256=_BJd1RRZAcK76T9vlsHzXKYVsPVaz6WTEAqStMQCAUQ,2069
|
|
150
152
|
vast_flatbuf/tabular/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
151
153
|
vastdb/__init__.py,sha256=J1JjKiFkKC95BHowfh9kJfQFTjRce-QMsc6zF_FfxC0,432
|
|
152
|
-
vastdb/_internal.py,sha256=
|
|
154
|
+
vastdb/_internal.py,sha256=nLa2G6FwjPiirjXo4HBc3Cs6P2XH8ub1yBsy1Zxu0R8,95257
|
|
153
155
|
vastdb/bucket.py,sha256=5KuKhPjZOevznZqWHDVVocejvAy7dcwobPuV6BJCfPc,2544
|
|
154
156
|
vastdb/config.py,sha256=1tMYtzKXerGcIUjH4tIGEvZNWvO4fviCEdcNCnELJZo,2269
|
|
155
157
|
vastdb/conftest.py,sha256=X2kVveySPQYZlVBXUMoo7Oea5IsvmJzjdqq3fpH2kVw,3469
|
|
156
158
|
vastdb/errors.py,sha256=2XR1ko7J5nkfiHSAgwuVAADw0SsyqxOwSeFaGgKZEXM,4186
|
|
157
159
|
vastdb/features.py,sha256=DxV746LSkORwVSD6MP2hdXRfnyoLkJwtOwGmp1dnquo,1322
|
|
158
|
-
vastdb/schema.py,sha256=
|
|
160
|
+
vastdb/schema.py,sha256=N9GLEoSFPrbpreJbCwcWGCtknoNQkavqra8UQvCzy3E,6306
|
|
159
161
|
vastdb/session.py,sha256=toMR0BXwTaECdWDKnIZky1F3MA1SmelRBiqCrqQ3GCM,2067
|
|
160
|
-
vastdb/table.py,sha256=
|
|
162
|
+
vastdb/table.py,sha256=PHtirFNL8j9PlXAgJp_rcLU37FgnWj0dPaFPFYWm28o,31186
|
|
161
163
|
vastdb/transaction.py,sha256=NlVkEowJ_pmtffjWBBDaKExYDKPekjSZyj_fK_bZPJE,3026
|
|
162
164
|
vastdb/util.py,sha256=8CUnVRsJukC3uNHNoB5D0qPf0FxS8OSdVB84nNoLJKc,6290
|
|
163
165
|
vastdb/bench/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -194,16 +196,16 @@ vastdb/tests/test_duckdb.py,sha256=STw_1PwTQR8Naz6s0p6lQTV1ZTKKhe3LPBUbhqzTCu0,1
|
|
|
194
196
|
vastdb/tests/test_imports.py,sha256=xKub3-bisFjH0BsZM8COfiUWuMrtoOoQKprF6VQT9RI,5669
|
|
195
197
|
vastdb/tests/test_nested.py,sha256=LPU6uV3Ri23dBzAEMFQqRPbqapV5LfmiHSHkhILPIY0,6332
|
|
196
198
|
vastdb/tests/test_projections.py,sha256=3y1kubwVrzO-xoR0hyps7zrjOJI8niCYspaFTN16Q9w,4540
|
|
197
|
-
vastdb/tests/test_sanity.py,sha256=
|
|
199
|
+
vastdb/tests/test_sanity.py,sha256=bv1ypGDzvOgmMvGbucDYiLQu8krQLlE6NB3M__q87x8,3303
|
|
198
200
|
vastdb/tests/test_schemas.py,sha256=l70YQMlx2UL1KRQhApriiG2ZM7GJF-IzWU31H3Yqn1U,3312
|
|
199
|
-
vastdb/tests/test_tables.py,sha256=
|
|
201
|
+
vastdb/tests/test_tables.py,sha256=711oTcdw431zs5LAyDxvTaJqF86xYwVCo5iZxSpH58o,39184
|
|
200
202
|
vastdb/tests/test_util.py,sha256=n7gvT5Wg6b6bxgqkFXkYqvFd_W1GlUdVfmPv66XYXyA,1956
|
|
201
203
|
vastdb/tests/util.py,sha256=dpRJYbboDnlqL4qIdvScpp8--5fxRUBIcIYitrfcj9o,555
|
|
202
204
|
vastdb/vast_tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
203
205
|
vastdb/vast_tests/test_ha.py,sha256=744P4G6VJ09RIkHhMQL4wlipCBJWQVMhyvUrSc4k1HQ,975
|
|
204
206
|
vastdb/vast_tests/test_scale.py,sha256=5jGwOdZH6Tv5tPdZYPWoqcxOceI2jA5i2D1zNKZHER4,3958
|
|
205
|
-
vastdb-1.3.
|
|
206
|
-
vastdb-1.3.
|
|
207
|
-
vastdb-1.3.
|
|
208
|
-
vastdb-1.3.
|
|
209
|
-
vastdb-1.3.
|
|
207
|
+
vastdb-1.3.3.dist-info/LICENSE,sha256=obffan7LYrq7hLHNrY7vHcn2pKUTBUYXMKu-VOAvDxU,11333
|
|
208
|
+
vastdb-1.3.3.dist-info/METADATA,sha256=xqBDm4Puvz348pzEDM7b_IIs-nZDSha7Sgg0RHHh94w,1340
|
|
209
|
+
vastdb-1.3.3.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
|
|
210
|
+
vastdb-1.3.3.dist-info/top_level.txt,sha256=Vsj2MKtlhPg0J4so64slQtnwjhgoPmJgcG-6YcVAwVc,20
|
|
211
|
+
vastdb-1.3.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|