1313# limitations under the License.
1414
1515from gremlin_python .structure .io .graphbinaryV1 import (
16- _GraphBinaryTypeIO , StringIO , GraphBinaryReader , GraphBinaryWriter , DataType ,
16+ _GraphBinaryTypeIO , StringIO , GraphBinaryReader , GraphBinaryWriter , DataType ,
1717 _make_packer ,
18- uint64_pack , uint64_unpack , uint8_pack , uint8_unpack
18+ uint64_pack , uint64_unpack , uint8_pack , uint8_unpack ,
1919)
2020from janusgraph_python .process .traversal import _JanusGraphP , RelationIdentifier
2121
2424
2525class JanusGraphBinaryReader (GraphBinaryReader ):
2626 def __init__ (self ):
27- # register JanusGraph-specific RelationIdentifier deserializer for custom type
27+ # register JanusGraph-specific deserializer for custom type code
2828 deserializer_map = {
29- DataType .custom : JanusGraphCustomIO
29+ DataType .custom : JanusGraphBinaryTypeIO
3030 }
3131
3232 GraphBinaryReader .__init__ (self , deserializer_map )
@@ -38,17 +38,66 @@ def __init__(self):
3838 (RelationIdentifier , JanusGraphRelationIdentifierIO ),
3939 (_JanusGraphP , JanusGraphPSerializer )
4040 ]
41+
4142 GraphBinaryWriter .__init__ (self , serializer_map )
4243
43- class _JanusGraphBinaryTypeIO (_GraphBinaryTypeIO ):
44+ class JanusGraphBinaryTypeIO (_GraphBinaryTypeIO ):
45+ # registry of JanusGraph-specific types with their type_id, type_name and class for deserialization
46+ io_registry = {}
47+
48+ @classmethod
49+ def register_deserializer (cls , type_class ):
50+ """
51+ Method to register a deserializer for a JanusGraph-specific type
52+ """
53+ cls .io_registry [type_class .graphbinary_type_id ] = (type_class .graphbinary_type_name , type_class )
54+
55+ @classmethod
56+ def objectify (cls , buff , reader , nullable = True ):
57+ """
58+ Method used for deserialization of JanusGraph-specific type
59+ """
60+ return cls .is_null (buff , reader , cls ._read_data , nullable )
61+
4462 @classmethod
45- def custom_type (cls , writer , to_extend , as_value = False ):
63+ def _read_data (cls , b , r ):
64+ """
65+ Method used for identifying a JanusGraph-specific type and
66+ find a deserializer class for it
67+ """
68+ # check if first byte is custom type code byte
69+ if uint8_unpack (b .read (1 )) != DataType .custom .value :
70+ return None
71+
72+ # get the custom type name length
73+ custom_type_name_length = uint16_unpack (b .read (2 ))
74+ custom_type_name = b .read (custom_type_name_length ).decode ()
75+
76+ # read the custom type id
77+ custom_type_id = uint32_unpack (b .read (4 ))
78+
79+ # try to get a deserializer class for the JanusGraph-specific type
80+ custom_serializer = cls .io_registry .get (custom_type_id )
81+ if not custom_serializer :
82+ raise NotImplementedError (f"No JanusGraph serializer found for type with id: { custom_type_id } " )
83+
84+ # check the type name
85+ if custom_serializer [0 ] != custom_type_name :
86+ raise NotImplementedError (f"No JanusGraph serializer found for type with name: { custom_type_name } " )
87+
88+ return custom_serializer [1 ].objectify (b , r )
89+
90+ @classmethod
91+ def prefix_bytes_custom_type (cls , writer , to_extend , as_value = False ):
92+ """
93+ Helper method to add a specific byte array prefix while serializing
94+ JanusGraph-specific type as custom type
95+ """
4696 if to_extend is None :
4797 to_extend = bytearray ()
4898
49- # serializing the custom JanusGraph type
5099 # use the custom type code
51- if not as_value : #- identifier does not like this if
100+ if not as_value :
52101 to_extend += uint8_pack (DataType .custom .value )
53102
54103 # add the name of the custom JanusGraph type
@@ -61,52 +110,54 @@ def custom_type(cls, writer, to_extend, as_value=False):
61110 if not as_value :
62111 to_extend += uint8_pack (DataType .custom .value )
63112
64- class JanusGraphPSerializer (_JanusGraphBinaryTypeIO ):
113+ class JanusGraphPSerializer (JanusGraphBinaryTypeIO ):
65114 graphbinary_type_id = 0x1002
66115 graphbinary_type_name = "janusgraph.P"
67116 python_type = _JanusGraphP
68117
69118 @classmethod
70119 def dictify (cls , obj , writer , to_extend , as_value = False , nullable = True ):
71- cls .custom_type (writer , to_extend , as_value )
120+ """
121+ Method to serialize JanusGraph-specific Text predicate
122+ """
123+ cls .prefix_bytes_custom_type (writer , to_extend , as_value )
72124
73- # serializing the custom JanusGraph operator
125+ # serialize the custom JanusGraph operator
74126 StringIO .dictify (obj .operator , writer , to_extend , True , False )
75-
127+
76128 # serialize the value
77129 writer .to_dict (obj .value , to_extend )
78130
79131 return to_extend
80132
81- class JanusGraphRelationIdentifierIO (_JanusGraphBinaryTypeIO ):
133+ class JanusGraphRelationIdentifierIO (JanusGraphBinaryTypeIO ):
82134 graphbinary_type_id = 0x1001
83135 graphbinary_type_name = "janusgraph.RelationIdentifier"
84136 python_type = RelationIdentifier
85137
86138 long_marker = 0
87139 string_marker = 1
88140
89- @classmethod
90- def _write_string (cls , string , writer , to_extend ):
91- b = bytearray ()
92- b .extend (map (ord , string ))
93- b [- 1 ] |= 0x80 # add end marker to the last character
94- to_extend += b
95-
96141 @classmethod
97142 def dictify (cls , obj , writer , to_extend , as_value = False , nullable = True ):
98- cls .custom_type (writer , to_extend , as_value )
143+ """
144+ Method to serialize JanusGraph-specific RelationIdentifier
145+ """
146+ cls .prefix_bytes_custom_type (writer , to_extend , as_value )
99147
148+ # serialize out vertex ID
100149 if isinstance (obj .out_vertex_id , int ):
101150 to_extend += uint8_pack (cls .long_marker )
102151 to_extend += uint64_pack (obj .out_vertex_id )
103152 else :
104153 to_extend += uint8_pack (cls .string_marker )
105154 cls ._write_string (obj .out_vertex_id , writer , to_extend )
106155
156+ # serialize edge type ID and relation ID
107157 to_extend += uint64_pack (obj .type_id )
108158 to_extend += uint64_pack (obj .relation_id )
109159
160+ # serialize in vertex ID
110161 if obj .in_vertex_id is None :
111162 to_extend += uint8_pack (cls .long_marker )
112163 to_extend += uint64_pack (0 )
@@ -119,33 +170,28 @@ def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
119170
120171 return to_extend
121172
122- @classmethod
123- def _read_string (cls , buff ):
124- final_string = ""
125- while True :
126- c = 0xFF & uint8_unpack (buff .read (1 ))
127- final_string += chr (c & 0x7F )
128- if c & 0x80 > 0 :
129- break
130-
131- return final_string
132-
133173 @classmethod
134174 def objectify (cls , b , r ):
175+ """
176+ Method to deserialize JanusGraph-specific RelationIdentifier
177+ """
135178 if uint8_unpack (b .read (1 )) != DataType .custom .value :
136179 raise Exception ("Unexpected type while deserializing JanusGraph RelationIdentifier" )
137180
138181 # read the next byte that shows if the out vertex id is string or long
139182 out_vertex_id_marker = uint8_unpack (b .read (1 ))
140183
184+ # deserialize out vertex ID
141185 if out_vertex_id_marker == cls .string_marker :
142186 out_vertex_id = cls ._read_string (b )
143187 else :
144188 out_vertex_id = uint64_unpack (b .read (8 ))
145189
190+ # deserialize edge type ID and relation ID
146191 type_id = uint64_unpack (b .read (8 ))
147192 relation_id = uint64_unpack (b .read (8 ))
148193
194+ # deserialize out vertex ID
149195 in_vertex_id_marker = uint8_unpack (b .read (1 ))
150196 if in_vertex_id_marker == cls .string_marker :
151197 in_vertex_id = cls ._read_string (b )
@@ -155,36 +201,40 @@ def objectify(cls, b, r):
155201 in_vertex_id = None
156202
157203 return RelationIdentifier .from_ids (out_vertex_id , type_id , relation_id , in_vertex_id )
204+
205+ @classmethod
206+ def _read_string (cls , buff ):
207+ """
208+ Helper method to read a string represented as byte array.
209+ The length of the string is not known upfront so the byte
210+ array needs to be red until a byte occurs that is marked
211+ with a special end marker
212+ """
213+ final_string = ""
214+ while True :
215+ c = 0xFF & uint8_unpack (buff .read (1 ))
216+ final_string += chr (c & 0x7F )
158217
159- class JanusGraphCustomIO (_GraphBinaryTypeIO ):
160- # list of JanusGraph custom types with their type_id, type_name and class for deserialization
161- io_registry = {
162- 0x1001 : ("janusgraph.RelationIdentifier" , JanusGraphRelationIdentifierIO )
163- }
218+ # check if the character is marked with end marker
219+ # if yes that is the end of the string
220+ if c & 0x80 > 0 :
221+ break
164222
165- @classmethod
166- def objectify (cls , buff , reader , nullable = True ):
167- return cls .is_null (buff , reader , cls ._read_data , nullable )
223+ return final_string
168224
169225 @classmethod
170- def _read_data (cls , b , r ):
171- # check if first byte is custom byte notation
172- if uint8_unpack (b .read (1 )) != DataType .custom .value :
173- return None
174-
175- # get the custom type name length
176- custom_type_name_length = uint16_unpack (b .read (2 ))
177- custom_type_name = b .read (custom_type_name_length ).decode ()
226+ def _write_string (cls , string , writer , to_extend ):
227+ """
228+ Helper method to create a byte array from a string and
229+ mark the string's last character with special end marker
230+ """
231+ b = bytearray ()
232+ b .extend (map (ord , string ))
178233
179- # read the custom type id
180- custom_type_id = uint32_unpack ( b . read ( 4 ))
234+ # add end marker to the last character
235+ b [ - 1 ] |= 0x80
181236
182- custom_serializer = cls .io_registry .get (custom_type_id )
183- if not custom_serializer :
184- raise NotImplementedError (f"No JanusGraph serializer found for type with id: { custom_type_id } " )
185-
186- # check the type name
187- if custom_serializer [0 ] != custom_type_name :
188- raise NotImplementedError (f"No JanusGraph serializer found for type with name: { custom_type_name } " )
189-
190- return custom_serializer [1 ].objectify (b , r )
237+ to_extend += b
238+
239+ # register the JanusGraph-specific RelationIdentifier as deserializer
240+ JanusGraphBinaryTypeIO .register_deserializer (JanusGraphRelationIdentifierIO )
0 commit comments