File Coverage

lib/Neo4j/Driver/Session.pm
Criterion Covered Total %
statement 105 105 100.0
branch 16 16 100.0
condition 13 13 100.0
subroutine 32 32 100.0
pod 5 7 100.0
total 171 173 100.0


line stmt bran cond sub pod time code
1 17     17   306 use 5.010;
  17         56  
2 17     17   89 use strict;
  17         29  
  17         391  
3 17     17   79 use warnings;
  17         24  
  17         448  
4 17     17   83 use utf8;
  17         32  
  17         122  
5              
6             package Neo4j::Driver::Session;
7             # ABSTRACT: Context of work for database interactions
8             $Neo4j::Driver::Session::VERSION = '0.38';
9              
10 17     17   1094 use Carp qw(croak);
  17         28  
  17         1435  
11             our @CARP_NOT = qw(
12             Neo4j::Driver
13             Try::Tiny
14             );
15 17     17   214 use List::Util qw(min);
  17         33  
  17         1995  
16 17     17   147 use Scalar::Util qw(blessed);
  17         28  
  17         840  
17 17     17   9354 use Time::HiRes ();
  17         24105  
  17         512  
18 17     17   7539 use Try::Tiny;
  17         31992  
  17         1123  
19 17     17   119 use URI 1.25;
  17         247  
  17         392  
20              
21 17     17   7034 use Neo4j::Driver::Net::Bolt;
  17         42  
  17         548  
22 17     17   6659 use Neo4j::Driver::Net::HTTP;
  17         60  
  17         773  
23 17     17   7379 use Neo4j::Driver::Transaction;
  17         39  
  17         477  
24 17     17   106 use Neo4j::Error;
  17         40  
  17         14872  
25              
26              
27             sub new {
28             # uncoverable pod (private method)
29 175     175 0 388 my ($class, $driver) = @_;
30            
31 175 100       653 return Neo4j::Driver::Session::Bolt->new($driver) if $driver->{uri}->scheme eq 'bolt';
32 162         4049 return Neo4j::Driver::Session::HTTP->new($driver);
33             }
34              
35              
36             # Connect and get ServerInfo (via Bolt HELLO or HTTP Discovery API),
37             # then determine the default database name for Neo4j >= 4.
38             sub _connect {
39 167     167   458 my ($self, $database) = @_;
40            
41 167         472 my $neo4j_version = $self->server->agent; # ensure contact with the server has been made
42 165 100       531 $self->{cypher_params_v2} = 0 if $neo4j_version =~ m{^Neo4j/2\.}; # no conversion required
43            
44 165   100     566 $database //= $self->server->_default_database($self->{driver});
45 163         688 $self->{net}->_set_database($database);
46 163         879 return $self;
47             }
48              
49              
50             sub begin_transaction {
51 33     33 1 11620 my ($self) = @_;
52            
53 33         100 return $self->new_tx->_begin;
54             }
55              
56              
57             sub run {
58 182     182 1 169840 my ($self, $query, @parameters) = @_;
59            
60 182         596 return $self->new_tx->_run_autocommit($query, @parameters);
61             }
62              
63              
64             sub _execute {
65 33     33   61 my ($self, $mode, $func) = @_;
66            
67 33 100       135 croak sprintf "%s->execute_%s() requires subroutine ref", __PACKAGE__, lc $mode unless ref $func eq 'CODE';
68            
69 31   100     107 $self->{retry_sleep} //= 1;
70 31         38 my (@r, $r);
71 31         54 my $wantarray = wantarray;
72             my $time_stop = Time::HiRes::time
73 31   100     168 + ($self->{driver}->{max_transaction_retry_time} // 30); # seconds
74 31         41 my $tries = 0;
75 31         48 my $success = 0;
76 31         35 do {
77 37         115 my $tx = $self->new_tx($mode);
78 37     11   168 $tx->{error_handler} = sub { die shift };
  11         115  
79            
80             try {
81 37     37   4079 $tx->_begin;
82 34         57 $tx->{managed} = 1; # Disallow commit() in $func
83 34 100       69 if ($wantarray) {
84 3         7 @r = $func->($tx);
85             }
86             else {
87 31         83 $r = $func->($tx);
88             }
89 15         64 $tx->{managed} = 0;
90 15         50 $tx->commit;
91 15         35 $success = 1; # return from sub not possible in a Try::Tiny block
92             }
93             catch {
94             # The tx may or may not already be closed; we need to make sure
95 22     22   5578 $tx->{managed} = 0;
96 22         119 try { $tx->rollback };
  22         1244  
97            
98             # Never retry non-Neo4j errors
99 22 100 100     11900 croak $_ unless blessed $_ && $_->isa('Neo4j::Error');
100            
101 11 100 100     55 if (! $_->is_retryable || Time::HiRes::time >= $time_stop) {
102 5         194 $self->{driver}->{plugins}->trigger( error => $_ );
103 1         35 $success = -1; # return in case the event handler doesn't die
104             }
105             else {
106             Time::HiRes::sleep min
107 6         110189 $self->{retry_sleep} * (1 << $tries++),
108             $time_stop - Time::HiRes::time;
109             }
110 37         252 };
111             } until ($success);
112 16 100       423 return $wantarray ? @r : $r;
113             }
114              
115              
116             sub execute_read {
117 19     19 1 13284 my ($self, $func) = @_;
118            
119 19         54 return $self->_execute( READ => $func );
120             }
121              
122              
123             sub execute_write {
124 14     14 1 7897 my ($self, $func) = @_;
125            
126 14         41 return $self->_execute( WRITE => $func );
127             }
128              
129              
130             sub close {
131             # uncoverable pod (see Deprecations.pod)
132 1     1 0 1779 warnings::warnif deprecated => __PACKAGE__ . "->close() is deprecated";
133             }
134              
135              
136             sub server {
137 253     253 1 4695 my ($self) = @_;
138            
139 253         453 my $server_info = $self->{driver}->{server_info};
140 253 100       886 return $server_info if defined $server_info;
141 81         273 return $self->{driver}->{server_info} = $self->{net}->_server;
142             }
143              
144              
145              
146              
147             package # private
148             Neo4j::Driver::Session::Bolt;
149 17     17   153 use parent -norequire => 'Neo4j::Driver::Session';
  17         53  
  17         86  
150              
151              
152             sub new {
153 13     13   275 my ($class, $driver) = @_;
154            
155             return bless {
156             cypher_params_v2 => $driver->{cypher_params_v2},
157 13         61 driver => $driver,
158             net => Neo4j::Driver::Net::Bolt->new($driver),
159             }, $class;
160             }
161              
162              
163             sub new_tx {
164 27     27   108 return Neo4j::Driver::Transaction::Bolt->new(@_);
165             }
166              
167              
168              
169              
170             package # private
171             Neo4j::Driver::Session::HTTP;
172 17     17   3138 use parent -norequire => 'Neo4j::Driver::Session';
  17         48  
  17         96  
173              
174              
175             sub new {
176 166     166   2211 my ($class, $driver) = @_;
177            
178             return bless {
179             cypher_params_v2 => $driver->{cypher_params_v2},
180 166         805 driver => $driver,
181             net => Neo4j::Driver::Net::HTTP->new($driver),
182             }, $class;
183             }
184              
185              
186             sub new_tx {
187 225     225   1178 return Neo4j::Driver::Transaction::HTTP->new(@_);
188             }
189              
190              
191             1;
192              
193             __END__