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   7584 use 5.010;
  17         51  
2 17     17   77 use strict;
  17         21  
  17         349  
3 17     17   90 use warnings;
  17         28  
  17         558  
4 17     17   81 use utf8;
  17         48  
  17         132  
5              
6             package Neo4j::Driver::Result;
7             # ABSTRACT: Result of running a Cypher statement (a stream of records)
8             $Neo4j::Driver::Result::VERSION = '0.40';
9              
10 17     17   1018 use parent 'Neo4j::Driver::StatementResult';
  17         36  
  17         169  
11              
12 17     17   727 use Carp qw(croak);
  17         29  
  17         735  
13              
14 17     17   6283 use Neo4j::Driver::Record;
  17         32  
  17         511  
15 17     17   5919 use Neo4j::Driver::ResultColumns;
  17         36  
  17         475  
16 17     17   92 use Neo4j::Driver::ResultSummary;
  17         38  
  17         21032  
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 17 my ($class) = @_;
25            
26 3         29 return bless { buffer => [] }, $class;
27             }
28              
29              
30             sub _column_keys {
31 11     11   25 my ($self) = @_;
32            
33 11 100       66 $self->{columns} = Neo4j::Driver::ResultColumns->new($self->{result}) unless $self->{columns};
34 10         18 return $self->{columns};
35             }
36              
37              
38             sub keys {
39 7     7 1 3161 my ($self) = @_;
40            
41 7         12 return @{ $self->{result}->{columns} };
  7         36  
42             }
43              
44              
45             sub list {
46 281     281 1 7731 my ($self) = @_;
47            
48 281         576 $self->_fill_buffer;
49 281         691 $self->{exhausted} = 1;
50 281 100       1882 return wantarray ? @{$self->{buffer}} : $self->{buffer};
  133         306  
51             }
52              
53              
54             sub size {
55 138     138 1 4623 my ($self) = @_;
56            
57 138         180 return scalar @{$self->list};
  138         309  
58             }
59              
60              
61             sub single {
62 127     127 1 19292 my ($self) = @_;
63            
64 127 100       1638 croak 'There is not exactly one result record' if $self->size != 1;
65 124         250 my ($record) = $self->list;
66 124 100       449 $record->{_summary} = $self->summary if $self->{result}->{stats};
67 124         554 return $record;
68             }
69              
70              
71             sub _as_fully_buffered {
72 221     221   391 my ($self) = @_;
73            
74 221         371 $self->{attached} = $fake_attached;
75 221 100       452 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         391 $self->{buffer} = $self->{result}->{data};
81 218         957 $self->{columns} = Neo4j::Driver::ResultColumns->new($self->{result});
82 218         296 $self->_init_record( $_ ) for @{ $self->{buffer} };
  218         717  
83 216         822 return $self;
84             }
85              
86              
87             sub _fill_buffer {
88 440     440   1851 my ($self, $minimum) = @_;
89            
90 440 100       1041 return 0 unless $self->{attached};
91            
92 10 50       47 $self->_column_keys if $self->{result};
93            
94             # try to get at least $minimum records on the buffer
95 10         28 my $buffer = $self->{buffer};
96 10         15 my $count = 0;
97 10         14 my $next = 1;
98 10   100     63 while ( (! $minimum || @$buffer < $minimum)
      100        
99             && ($next = $self->_fetch_next) ) {
100 7         14 push @$buffer, $next;
101 7         24 $count++;
102             }
103            
104             # _fetch_next was called, but didn't return records => end of stream; detach
105 9 100       24 if (! $next) {
106 5 100       19 $self->{result}->{stats} = $self->{stream}->update_counts if $self->{stream};
107 5         13 $self->{cxn} = undef; # decrease reference count, allow garbage collection
108 5         14 $self->{stream} = undef;
109 5         9 $self->{attached} = 0;
110             }
111            
112 9         13 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     28 $self->{json_cursor} //= 0;
121 8         17 my $record = $self->{result}->{data}->[ $self->{json_cursor}++ ];
122 8 100       23 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 39746 my ($self) = @_;
129            
130 57 100       172 return if $self->{exhausted}; # fetch() mustn't destroy a list() buffer
131 56         122 $self->_fill_buffer(1);
132 56         67 my $next = shift @{$self->{buffer}};
  56         102  
133 56         115 $self->{exhausted} = ! $next;
134 56         270 return $next;
135             }
136              
137              
138             sub peek {
139             # uncoverable pod (experimental feature)
140 3     3 0 1868 my ($self) = @_;
141            
142 3 100       31 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 14859 my ($self) = @_;
150            
151 24 100       87 return 0 if $self->{exhausted};
152 21         56 $self->_fill_buffer(1);
153 20         31 return scalar @{$self->{buffer}};
  20         92  
154             }
155              
156              
157             sub attached {
158             # uncoverable pod (see Deprecations.pod)
159 2     2 0 1765 my ($self) = @_;
160            
161 2         34 warnings::warnif deprecated => __PACKAGE__ . "->attached is deprecated";
162 2         1405 return $self->{attached};
163             }
164              
165              
166             sub detach {
167             # uncoverable pod (see Deprecations.pod)
168 1     1 0 1155 my ($self) = @_;
169            
170 1         16 warnings::warnif deprecated => __PACKAGE__ . "->detach is deprecated";
171 1         667 return $self->_fill_buffer;
172             }
173              
174              
175             sub consume {
176             # uncoverable pod (experimental feature)
177 1     1 0 62 my ($self) = @_;
178            
179             # Neo4j::Bolt doesn't offer direct access to neo4j_close_results()
180 1         2 $self->{exhausted} = 1;
181 1         4 return $self->summary;
182             }
183              
184              
185             sub summary {
186 76     76 1 950 my ($self) = @_;
187            
188 76         169 $self->_fill_buffer;
189            
190 76   66     636 $self->{summary} //= Neo4j::Driver::ResultSummary->new( $self->{result}, $self->{notifications}, $self->{statement}, $self->{server_info} );
191            
192 76         230 return $self->{summary}->_init;
193             }
194              
195              
196             sub stats {
197             # uncoverable pod (see Deprecations.pod)
198 3     3 0 1590 my ($self) = @_;
199 3         44 warnings::warnif deprecated => __PACKAGE__ . "->stats is deprecated; use summary instead";
200            
201 3         1039 $self->_fill_buffer;
202 3 100       53 return $self->{result}->{stats} ? $self->summary->counters : {};
203             }
204              
205              
206             1;
207              
208             __END__