File Coverage

lib/Neo4j/Driver/Result.pm
Criterion Covered Total %
statement 108 108 100.0
branch 27 28 96.4
condition 10 11 90.9
subroutine 26 26 100.0
pod 7 13 100.0
total 178 186 98.9


line stmt bran cond sub pod time code
1 17     17   7125 use 5.010;
  17         54  
2 17     17   78 use strict;
  17         23  
  17         354  
3 17     17   73 use warnings;
  17         25  
  17         583  
4 17     17   127 use utf8;
  17         41  
  17         96  
5              
6             package Neo4j::Driver::Result;
7             # ABSTRACT: Result of running a Cypher statement (a stream of records)
8             $Neo4j::Driver::Result::VERSION = '0.39';
9              
10 17     17   888 use parent 'Neo4j::Driver::StatementResult';
  17         27  
  17         173  
11              
12 17     17   755 use Carp qw(croak);
  17         31  
  17         698  
13              
14 17     17   6046 use Neo4j::Driver::Record;
  17         80  
  17         562  
15 17     17   6348 use Neo4j::Driver::ResultColumns;
  17         34  
  17         487  
16 17     17   97 use Neo4j::Driver::ResultSummary;
  17         24  
  17         20326  
17              
18              
19             our $fake_attached = 0; # 1: simulate an attached stream (only used in testing)
20              
21              
22             sub new {
23             # uncoverable pod (private method)
24 3     3 0 9 my ($class) = @_;
25            
26 3         22 return bless { buffer => [] }, $class;
27             }
28              
29              
30             sub _column_keys {
31 11     11   22 my ($self) = @_;
32            
33 11 100       78 $self->{columns} = Neo4j::Driver::ResultColumns->new($self->{result}) unless $self->{columns};
34 10         14 return $self->{columns};
35             }
36              
37              
38             sub keys {
39 7     7 1 3653 my ($self) = @_;
40            
41 7         11 return @{ $self->{result}->{columns} };
  7         40  
42             }
43              
44              
45             sub list {
46 281     281 1 6967 my ($self) = @_;
47            
48 281         603 $self->_fill_buffer;
49 281         344 $self->{exhausted} = 1;
50 281 100       3200 return wantarray ? @{$self->{buffer}} : $self->{buffer};
  133         314  
51             }
52              
53              
54             sub size {
55 138     138 1 4695 my ($self) = @_;
56            
57 138         176 return scalar @{$self->list};
  138         339  
58             }
59              
60              
61             sub single {
62 127     127 1 18489 my ($self) = @_;
63            
64 127 100       1384 croak 'There is not exactly one result record' if $self->size != 1;
65 124         266 my ($record) = $self->list;
66 124 100       480 $record->{_summary} = $self->summary if $self->{result}->{stats};
67 124         528 return $record;
68             }
69              
70              
71             sub _as_fully_buffered {
72 221     221   388 my ($self) = @_;
73            
74 221         384 $self->{attached} = $fake_attached;
75 221 100       464 return $self if $fake_attached; # (only used in testing)
76            
77             # JSON results are completely available immediately and can be fully
78             # buffered right away, avoiding the need to loop through _fetch_next().
79             # (also used in Bolt/Jolt testing, $gather_results 1)
80 218         419 $self->{buffer} = $self->{result}->{data};
81 218         1068 $self->{columns} = Neo4j::Driver::ResultColumns->new($self->{result});
82 218         345 $self->_init_record( $_ ) for @{ $self->{buffer} };
  218         764  
83 216         849 return $self;
84             }
85              
86              
87             sub _fill_buffer {
88 440     440   640 my ($self, $minimum) = @_;
89            
90 440 100       1017 return 0 unless $self->{attached};
91            
92 10 50       55 $self->_column_keys if $self->{result};
93            
94             # try to get at least $minimum records on the buffer
95 10         27 my $buffer = $self->{buffer};
96 10         17 my $count = 0;
97 10         14 my $next = 1;
98 10   100     67 while ( (! $minimum || @$buffer < $minimum)
      100        
99             && ($next = $self->_fetch_next) ) {
100 7         18 push @$buffer, $next;
101 7         26 $count++;
102             }
103            
104             # _fetch_next was called, but didn't return records => end of stream; detach
105 9 100       28 if (! $next) {
106 5 100       20 $self->{result}->{stats} = $self->{stream}->update_counts if $self->{stream};
107 5         13 $self->{cxn} = undef; # decrease reference count, allow garbage collection
108 5         10 $self->{stream} = undef;
109 5         10 $self->{attached} = 0;
110             }
111            
112 9         15 return $count;
113             }
114              
115              
116             sub _fetch_next {
117 8     8   17 my ($self) = @_;
118            
119             # simulate a JSON-backed result stream (only used in testing, $fake_attached 1)
120 8   100     29 $self->{json_cursor} //= 0;
121 8         18 my $record = $self->{result}->{data}->[ $self->{json_cursor}++ ];
122 8 100       25 return undef unless $record; ##no critic (ProhibitExplicitReturnUndef)
123 5         14 return $self->_init_record( $record );
124             }
125              
126              
127             sub fetch {
128 57     57 1 35341 my ($self) = @_;
129            
130 57 100       175 return if $self->{exhausted}; # fetch() mustn't destroy a list() buffer
131 56         151 $self->_fill_buffer(1);
132 56         73 my $next = shift @{$self->{buffer}};
  56         107  
133 56         120 $self->{exhausted} = ! $next;
134 56         267 return $next;
135             }
136              
137              
138             sub peek {
139             # uncoverable pod (experimental feature)
140 3     3 0 1994 my ($self) = @_;
141            
142 3 100       35 croak "iterator is exhausted" if $self->{exhausted};
143 2         6 $self->_fill_buffer(1);
144 2         8 return $self->{buffer}->[0];
145             }
146              
147              
148             sub has_next {
149 24     24 1 14038 my ($self) = @_;
150            
151 24 100       98 return 0 if $self->{exhausted};
152 21         62 $self->_fill_buffer(1);
153 20         27 return scalar @{$self->{buffer}};
  20         90  
154             }
155              
156              
157             sub attached {
158             # uncoverable pod (see Deprecations.pod)
159 2     2 0 1738 my ($self) = @_;
160            
161 2         34 warnings::warnif deprecated => __PACKAGE__ . "->attached is deprecated";
162 2         1382 return $self->{attached};
163             }
164              
165              
166             sub detach {
167             # uncoverable pod (see Deprecations.pod)
168 1     1 0 1078 my ($self) = @_;
169            
170 1         15 warnings::warnif deprecated => __PACKAGE__ . "->detach is deprecated";
171 1         710 return $self->_fill_buffer;
172             }
173              
174              
175             sub consume {
176             # uncoverable pod (experimental feature)
177 1     1 0 67 my ($self) = @_;
178            
179             # Neo4j::Bolt doesn't offer direct access to neo4j_close_results()
180 1         3 $self->{exhausted} = 1;
181 1         5 return $self->summary;
182             }
183              
184              
185             sub summary {
186 76     76 1 987 my ($self) = @_;
187            
188 76         182 $self->_fill_buffer;
189            
190 76   66     665 $self->{summary} //= Neo4j::Driver::ResultSummary->new( $self->{result}, $self->{notifications}, $self->{statement}, $self->{server_info} );
191            
192 76         256 return $self->{summary}->_init;
193             }
194              
195              
196             sub stats {
197             # uncoverable pod (see Deprecations.pod)
198 3     3 0 1777 my ($self) = @_;
199 3         64 warnings::warnif deprecated => __PACKAGE__ . "->stats is deprecated; use summary instead";
200            
201 3         1077 $self->_fill_buffer;
202 3 100       26 return $self->{result}->{stats} ? $self->summary->counters : {};
203             }
204              
205              
206             1;
207              
208             __END__