File Coverage

lib/Neo4j/Driver/Result.pm
Criterion Covered Total %
statement 89 91 97.8
branch 19 20 95.0
condition 14 16 87.5
subroutine 21 21 100.0
pod 8 10 100.0
total 151 158 96.8


line stmt bran cond sub pod time code
1 20     20   9123 use v5.12;
  20         74  
2 20     20   97 use warnings;
  20         29  
  20         1540  
3              
4             package Neo4j::Driver::Result 1.02;
5             # ABSTRACT: Result of running a Cypher query (a stream of records)
6              
7              
8 20     20   125 use Carp qw(croak);
  20         162  
  20         1345  
9              
10 20     20   8071 use Neo4j::Driver::Record;
  20         101  
  20         727  
11 20     20   111 use Neo4j::Driver::ResultSummary;
  20         29  
  20         18195  
12              
13              
14             our $fake_attached = 0; # 1: simulate an attached stream (only used in testing)
15              
16              
17             sub new {
18             # uncoverable pod (private method)
19 2     2 0 8 my ($class) = @_;
20            
21 2         15 return bless { buffer => [] }, $class;
22             }
23              
24              
25             sub keys {
26 9     9 1 4870 my ($self) = @_;
27            
28 9   100     96 return @{ $self->{result}->{columns} // [] };
  9         99  
29             }
30              
31              
32             sub list {
33 297     297 1 9925 my ($self) = @_;
34            
35 297         906 $self->_fill_buffer;
36 297         518 $self->{exhausted} = 1;
37 297 100       1384 return wantarray ? @{$self->{buffer}} : $self->{buffer};
  140         513  
38             }
39              
40              
41             sub size {
42 147     147 1 6778 my ($self) = @_;
43            
44 147         228 return scalar @{$self->list};
  147         545  
45             }
46              
47              
48             sub single {
49 136     136 1 11534 my ($self) = @_;
50            
51 136 100       2900 croak 'There is not exactly one result record' if $self->size != 1;
52 133         338 my ($record) = $self->list;
53 133         535 $record->{_summary} = $self->_summary;
54 133         773 return $record;
55             }
56              
57              
58             sub _as_fully_buffered {
59 228     228   496 my ($self) = @_;
60            
61 228         609 $self->{attached} = $fake_attached;
62 228 100       582 return $self if $fake_attached; # (only used in testing)
63            
64             # JSON results are completely available immediately and can be fully
65             # buffered right away, avoiding the need to loop through _fetch_next().
66             # (also used in Bolt/Jolt testing, $gather_results 1)
67 225         643 $self->{buffer} = $self->{result}->{data};
68 225         912 $self->{field_names_cache} = Neo4j::Driver::Record::_field_names_cache( $self->{result} );
69 225         382 $self->_init_record( $_ ) for @{ $self->{buffer} };
  225         1080  
70 223         1109 return $self;
71             }
72              
73              
74             sub _fill_buffer {
75 543     543   1017 my ($self, $minimum) = @_;
76            
77 543 100       1435 return 0 unless $self->{attached};
78            
79 9   66     74 $self->{field_names_cache} //= Neo4j::Driver::Record::_field_names_cache( $self->{result} );
80            
81             # try to get at least $minimum records on the buffer
82 9         18 my $buffer = $self->{buffer};
83 9         17 my $count = 0;
84 9         16 my $next = 1;
85 9   100     112 while ( (! $minimum || @$buffer < $minimum)
      100        
86             && ($next = $self->_fetch_next) ) {
87 8         22 push @$buffer, $next;
88 8         32 $count++;
89             }
90            
91             # _fetch_next was called, but didn't return records => end of stream; detach
92 8 100       22 if (! $next) {
93 6 100       34 $self->{result}->{stats} = $self->{stream}->update_counts if $self->{stream};
94 6         24 $self->{cxn} = undef; # decrease reference count, allow garbage collection
95 6         18 $self->{stream} = undef;
96 6         14 $self->{attached} = 0;
97             }
98            
99 8         14 return $count;
100             }
101              
102              
103             sub _fetch_next {
104 8     8   18 my ($self) = @_;
105            
106             # simulate a JSON-backed result stream (only used in testing, $fake_attached 1)
107 8   100     30 $self->{json_cursor} //= 0;
108 8         20 my $record = $self->{result}->{data}->[ $self->{json_cursor}++ ];
109 8 100       27 return undef unless $record; ##no critic (ProhibitExplicitReturnUndef)
110 5         17 return $self->_init_record( $record );
111             }
112              
113              
114             sub fetch {
115 78     78 1 45875 my ($self) = @_;
116            
117 78 100       340 return if $self->{exhausted}; # fetch() mustn't destroy a list() buffer
118 74         296 $self->_fill_buffer(2);
119 74         114 my $next = shift @{$self->{buffer}};
  74         187  
120 74         233 $self->{exhausted} = ! $next;
121 74         407 return $next;
122             }
123              
124              
125             sub peek {
126 3     3 1 2037 my ($self) = @_;
127            
128 3         11 $self->_fill_buffer(1);
129 3         16 return scalar $self->{buffer}->[0];
130             }
131              
132              
133             sub has_next {
134 23     23 1 26533 my ($self) = @_;
135            
136 23 100       132 return 0 if $self->{exhausted};
137 20         125 $self->_fill_buffer(1);
138 19         30 return scalar @{$self->{buffer}};
  19         173  
139             }
140              
141              
142             sub consume {
143 15     15 1 15273 my ($self) = @_;
144            
145 15         69 1 while $self->fetch; # Exhaust the result stream
146 15         63 return $self->_summary;
147             }
148              
149              
150             sub summary {
151             # uncoverable pod (see consume)
152 1     1 0 125 warnings::warnif deprecated => "summary() in Neo4j::Driver::Result is deprecated; use consume() instead";
153 1         3506 &_summary;
154             }
155              
156              
157             sub _summary {
158 149     149   282 my ($self) = @_;
159            
160 149         392 $self->_fill_buffer;
161            
162 149   66     1593 $self->{summary} //= Neo4j::Driver::ResultSummary->new( $self->{result}, $self->{notifications}, $self->{query}, $self->{server_info} );
163            
164 149         653 return $self->{summary};
165             }
166              
167              
168             sub _bool_values {
169 20     20   160 no if $^V ge v5.36, 'warnings', 'experimental::builtin';
  20         56  
  20         3086  
170 40 50   40   1248 if ( $^V ge v5.36 ) {
171 40         283 return builtin::false(), builtin::true();
172             }
173             else {
174 0           require JSON::PP;
175 0           return JSON::PP::false(), JSON::PP::true();
176             }
177             }
178              
179              
180             1;
181              
182             __END__