File Coverage

lib/Neo4j/Bolt/CTypeHandlers.xs
Criterion Covered Total %
statement 188 224 83.9
branch 101 162 62.3
condition n/a
subroutine n/a
pod n/a
total 289 386 74.8


line stmt bran cond sub pod time code
1             #include "perlbolt.h"
2             #include "values.h"
3             #include
4              
5             extern neo4j_value_t neo4j_identity(long long);
6             extern neo4j_value_t neo4j_node(const neo4j_value_t*);
7             extern neo4j_value_t neo4j_relationship(const neo4j_value_t*);
8              
9             /**
10             Types
11             NEO4J_BOOL
12             NEO4J_BYTES
13             NEO4J_FLOAT
14             NEO4J_IDENTITY
15             NEO4J_INT
16             NEO4J_LIST
17             NEO4J_MAP
18             NEO4J_NODE
19             NEO4J_NULL
20             NEO4J_PATH
21             NEO4J_RELATIONSHIP
22             NEO4J_STRING
23             **/
24              
25             neo4j_value_t SViv_to_neo4j_bool (SV *sv);
26             neo4j_value_t SViv_to_neo4j_int (SV *sv);
27             neo4j_value_t SVnv_to_neo4j_float (SV *sv);
28             neo4j_value_t SVpv_to_neo4j_string (SV *sv);
29             neo4j_value_t AV_to_neo4j_list(AV *av);
30             neo4j_value_t HV_to_neo4j_map(HV *hv);
31             neo4j_value_t HV_to_neo4j_node(HV *hv);
32             neo4j_value_t HV_to_neo4j_relationship(HV *hv);
33             neo4j_value_t AV_to_neo4j_path(AV *av);
34             neo4j_value_t SV_to_neo4j_value(SV *sv);
35              
36             SV* neo4j_bool_to_SViv( neo4j_value_t value );
37             SV* neo4j_bytes_to_SVpv( neo4j_value_t value );
38             SV* neo4j_float_to_SVnv( neo4j_value_t value );
39             SV* neo4j_int_to_SViv( neo4j_value_t value );
40             SV* neo4j_string_to_SVpv( neo4j_value_t value );
41             HV* neo4j_node_to_HV( neo4j_value_t value );
42             HV* neo4j_relationship_to_HV( neo4j_value_t value );
43             AV* neo4j_path_to_AV( neo4j_value_t value);
44             AV* neo4j_list_to_AV( neo4j_value_t value );
45             HV* neo4j_map_to_HV( neo4j_value_t value );
46             SV* neo4j_value_to_SV( neo4j_value_t value );
47              
48             long long neo4j_identity_value(neo4j_value_t value);
49             char *neo4j_string_to_alloc_str(neo4j_value_t value);
50              
51 26           char *neo4j_string_to_alloc_str(neo4j_value_t value) {
52             assert(neo4j_type(value) == NEO4J_STRING);
53             char *s;
54             int nlength;
55 26           nlength = (int) neo4j_string_length(value);
56 26           Newx(s,nlength+1,char);
57 26           return neo4j_string_value(value,s,(size_t) nlength+1);
58             }
59              
60 1           neo4j_value_t SViv_to_neo4j_bool (SV *sv) {
61 1 50         return neo4j_bool( (bool) SvIV(sv) );
62             }
63              
64 3           neo4j_value_t SViv_to_neo4j_int (SV *sv) {
65 3 50         return neo4j_int( (long long) SvIV(sv) );
66             }
67              
68 1           neo4j_value_t SVnv_to_neo4j_float (SV *sv) {
69 1 50         return neo4j_float( SvNV(sv) );
70             }
71              
72 16           neo4j_value_t SVpv_to_neo4j_string (SV *sv) {
73             STRLEN len;
74             char *k0,*k;
75 16 50         k = SvPV(sv,len);
76 16           Newx(k0,len+1,char);
77 16           strncpy(k0,k,(size_t) len);
78 16           *(k0+len) = 0;
79 16           return neo4j_string(k0);
80             }
81              
82 28           neo4j_value_t SV_to_neo4j_value(SV *sv) {
83             int t;
84             SV *thing;
85             HV *hv;
86              
87 28 50         if (!SvOK(sv) ) {
    0          
    0          
88 0           return neo4j_null;
89             }
90 28 100         if (SvROK(sv)) { // a ref
91 10           thing = SvRV(sv);
92 10           t = SvTYPE(thing);
93 10 100         if ( t < SVt_PVAV) { // scalar ref
94 1 50         if ((sv_isobject(sv) && sv_isa(sv, "JSON::PP::Boolean")) || (SvIOK(thing) && SvIV(thing) >> 1 == 0)) {
    0          
    50          
    50          
    50          
    0          
95             // boolean (accepts JSON::PP, Types::Serialiser, literal \1 and \0)
96 1           return SViv_to_neo4j_bool(thing);
97             }
98             else {
99 0           return SV_to_neo4j_value(thing);
100             }
101             }
102 9 100         else if (t == SVt_PVAV) { //array
103 2 100         if (sv_isobject(sv)) {
104 1 50         if (sv_isa(sv, PATH_CLASS)) { // path
105 1           return AV_to_neo4j_path( (AV*) thing );
106             }
107 0           warn("Unknown blessed array reference type encountered");
108             }
109 1           return AV_to_neo4j_list( (AV*) thing );
110             }
111 7 50         else if (t == SVt_PVHV) { //hash
112             // determine if is a map, node, or reln
113 7           hv = (HV *)thing;
114 7 100         if (sv_isobject(sv)) {
115 6 100         if (sv_isa(sv, NODE_CLASS)) { // node
116 3           return HV_to_neo4j_node(hv);
117             }
118 3 50         if (sv_isa(sv, RELATIONSHIP_CLASS)) { // reln
119 3           return HV_to_neo4j_relationship(hv);
120             }
121 0           warn("Unknown blessed hash reference type encountered");
122             }
123 1           return HV_to_neo4j_map(hv); // map
124             }
125             }
126             else {
127 18 100         if (SvIOK(sv)) {
128 3           return SViv_to_neo4j_int(sv);
129             }
130 15 100         else if (SvNOK(sv)) {
131 1           return SVnv_to_neo4j_float(sv);
132             }
133 14 50         else if (SvPOK(sv)) {
134 14           return SVpv_to_neo4j_string(sv);
135             }
136             else {
137 0           perror("Can't handle this scalar");
138 0           return neo4j_null;
139             }
140             }
141 0           return neo4j_null;
142             }
143              
144 2           neo4j_value_t AV_to_neo4j_list(AV *av) {
145             int i,n;
146             neo4j_value_t *items;
147 2           n = av_top_index(av);
148 2 50         if (n < 0) {
149 0           return neo4j_null;
150             }
151 2 50         Newx(items, n+1, neo4j_value_t);
152 8 100         for (i=0;i<=n;i++) {
153 6           items[i] = SV_to_neo4j_value( *(av_fetch(av,i,0)) );
154             }
155 2           return neo4j_list(items, n+1);
156             }
157              
158 4           neo4j_value_t HV_to_neo4j_map (HV *hv) {
159             HE *ent;
160             char *k,*k0;
161             SV *v;
162             int n,retlen;
163             neo4j_map_entry_t *map_ents;
164 4 50         if (!HvTOTALKEYS(hv)) {
165 0           return neo4j_null;
166             }
167 4 50         Newx(map_ents,HvTOTALKEYS(hv),neo4j_map_entry_t);
168 4           hv_iterinit(hv);
169 4           n=0;
170 13 100         while ((ent = hv_iternext(hv))) {
171 9           k = hv_iterkey(ent,&retlen);
172 9           Newx(k0,retlen+1,char);
173 9           strncpy(k0,k,retlen);
174 9           *(k0+retlen)=0;
175 9           map_ents[n] = neo4j_map_entry( k0, SV_to_neo4j_value(hv_iterval(hv,ent)));
176 9           n++;
177             }
178 4           return neo4j_map( map_ents, HvTOTALKEYS(hv) );
179             }
180              
181             // neo4j_node(neo4j_value_t fields[3]) is not exposed in the API
182             // fields[0] is a NEO4J_IDENTITY
183             // fields[1] is a NEO4J_LIST of node labels (NEO4J_STRINGs)
184             // (note REST::Neo4p::Node doesn't store a list of labels in the
185             // simple rendering! Fix!)
186             // fields[2] is a NEO4J_MAP of properties
187 3           neo4j_value_t HV_to_neo4j_node(HV *hv) {
188             SV **node_id_p, **lbls_ref_p, **props_ref_p;
189             AV *lbls;
190             HV *props;
191             neo4j_value_t *fields;
192             neo4j_map_entry_t null_ent;
193 3           Newx(fields, 3, neo4j_value_t);
194              
195 3           node_id_p = hv_fetch(hv, "id", 2, 0);
196 3           lbls_ref_p = hv_fetch(hv, "labels", 6, 0);
197 3 100         if (lbls_ref_p && SvROK(*lbls_ref_p)) {
    50          
198 1           lbls = (AV*) SvRV(*lbls_ref_p);
199             } else {
200 2           lbls = NULL;
201             }
202 3 100         if (lbls && SvTYPE((SV*)lbls) == SVt_PVAV && av_top_index(lbls) >= 0) {
    50          
    50          
203 1           fields[1] = AV_to_neo4j_list(lbls);
204             } else {
205 2           fields[1] = neo4j_list( &neo4j_null, 0 );
206             }
207 3 50         fields[0] = neo4j_identity( node_id_p ? SvIV( *node_id_p ) : -1 );
    50          
208              
209 3           props_ref_p = hv_fetch(hv, "properties", 10, 0);
210 3 100         if (props_ref_p && SvROK(*props_ref_p)) {
    50          
211 2           props = (HV*) SvRV(*props_ref_p);
212             } else {
213 1           props = NULL;
214             }
215 3 100         if (props && SvTYPE((SV*)props) == SVt_PVHV && HvTOTALKEYS(props)) {
    50          
    50          
216 2           fields[2] = HV_to_neo4j_map(props);
217             } else {
218 1           null_ent = neo4j_map_entry( "", neo4j_null );
219 1           fields[2] = neo4j_map( &null_ent, 0 );
220             }
221 3           return neo4j_node(fields);
222             }
223              
224              
225             // neo4j_relationship( neo4j_value_t fields[5] ) is not exposed in API
226             // field[0] is NEO4J_IDENTITY (id of the relationship)
227             // field[1] is NEO4J_IDENTITY (id of the start node))
228             // field[2] is NEO4J_IDENTITY (id of the end node))
229             // field[3] is NEO4J_STRING (relationship type)
230             // field[4] is NEO4J_MAP (properties)
231              
232 3           neo4j_value_t HV_to_neo4j_relationship(HV *hv) {
233             SV **reln_id_p, **start_id_p, **end_id_p, **type_p, **props_ref_p;
234             HV *props;
235             neo4j_value_t *fields;
236             neo4j_map_entry_t null_ent;
237              
238 3           Newx(fields, 5, neo4j_value_t);
239              
240 3           reln_id_p = hv_fetch(hv, "id", 2, 0);
241 3           start_id_p = hv_fetch(hv, "start", 5, 0);
242 3           end_id_p = hv_fetch(hv, "end", 3, 0);
243 3           type_p = hv_fetch(hv, "type", 4, 0);
244              
245 3 50         fields[0] = neo4j_identity( reln_id_p ? SvIV( *reln_id_p ) : -1 );
    50          
246 3 50         fields[1] = neo4j_identity( start_id_p ? SvIV( *start_id_p ) : -1 );
    50          
247 3 50         fields[2] = neo4j_identity( end_id_p ? SvIV( *end_id_p ) : -1 );
    50          
248 3 100         if (type_p && SvOK(*type_p)) {
    50          
    0          
    0          
249 2           fields[3] = SVpv_to_neo4j_string( *type_p );
250             } else {
251 1           fields[3] = neo4j_string("");
252             }
253              
254 3           props_ref_p = hv_fetch(hv, "properties", 10, 0);
255 3 100         if (props_ref_p && SvROK(*props_ref_p)) {
    50          
256 1           props = (HV*) SvRV(*props_ref_p);
257             } else {
258 2           props = NULL;
259             }
260 3 100         if (props && SvTYPE((SV*)props) == SVt_PVHV && HvTOTALKEYS(props)) {
    50          
    50          
261 1           fields[4] = HV_to_neo4j_map(props);
262             } else {
263 2           null_ent = neo4j_map_entry( "", neo4j_null );
264 2           fields[4] = neo4j_map( &null_ent, 0 );
265             }
266 3           return neo4j_relationship(fields);
267             }
268              
269 1           neo4j_value_t AV_to_neo4j_path(AV *av) {
270 1           fprintf(stderr, "Not yet implemented");
271 1           return neo4j_null;
272             }
273              
274 12           long long neo4j_identity_value(neo4j_value_t value)
275             {
276 12           value._type = NEO4J_INT;
277 12           return neo4j_int_value(value);
278             }
279              
280              
281 2           SV* neo4j_bool_to_SViv( neo4j_value_t value) {
282 2           HV* boolean_stash = gv_stashpv("JSON::PP::Boolean", GV_ADD);
283 2           SV* scalar = newSViv( (IV) neo4j_bool_value(value) );
284 2           return sv_bless(newRV_noinc(scalar), boolean_stash);
285             }
286              
287 0           SV* neo4j_bytes_to_SVpv( neo4j_value_t value ) {
288 0           return newSVpvn( neo4j_bytes_value(value),
289             neo4j_bytes_length(value) );
290             }
291              
292 1           SV* neo4j_float_to_SVnv( neo4j_value_t value ) {
293 1           return newSVnv( neo4j_float_value( value ) );
294             }
295              
296 3           SV* neo4j_int_to_SViv( neo4j_value_t value ) {
297 3           return newSViv( (IV) neo4j_int_value( value ) );
298             }
299              
300 17           SV* neo4j_string_to_SVpv( neo4j_value_t value ) {
301             SV* pv;
302 17           pv = newSVpv(neo4j_string_to_alloc_str(value), 0);
303 17           SvUTF8_on(pv); // depends on libneo4j-client output being valid UTF-8, always
304 17           return pv;
305             }
306              
307 29           SV* neo4j_value_to_SV( neo4j_value_t value ) {
308             neo4j_type_t the_type;
309 29           the_type = neo4j_type( value );
310 29 100         if ( the_type == NEO4J_BOOL) {
311 2           return neo4j_bool_to_SViv(value);
312 27 50         } else if ( the_type == NEO4J_BYTES) {
313 0           return neo4j_bytes_to_SVpv(value);
314 27 100         } else if ( the_type == NEO4J_FLOAT) {
315 1           return neo4j_float_to_SVnv(value);
316 26 100         } else if ( the_type == NEO4J_INT) {
317 3           return neo4j_int_to_SViv(value);
318 23 100         } else if ( the_type == NEO4J_NODE) {
319 3           return sv_bless( newRV_noinc((SV*)neo4j_node_to_HV( value )),
320             gv_stashpv(NODE_CLASS, GV_ADD) );
321 20 100         } else if ( the_type == NEO4J_RELATIONSHIP) {
322 3           return sv_bless( newRV_noinc((SV*)neo4j_relationship_to_HV( value )),
323             gv_stashpv(RELATIONSHIP_CLASS, GV_ADD) );
324 17 50         } else if ( the_type == NEO4J_NULL) {
325 0           return newSV(0);
326 17 100         } else if ( the_type == NEO4J_LIST) {
327 2           return newRV_noinc((SV*)neo4j_list_to_AV( value ));
328 15 100         } else if ( the_type == NEO4J_MAP) {
329 1           return newRV_noinc( (SV*)neo4j_map_to_HV( value ));
330 14 50         } else if ( the_type == NEO4J_PATH ){
331 0           return sv_bless( newRV_noinc((SV*)neo4j_path_to_AV( value )),
332             gv_stashpv(PATH_CLASS, GV_ADD) );
333              
334 14 50         } else if ( the_type == NEO4J_STRING) {
335 14           return neo4j_string_to_SVpv(value);
336             } else {
337 0           warn("Unknown neo4j_value type encountered");
338 0           return newSV(0);
339             }
340             }
341              
342 2           AV* neo4j_list_to_AV( neo4j_value_t value ) {
343             int i,n;
344             AV* av;
345             neo4j_value_t entry;
346 2           n = neo4j_list_length( value );
347 2           av = newAV();
348 8 100         for (i=0;i
349 6           entry = neo4j_list_get(value, i);
350 6           av_push(av, neo4j_value_to_SV( entry ));
351             }
352 2           return av;
353             }
354              
355 7           HV* neo4j_map_to_HV( neo4j_value_t value ) {
356             int i,n;
357             char *ks;
358             const neo4j_map_entry_t *entry;
359             HV *hv;
360             SV *sv;
361 7           hv = newHV();
362 7           n = (int) neo4j_map_size(value);
363 16 100         for (i=0;i
364 9           entry = neo4j_map_getentry(value,i);
365 9           ks = neo4j_string_to_alloc_str(entry->key);
366 9           sv = neo4j_value_to_SV(entry->value);
367 9           SvREFCNT_inc(sv);
368 9 50         if (hv_store(hv, ks, neo4j_string_length(entry->key), sv,0) ==
369             NULL) {
370 0           SvREFCNT_dec(sv);
371 0           fprintf(stderr, "Failed to create hash entry for key '%s'\n",ks);
372             }
373             }
374 7           return hv;
375             }
376              
377 3           HV* neo4j_node_to_HV( neo4j_value_t value ) {
378             HV *hv, *props_hv;
379             char *k;
380             SV *v;
381             I32 retlen;
382             long long id;
383             neo4j_value_t labels,props;
384             // const struct neo4j_struct *V;
385             // V = (const struct neo4j_struct *)&value;
386             // printf(neo4j_typestr(neo4j_type(V->fields[0])));
387              
388 3           hv = newHV();
389 3           id = neo4j_identity_value(neo4j_node_identity(value));
390 3           labels = neo4j_node_labels(value);
391 3           props_hv = neo4j_map_to_HV(neo4j_node_properties(value));
392 3           hv_stores(hv, "id", newSViv( (IV) id ));
393 3 100         if (neo4j_list_length(labels)) {
394 1           hv_stores(hv, "labels", neo4j_value_to_SV(labels));
395             }
396 3 100         if (HvTOTALKEYS(props_hv)) {
397 2           hv_stores(hv, "properties", newRV_noinc( (SV*) props_hv ));
398             }
399 3           return hv;
400             }
401              
402 3           HV* neo4j_relationship_to_HV( neo4j_value_t value ) {
403             HV *hv, *props_hv;
404             char *k;
405             SV *type,*v;
406             STRLEN len;
407             I32 retlen;
408             long long reln_id,start_id,end_id;
409 3           hv = newHV();
410 3           reln_id = neo4j_identity_value(neo4j_relationship_identity(value));
411 3           start_id = neo4j_identity_value(neo4j_relationship_start_node_identity(value));
412 3           end_id = neo4j_identity_value(neo4j_relationship_end_node_identity(value));
413 3           type = neo4j_string_to_SVpv(neo4j_relationship_type(value));
414 3           props_hv = neo4j_map_to_HV(neo4j_relationship_properties(value));
415 3           hv_stores(hv, "id", newSViv( (IV) reln_id ));
416 3           hv_stores(hv, "start", newSViv( (IV) start_id ));
417 3           hv_stores(hv, "end", newSViv( (IV) end_id ));
418 3 50         SvPV(type,len);
419 3           retlen = (I32) len;
420 3 100         if (retlen) {
421 2           hv_stores(hv, "type", type);
422             }
423 3 100         if (HvTOTALKEYS(props_hv)) {
424 1           hv_stores(hv, "properties", newRV_noinc( (SV*) props_hv ));
425             }
426 3           return hv;
427             }
428              
429 0           AV* neo4j_path_to_AV( neo4j_value_t value) {
430             int i,n,last_node_id,node_id;
431             AV* av;
432             struct neo4j_struct *v;
433             _Bool dir;
434             SV* rel_sv;
435             neo4j_value_t node;
436 0           av = newAV();
437 0           n = neo4j_path_length(value);
438 0           node = neo4j_path_get_node(value, 0);
439 0           av_push(av, neo4j_value_to_SV( node ));
440 0           last_node_id = neo4j_identity_value( neo4j_node_identity(node) );
441 0 0         if (n==0) {
442 0           return av;
443             } else {
444 0 0         for (i=1; i<=n; i++) {
445 0           node = neo4j_path_get_node(value,i);
446 0           node_id = neo4j_identity_value( neo4j_node_identity(node) );
447 0           rel_sv = neo4j_value_to_SV(neo4j_path_get_relationship(value,i-1,&dir));
448 0 0         hv_stores( (HV*) SvRV(rel_sv), "start", newSViv( (IV) (dir ? last_node_id : node_id)));
449 0 0         hv_stores( (HV*) SvRV(rel_sv), "end", newSViv( (IV) (dir ? node_id : last_node_id)));
450 0           av_push(av, rel_sv);
451 0           av_push(av, neo4j_value_to_SV(node));
452 0           last_node_id = node_id;
453             }
454 0           return av;
455             }
456             }
457              
458              
459             MODULE = Neo4j::Bolt::CTypeHandlers PACKAGE = Neo4j::Bolt::CTypeHandlers
460              
461             PROTOTYPES: DISABLE
462              
463