File Coverage

lib/Neo4j/Bolt/CTypeHandlers.xs
Criterion Covered Total %
statement 194 231 83.9
branch 104 168 61.9
condition n/a
subroutine n/a
pod n/a
total 298 399 74.6


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