diff --git a/nebula2/data/DataObject.py b/nebula2/data/DataObject.py index 4401409e..0ec094a5 100644 --- a/nebula2/data/DataObject.py +++ b/nebula2/data/DataObject.py @@ -13,7 +13,7 @@ InvalidKeyException, OutOfRangeException ) -from nebula2.common.ttypes import NullType +from nebula2.common.ttypes import NullType, Edge, Vertex class Record(object): @@ -613,7 +613,7 @@ def gen_segment(cls, start_node, end_node, relationship): class Node(object): - def __init__(self, vertex, decode_type='utf-8'): + def __init__(self, vertex: Vertex, decode_type='utf-8'): self._value = vertex self._tag_indexes = dict() self._decode_type = decode_type @@ -633,12 +633,14 @@ def tags(self): def has_tag(self, tag): return True if tag in self._tag_indexes.keys() else False - def propertys(self, tag): + def properties(self, tag): if tag not in self._tag_indexes.keys(): raise InvalidKeyException(tag) props = self._value.tags[self._tag_indexes[tag]].props result_props = {} + if props is None: + return result_props for key in props.keys(): result_props[key.decode(self._decode_type)] = ValueWrapper(props[key]) return result_props @@ -647,18 +649,24 @@ def prop_names(self, tag): if tag not in self._tag_indexes.keys(): raise InvalidKeyException(tag) index = self._tag_indexes[tag] - return [(key.decode(self._decode_type)) for key in self._value.tags[index].props.keys()] + props = self._value.tags[index].props + if props is None: + return [] + return [(key.decode(self._decode_type)) for key in props.keys()] def prop_values(self, tag): if tag not in self._tag_indexes.keys(): raise InvalidKeyException(tag) index = self._tag_indexes[tag] - return [(ValueWrapper(value)) for value in self._value.tags[index].props.values()] + props = self._value.tags[index].props + if props is None: + return [] + return [(ValueWrapper(value)) for value in props.values()] def __repr__(self): tag_str_list = list() for tag in self._tag_indexes.keys(): - prop_strs = ['%s: %s' % (key, str(val)) for key, val in self.propertys(tag).items()] + prop_strs = ['%s: %s' % (key, str(val)) for key, val in self.properties(tag).items()] tag_str_list.append(':%s{%s}' % (tag, ', '.join(prop_strs))) return '({} {})'.format(str(self.get_id()), ' '.join(tag_str_list)) @@ -673,7 +681,7 @@ def __ne__(self, other): class Relationship(object): - def __init__(self, edge, decode_type='utf-8'): + def __init__(self, edge: Edge, decode_type='utf-8'): self._decode_type = decode_type self._value = edge @@ -703,20 +711,26 @@ def edge_name(self): def ranking(self): return self._value.ranking - def propertys(self): + def properties(self): props = {} + if self._value.props is None: + return props for key in self._value.props.keys(): props[key.decode(self._decode_type)] = ValueWrapper(self._value.props[key]) return props def keys(self): + if self._value.props is None: + return [] return [(key.decode(self._decode_type)) for key in self._value.props.keys()] def values(self): - return [(ValueWrapper(value)) for value in self._value.props.values] + if self._value.props is None: + return [] + return [(ValueWrapper(value)) for value in self._value.props.values()] def __repr__(self): - prop_strs = ['%s: %s' % (key, str(val)) for key, val in self.propertys().items()] + prop_strs = ['%s: %s' % (key, str(val)) for key, val in self.properties().items()] return "(%s)-[:%s@%d{%s}]->(%s)" % (str(self.start_vertex_id()), self.edge_name(), self.ranking(), @@ -744,7 +758,7 @@ def __repr__(self): return "{}-[:{}@{}{}]->{}".format(self.start_node, self.relationship.edge_name(), self.relationship.ranking(), - self.relationship.propertys(), + self.relationship.properties(), self.end_node) def __eq__(self, other): @@ -836,7 +850,7 @@ def __repr__(self): step.ranking, step.props)) edge_str = '' - prop_strs = ['%s: %s' % (key, str(val)) for key, val in relationship.propertys().items()] + prop_strs = ['%s: %s' % (key, str(val)) for key, val in relationship.properties().items()] if step.type > 0: edge_str = '-[:%s@%d{%s}]->%s' % (relationship.edge_name(), relationship.ranking(), diff --git a/tests/test_data_type.py b/tests/test_data_type.py index 04e347e1..39fd4525 100644 --- a/tests/test_data_type.py +++ b/tests/test_data_type.py @@ -47,23 +47,24 @@ class TestBaseCase(TestCase): @classmethod - def get_vertex_value(self, vid): + def get_vertex_value(cls, vid, empty_props=False): vertex = ttypes.Vertex() vertex.vid = ttypes.Value(sVal=vid) vertex.tags = list() for i in range(0, 3): tag = ttypes.Tag() tag.name = ('tag{}'.format(i)).encode('utf-8') - tag.props = dict() - for j in range(0, 5): - value = ttypes.Value() - value.set_iVal(j) - tag.props[('prop{}'.format(j)).encode('utf-8')] = value + if not empty_props: + tag.props = dict() + for j in range(0, 5): + value = ttypes.Value() + value.set_iVal(j) + tag.props[('prop{}'.format(j)).encode('utf-8')] = value vertex.tags.append(tag) return vertex @classmethod - def get_edge_value(self, src_id, dst_id, is_reverse=False): + def get_edge_value(cls, src_id, dst_id, is_reverse=False, empty_props=False): edge = ttypes.Edge() if not is_reverse: edge.src = ttypes.Value(sVal=src_id) @@ -74,21 +75,22 @@ def get_edge_value(self, src_id, dst_id, is_reverse=False): edge.type = 1 edge.name = b'classmate' edge.ranking = 100 - edge.props = dict() - for i in range(0, 5): - value = ttypes.Value() - value.set_iVal(i) - edge.props[('prop{}'.format(i)).encode('utf-8')] = value + if not empty_props: + edge.props = dict() + for i in range(0, 5): + value = ttypes.Value() + value.set_iVal(i) + edge.props[('prop{}'.format(i)).encode('utf-8')] = value return edge @classmethod - def get_path_value(self, start_id, steps=5): + def get_path_value(cls, start_id, steps=5): path = ttypes.Path() - path.src = self.get_vertex_value(start_id) + path.src = cls.get_vertex_value(start_id) path.steps = list() for i in range(0, steps): step = ttypes.Step() - step.dst = self.get_vertex_value(('vertex{}'.format(i)).encode('utf-8')) + step.dst = cls.get_vertex_value(('vertex{}'.format(i)).encode('utf-8')) step.type = 1 if i % 2 == 0 else -1 step.name = b'classmate' step.ranking = 100 @@ -101,7 +103,7 @@ def get_path_value(self, start_id, steps=5): return path @classmethod - def get_data_set(self): + def get_data_set(cls): data_set = ttypes.DataSet() data_set.column_names = [b"col1_empty", b"col2_null", @@ -168,13 +170,13 @@ def get_data_set(self): value12.set_dtVal(DateTime(2020, 10, 1, 10, 10, 10, 10000)) row.values.append(value12) value13 = ttypes.Value() - value13.set_vVal(self.get_vertex_value(b"Tom")) + value13.set_vVal(cls.get_vertex_value(b"Tom")) row.values.append(value13) value14 = ttypes.Value() - value14.set_eVal(self.get_edge_value(b"Tom", b"Lily")) + value14.set_eVal(cls.get_edge_value(b"Tom", b"Lily")) row.values.append(value14) value15 = ttypes.Value() - value15.set_pVal(self.get_path_value(b"Tom", 3)) + value15.set_pVal(cls.get_path_value(b"Tom", 3)) row.values.append(value15) data_set.rows = [] data_set.rows.append(row) @@ -182,7 +184,7 @@ def get_data_set(self): return data_set @classmethod - def get_result_set(self): + def get_result_set(cls): resp = graphTtype.ExecutionResponse() resp.error_code = ErrorCode.E_BAD_PERMISSION resp.error_msg = b"Permission" @@ -190,7 +192,7 @@ def get_result_set(self): resp.space_name = b"test" resp.latency_in_us = 100 - resp.data = self.get_data_set() + resp.data = cls.get_data_set() return ResultSet(resp, 100) @@ -352,6 +354,15 @@ def test_as_node(self): node = value_wrapper.as_node() assert isinstance(node, Node) + assert node.get_id().as_string() == 'Tom' + assert node.has_tag('tag1') + assert node.prop_names('tag1').sort() == ['prop0', 'prop1', 'prop2', 'prop3', 'prop4'].sort() + expect_values = [(v.as_int()) for v in node.prop_values('tag1')] + assert expect_values == [0, 1, 2, 3, 4] + assert node.tags() == ['tag0', 'tag1', 'tag2'] + assert list(node.properties('tag1').keys()).sort() == ['prop0', 'prop1', 'prop2', 'prop3', 'prop4'].sort() + expect_values = [(v.as_int()) for v in node.properties('tag1').values()] + assert expect_values == [0, 1, 2, 3, 4] def test_as_relationship(self): value = ttypes.Value(eVal=self.get_edge_value(b'Tom', b'Lily')) @@ -375,6 +386,24 @@ def test_as_relationship(self): assert isinstance(reversely_relationship, Relationship) assert reversely_relationship != relationship + relationship.ranking() == 100 + relationship.edge_name() == 'classmate' + relationship.start_vertex_id().as_string() == 'Lily' + relationship.start_vertex_id().as_string() == 'Tom' + assert relationship.keys() == ['prop0', 'prop1', 'prop2', 'prop3', 'prop4'] + expect_values = [(v.as_int()) for v in relationship.values()] + assert expect_values == [0, 1, 2, 3, 4] + assert list(relationship.properties().keys()).sort() == ['prop0', 'prop1', 'prop2', 'prop3', 'prop4'].sort() + expect_values = [(v.as_int()) for v in relationship.properties().values()] + assert expect_values == [0, 1, 2, 3, 4] + + # test empty props + value = ttypes.Value(eVal=self.get_edge_value(b'Tom', b'Lily', empty_props=True)) + relationship = ValueWrapper(value).as_relationship() + assert relationship.keys() == [] + assert relationship.values() == [] + assert len(relationship.properties()) == 0 + def test_as_path(self): value = ttypes.Value() value.set_pVal(self.get_path_value(b'Tom')) @@ -401,8 +430,8 @@ def test_node_api(self): assert ['tag0', 'tag1', 'tag2'] == node.tags() expect_propertys = {} - for key in node.propertys('tag2').keys(): - expect_propertys[key] = node.propertys('tag2')[key].as_int() + for key in node.properties('tag2').keys(): + expect_propertys[key] = node.properties('tag2')[key].as_int() assert {'prop0': 0, 'prop1': 1, 'prop2': 2, 'prop3': 3, 'prop4': 4} == expect_propertys @@ -423,8 +452,8 @@ def test_relationship_api(self): assert ['prop0', 'prop1', 'prop2', 'prop3', 'prop4'] == relationship.keys() expect_propertys = {} - for key in relationship.propertys().keys(): - expect_propertys[key] = relationship.propertys()[key].as_int() + for key in relationship.properties().keys(): + expect_propertys[key] = relationship.properties()[key].as_int() assert {'prop0': 0, 'prop1': 1, 'prop2': 2, 'prop3': 3, 'prop4': 4} == expect_propertys