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   7202 use 5.010;
  17         54  
2 17     17   81 use strict;
  17         26  
  17         346  
3 17     17   73 use warnings;
  17         23  
  17         531  
4 17     17   90 use utf8;
  17         45  
  17         99  
5              
6             package Neo4j::Driver::Result;
7             # ABSTRACT: Result of running a Cypher statement (a stream of records)
8             $Neo4j::Driver::Result::VERSION = '0.38';
9              
10 17     17   920 use parent 'Neo4j::Driver::StatementResult';
  17         27  
  17         158  
11              
12 17     17   771 use Carp qw(croak);
  17         26  
  17         689  
13              
14 17     17   6117 use Neo4j::Driver::Record;
  17         39  
  17         514  
15 17     17   5866 use Neo4j::Driver::ResultColumns;
  17         52  
  17         484  
16 17     17   93 use Neo4j::Driver::ResultSummary;
  17         32  
  17         19913  
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 7 my ($class) = @_;
25            
26 3         24 return bless { buffer => [] }, $class;
27             }
28              
29              
30             sub _column_keys {
31 11     11   27 my ($self) = @_;
32            
33 11 100       70 $self->{columns} = Neo4j::Driver::ResultColumns->new($self->{result}) unless $self->{columns};
34 10         21 return $self->{columns};
35             }
36              
37              
38             sub keys {
39 7     7 1 3689 my ($self) = @_;
40            
41 7         14 return @{ $self->{result}->{columns} };
  7         116  
42             }
43              
44              
45             sub list {
46 281     281 1 7562 my ($self) = @_;
47            
48 281         596 $self->_fill_buffer;
49 281         352 $self->{exhausted} = 1;
50 281 100       901 return wantarray ? @{$self->{buffer}} : $self->{buffer};
  133         303  
51             }
52              
53              
54             sub size {
55 138     138 1 4752 my ($self) = @_;
56            
57 138         186 return scalar @{$self->list};
  138         593  
58             }
59              
60              
61             sub single {
62 127     127 1 18580 my ($self) = @_;
63            
64 127 100       341 croak 'There is not exactly one result record' if $self->size != 1;
65 124         1275 my ($record) = $self->list;
66 124 100       2789 $record->{_summary} = $self->summary if $self->{result}->{stats};
67 124         619 return $record;
68             }
69              
70              
71             sub _as_fully_buffered {
72 221     221   382 my ($self) = @_;
73            
74 221         456 $self->{attached} = $fake_attached;
75 221 100       476 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         409 $self->{buffer} = $self->{result}->{data};
81 218         1074 $self->{columns} = Neo4j::Driver::ResultColumns->new($self->{result});
82 218         301 $self->_init_record( $_ ) for @{ $self->{buffer} };
  218         746  
83 216         897 return $self;
84             }
85              
86              
87             sub _fill_buffer {
88 440     440   622 my ($self, $minimum) = @_;
89            
90 440 100       1060 return 0 unless $self->{attached};
91            
92 10 50       61 $self->_column_keys if $self->{result};
93            
94             # try to get at least $minimum records on the buffer
95 10         22 my $buffer = $self->{buffer};
96 10         14 my $count = 0;
97 10         17 my $next = 1;
98 10   100     66 while ( (! $minimum || @$buffer < $minimum)
      100        
99             && ($next = $self->_fetch_next) ) {
100 7         15 push @$buffer, $next;
101 7         25 $count++;
102             }
103            
104             # _fetch_next was called, but didn't return records => end of stream; detach
105 9 100       42 if (! $next) {
106 5 100       22 $self->{result}->{stats} = $self->{stream}->update_counts if $self->{stream};
107 5         19 $self->{cxn} = undef; # decrease reference count, allow garbage collection
108 5         12 $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   14 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         15 my $record = $self->{result}->{data}->[ $self->{json_cursor}++ ];
122 8 100       24 return undef unless $record; ##no critic (ProhibitExplicitReturnUndef)
123 5         15 return $self->_init_record( $record );
124             }
125              
126              
127             sub fetch {
128 57     57 1 40130 my ($self) = @_;
129            
130 57 100       179 return if $self->{exhausted}; # fetch() mustn't destroy a list() buffer
131 56         142 $self->_fill_buffer(1);
132 56         76 my $next = shift @{$self->{buffer}};
  56         105  
133 56         172 $self->{exhausted} = ! $next;
134 56         255 return $next;
135             }
136              
137              
138             sub peek {
139             # uncoverable pod (experimental feature)
140 3     3 0 2052 my ($self) = @_;
141            
142 3 100       29 croak "iterator is exhausted" if $self->{exhausted};
143 2         7 $self->_fill_buffer(1);
144 2         10 return $self->{buffer}->[0];
145             }
146              
147              
148             sub has_next {
149 24     24 1 15436 my ($self) = @_;
150            
151 24 100       93 return 0 if $self->{exhausted};
152 21         61 $self->_fill_buffer(1);
153 20         30 return scalar @{$self->{buffer}};
  20         92  
154             }
155              
156              
157             sub attached {
158             # uncoverable pod (see Deprecations.pod)
159 2     2 0 1811 my ($self) = @_;
160            
161 2         35 warnings::warnif deprecated => __PACKAGE__ . "->attached is deprecated";
162 2         1359 return $self->{attached};
163             }
164              
165              
166             sub detach {
167             # uncoverable pod (see Deprecations.pod)
168 1     1 0 1132 my ($self) = @_;
169            
170 1         16 warnings::warnif deprecated => __PACKAGE__ . "->detach is deprecated";
171 1         675 return $self->_fill_buffer;
172             }
173              
174              
175             sub consume {
176             # uncoverable pod (experimental feature)
177 1     1 0 64 my ($self) = @_;
178            
179             # Neo4j::Bolt doesn't offer direct access to neo4j_close_results()
180 1         3 $self->{exhausted} = 1;
181 1         4 return $self->summary;
182             }
183              
184              
185             sub summary {
186 76     76 1 2137 my ($self) = @_;
187            
188 76         174 $self->_fill_buffer;
189            
190 76   66     654 $self->{summary} //= Neo4j::Driver::ResultSummary->new( $self->{result}, $self->{notifications}, $self->{statement}, $self->{server_info} );
191            
192 76         255 return $self->{summary}->_init;
193             }
194              
195              
196             sub stats {
197             # uncoverable pod (see Deprecations.pod)
198 3     3 0 1680 my ($self) = @_;
199 3         49 warnings::warnif deprecated => __PACKAGE__ . "->stats is deprecated; use summary instead";
200            
201 3         1034 $self->_fill_buffer;
202 3 100       22 return $self->{result}->{stats} ? $self->summary->counters : {};
203             }
204              
205              
206             1;
207              
208             __END__