File Coverage

blib/lib/REST/Neo4p/Node.pm
Criterion Covered Total %
statement 22 164 13.4
branch 0 66 0.0
condition 0 4 0.0
subroutine 8 20 40.0
pod 9 12 75.0
total 39 266 14.6


line stmt bran cond sub pod time code
1             #$Id$
2             package REST::Neo4p::Node;
3 36     36   263 use base 'REST::Neo4p::Entity';
  36         68  
  36         16038  
4 36     36   14801 use REST::Neo4p::Relationship;
  36         96  
  36         993  
5 36     36   236 use REST::Neo4p::Exceptions;
  36         67  
  36         578  
6 36     36   164 use JSON;
  36         56  
  36         207  
7 36     36   3964 use Carp qw(croak carp);
  36         93  
  36         1645  
8 36     36   212 use strict;
  36         100  
  36         816  
9 36     36   181 use warnings;
  36         69  
  36         1692  
10             BEGIN {
11 36     36   59798 $REST::Neo4p::Node::VERSION = '0.4000';
12             }
13              
14             # creation, deletion and property manipulation are delegated
15             # to the parent Entity.
16              
17             # $node1->relate_to($node2, $relationship_type, \%reln_props);
18             # direction is from $node1 -> $node2
19             # return the Relationship object
20             sub relate_to {
21 0     0 1   my $self = shift;
22 0           my ($target_node, $rel_type, $rel_props) = @_;
23 0           local $REST::Neo4p::HANDLE;
24 0           REST::Neo4p->set_handle($self->_handle);
25 0           my $agent = REST::Neo4p->agent;
26 0   0       my $suffix = $self->_get_url_suffix('create_relationship')
27             || 'relationships'; # weak workaround
28 0           my $content = {
29             'to' => $target_node->_self_url,
30             'type' => $rel_type
31             };
32 0 0         if ($rel_props) {
33 0           $content->{data} = $rel_props;
34             }
35 0           my $decoded_resp;
36 0           eval {
37 0           $decoded_resp = $agent->post_node([$$self,$suffix],
38             $content);
39             };
40 0           my $e;
41 0 0         if ($e = Exception::Class->caught('REST::Neo4p::Exception')) {
    0          
42             # TODO : handle different classes
43 0           $e->rethrow;
44             }
45             elsif ($@) {
46 0 0         ref $@ ? $@->rethrow : die $@;
47             }
48 0 0         return ref($decoded_resp) ?
49             REST::Neo4p::Relationship->new_from_json_response($decoded_resp) :
50             REST::Neo4p::Relationship->new_from_batch_response($decoded_resp);
51             }
52              
53             sub get_relationships {
54 0     0 1   my $self = shift;
55 0           my ($direction) = @_;
56 0   0       $direction ||= 'all';
57 0           local $REST::Neo4p::HANDLE;
58 0           REST::Neo4p->set_handle($self->_handle);
59 0           my $agent = REST::Neo4p->agent;
60 0           my $action;
61 0           for ($direction) {
62 0 0         /^all$/ && do {
63 0           $action = 'all_relationships';
64 0           last;
65             };
66 0 0         /^in$/ && do {
67 0           $action = 'incoming_relationships';
68 0           last;
69             };
70 0 0         /^out$/ && do {
71 0           $action = 'outgoing_relationships';
72 0           last;
73             };
74 0           do { # huh?
75 0           REST::Neo4p::LocalException->throw("Got '$direction' for relationship direction; expected [in|out|all]\n");
76             };
77             }
78 0           my $decoded_resp;
79 0           eval {
80 0           my @a = split /\//,$self->_get_url_suffix($action);
81 0           $decoded_resp = $agent->get_node($$self,@a);
82             };
83 0           my $e;
84 0 0         if ($e = Exception::Class->caught('REST::Neo4p::Exception')) {
    0          
85             # TODO : handle different classes
86 0           $e->rethrow;
87             }
88             elsif ($@) {
89 0 0         ref $@ ? $@->rethrow : die $@;
90             }
91 0           my @ret;
92             # TODO: handle Neo4j::Driver case
93 0 0         if (ref $decoded_resp eq 'HASH') {
94 0           $decoded_resp = [$decoded_resp];
95             }
96 0           for (@$decoded_resp) {
97 0 0         push @ret, ref($_) ?
98             REST::Neo4p::Relationship->new_from_json_response($_) :
99             REST::Neo4p::Relationship->new_from_batch_response($_);
100             }
101 0           return @ret;
102             }
103              
104             sub set_labels {
105 0     0 1   my $self = shift;
106 0           my @labels = @_;
107 0 0         unless (REST::Neo4p->_check_version(2)) {
108 0           REST::Neo4p::VersionMismatchException->throw("set_labels requires neo4j v2.0 or greater");
109             }
110 0           local $REST::Neo4p::HANDLE;
111 0           REST::Neo4p->set_handle($self->_handle);
112 0           my $agent = REST::Neo4p->agent;
113 0           my $decoded_resp;
114 0           eval {
115 0           $decoded_resp= $agent->put_node([$$self,'labels'],[@labels]);
116             };
117 0           my $e;
118 0 0         if ($e = Exception::Class->caught('REST::Neo4p::Exception')) {
    0          
119             # TODO : handle different classes
120 0           $e->rethrow;
121             }
122             elsif ($@) {
123 0 0         ref $@ ? $@->rethrow : die $@;
124             }
125 0           return $self;
126             }
127              
128             sub add_labels {
129 0     0 1   my $self = shift;
130 0           my @labels = @_;
131 0 0         unless (REST::Neo4p->_check_version(2)) {
132 0           REST::Neo4p::VersionMismatchException->throw("add_labels requires neo4j v2.0 or greater");
133             }
134 0           local $REST::Neo4p::HANDLE;
135 0           REST::Neo4p->set_handle($self->_handle);
136 0           my $agent = REST::Neo4p->agent;
137 0           my $decoded_resp;
138 0           eval {
139 0           $decoded_resp= $agent->post_node([$$self,'labels'],[@labels]);
140             };
141 0           my $e;
142 0 0         if ($e = Exception::Class->caught('REST::Neo4p::Exception')) {
    0          
143             # TODO : handle different classes
144 0           $e->rethrow;
145             }
146             elsif ($@) {
147 0 0         ref $@ ? $@->rethrow : die $@;
148             }
149 0           return $self;
150             }
151              
152             sub get_labels {
153 0     0 1   my $self = shift;
154 0 0         unless (REST::Neo4p->_check_version(2)) {
155 0           REST::Neo4p::VersionMismatchException->throw("get_labels requires neo4j v2.0 or greater");
156             }
157 0           local $REST::Neo4p::HANDLE;
158 0           REST::Neo4p->set_handle($self->_handle);
159 0           my $agent = REST::Neo4p->agent;
160 0           my $decoded_resp;
161 0           eval {
162 0           $decoded_resp = $agent->get_node($$self, 'labels');
163             };
164 0           my $e;
165 0 0         if ($e = Exception::Class->caught('REST::Neo4p::Exception')) {
    0          
166             # TODO : handle different classes
167 0           $e->rethrow;
168             }
169             elsif ($@) {
170 0 0         ref $@ ? $@->rethrow : die $@;
171             }
172             # TODO: handle Neo4j::Driver case
173 0           return @$decoded_resp;
174             }
175              
176             sub drop_labels {
177 0     0 1   my $self = shift;
178 0 0         unless (REST::Neo4p->_check_version(2)) {
179 0           REST::Neo4p::VersionMismatchException->throw("drop_labels requires neo4j v2.0 or greater");
180             }
181 0           my @labels = @_;
182 0 0         return $self unless @labels;
183 0           local $REST::Neo4p::HANDLE;
184 0           REST::Neo4p->set_handle($self->_handle);
185 0           my $agent = REST::Neo4p->agent;
186 0           my $decoded_resp;
187 0           eval {
188 0           foreach my $label (@labels) {
189 0           $decoded_resp = $agent->delete_node($$self, 'labels', $label);
190             }
191             };
192 0           my $e;
193 0 0         if ($e = Exception::Class->caught('REST::Neo4p::Exception')) {
    0          
194             # TODO : handle different classes
195 0           $e->rethrow;
196             }
197             elsif ($@) {
198 0 0         ref $@ ? $@->rethrow : die $@;
199             }
200 0           return $self;
201             }
202              
203 0     0 1   sub get_incoming_relationships { shift->get_relationships('in',@_) }
204 0     0 1   sub get_outgoing_relationships { shift->get_relationships('out',@_) }
205 0     0 0   sub get_all_relationships { shift->get_relationships('all',@_) }
206              
207             sub get_typed_relationships {
208 0     0 0   my $self = shift;
209 0           REST::Neo4p::NotImplException->throw( "get_typed_relationships() not implemented yet\n" );
210             }
211              
212             sub as_simple {
213 0     0 1   my $self = shift;
214 0           my $ret;
215 0           my $props = $self->get_properties;
216 0           $ret->{_node} = $$self + 0;
217 0           $ret->{$_} = $props->{$_} for keys %$props;
218 0           return $ret;
219             }
220              
221             sub simple_from_json_response {
222 0     0 0   my $class = shift;
223 0           my ($decoded_resp) = @_;
224 0           my $ret;
225 0           for (ref $decoded_resp) {
226 0 0         /HASH/ && do {
227             # node id
228 0           ($ret->{_node}) = $decoded_resp->{self} =~ m{.*/([0-9]+)$};
229             # node properties
230 0 0         if ($decoded_resp->{data}) {
231 0           $ret->{$_} = $decoded_resp->{data}->{$_} for keys %{$decoded_resp->{data}};
  0            
232             }
233             else { # use top-level keys except self
234 0           $ret->{$_} = $decoded_resp->{$_} for grep !/^self$/, keys %{$decoded_resp};
  0            
235             }
236 0           last;
237             };
238 0 0         /Driver/ && do {
239 0           $ret->{_node} = $decoded_resp->id;
240 0           $ret->{$_} = $decoded_resp->properties->{$_} for keys %{$decoded_resp->properties};
  0            
241 0           last;
242             };
243 0           do {
244 0           die "?";
245             };
246             }
247 0           return $ret;
248             }
249              
250             =head1 NAME
251              
252             REST::Neo4p::Node - Neo4j node object
253              
254             =head1 SYNOPSIS
255              
256             $n1 = REST::Neo4p::Node->new( {name => 'Ferb'} )
257             $n2 = REST::Neo4p::Node->new( {name => 'Phineas'} );
258             $n3 = REST::Neo4p::Node->new( {name => 'Perry'} );
259             $n1->relate_to($n2, 'brother');
260             $n3->relate_to($n1, 'pet');
261             $n3->set_property({ species => 'Ornithorhynchus anatinus' });
262              
263             =head1 DESCRIPTION
264              
265             REST::Neo4p::Node objects represent Neo4j nodes.
266              
267             =head1 METHODS
268              
269             =over
270              
271             =item new()
272              
273             $node = REST::Neo4p::Node->new();
274             $node_with_properties = REST::Neo4p::Node->new( \%props );
275              
276             Instantiates a new Node object and creates corresponding node in the database.
277              
278             =item remove()
279              
280             $node->remove()
281              
282             B: Removes a node from the database and destroys the object.
283              
284             =item get_property()
285              
286             $name = $node->get_property('name');
287             @vitals = $node->get_property( qw( height weight bp temp ) );
288              
289             Get the values of properties on nodes and relationships.
290              
291             =item set_property()
292              
293             $name = $node->set_property( {name => "Sun Tzu", occupation => "General"} );
294             $node1->relate_to($node2,"is_pal_of")->set_property( {duration => 'old pal'} );
295              
296             Sets values of properties on nodes and relationships.
297              
298             =item get_properties()
299              
300             $props = $node->get_properties;
301             print "'Sup, Al." if ($props->{name} eq 'Al');
302              
303             Get all the properties of a node or relationship as a hashref.
304              
305             =item remove_property()
306              
307             $node->remove_property('name');
308             $node->remove_property(@property_names);
309              
310             Remove properties from node.
311              
312             =item relate_to()
313              
314             $relationship = $node1->relate_to($node2, 'manager', { matrixed => 'yes' });
315              
316             Create a relationship between two nodes in the database and return the
317             L object. Call on the "from" node, first
318             argument is the "to" node, second argument is the relationship type,
319             third optional argument is a hashref of I properties.
320              
321             =item get_relationships()
322              
323             @all_relationships = $node1->get_relationships()
324              
325             Get all incoming and outgoing relationships of a node. Returns array
326             of L objects;
327              
328             =item get_incoming_relationships()
329              
330             @incoming_relationships = $node1->get_incoming_relationships();
331              
332             =item get_outgoing_relationships()
333              
334             @outgoing_relationships = $node1->get_outgoing_relationships();
335              
336             =item property auto-accessors
337              
338             See L.
339              
340             =item as_simple()
341              
342             $simple_node = $node1->as_simple
343             $node_id = $simple_node->{_node};
344             $value = $simple_node->{$property_name};
345              
346             Get node as a simple hashref.
347              
348             =back
349              
350             =head2 METHODS - Neo4j Version 2.0+
351              
352             These methods are supported by v2.0+ of the Neo4j server.
353              
354             =over
355              
356             =item set_labels()
357              
358             my $node = $node->set_labels($label1, $label2);
359              
360             Sets the node's labels. This replaces any existing node labels.
361              
362             =item add_labels()
363              
364             my $node = $node->add_labels($label3, $label4);
365              
366             Add labels to the nodes existing labels.
367              
368             =item get_labels()
369              
370             my @labels = $node->get_labels;
371              
372             Retrieve the node's list of labels, if any.
373              
374             =item drop_labels()
375              
376             my $node = $node->drop_labels($label1, $label4);
377              
378             Remove one or more labels from a node.
379              
380             =back
381              
382             =head1 SEE ALSO
383              
384             L, L, L.
385              
386             =head1 AUTHOR
387              
388             Mark A. Jensen
389             CPAN ID: MAJENSEN
390             majensen -at- cpan -dot- org
391              
392             =head1 LICENSE
393              
394             Copyright (c) 2012-2020 Mark A. Jensen. This program is free software; you
395             can redistribute it and/or modify it under the same terms as Perl
396             itself.
397              
398             =cut
399              
400              
401             1;