File Coverage

lib/Neo4j/Driver.pm
Criterion Covered Total %
statement 122 122 100.0
branch 68 68 100.0
condition 15 16 93.7
subroutine 22 22 100.0
pod 4 6 100.0
total 231 234 99.5


line stmt bran cond sub pod time code
1 17     17   621717 use 5.010;
  17         147  
2 17     17   102 use strict;
  17         28  
  17         435  
3 17     17   89 use warnings;
  17         27  
  17         471  
4 17     17   8388 use utf8;
  17         205  
  17         108  
5              
6             package Neo4j::Driver;
7             # ABSTRACT: Neo4j community graph database driver for Bolt and HTTP
8             $Neo4j::Driver::VERSION = '0.38';
9              
10 17     17   1012 use Carp qw(croak);
  17         36  
  17         1293  
11              
12 17     17   1839 use URI 1.25;
  17         19153  
  17         520  
13 17     17   6499 use Neo4j::Driver::Events;
  17         38  
  17         591  
14 17     17   6978 use Neo4j::Driver::Session;
  17         47  
  17         642  
15              
16 17     17   6721 use Neo4j::Driver::Type::Node;
  17         44  
  17         559  
17 17     17   6910 use Neo4j::Driver::Type::Relationship;
  17         50  
  17         549  
18 17     17   6079 use Neo4j::Driver::Type::Path;
  17         52  
  17         492  
19 17     17   6161 use Neo4j::Driver::Type::Point;
  17         41  
  17         493  
20 17     17   6141 use Neo4j::Driver::Type::Temporal;
  17         39  
  17         26679  
21              
22              
23             my %NEO4J_DEFAULT_PORT = (
24             bolt => 7687,
25             http => 7474,
26             https => 7473,
27             );
28              
29             my %OPTIONS = (
30             auth => 'auth',
31             ca_file => 'tls_ca',
32             cypher_filter => 'cypher_filter',
33             cypher_params => 'cypher_params_v2',
34             cypher_types => 'cypher_types',
35             encrypted => 'tls',
36             jolt => 'jolt',
37             concurrent_tx => 'concurrent_tx',
38             max_transaction_retry_time => 'max_transaction_retry_time',
39             net_module => 'net_module',
40             timeout => 'timeout',
41             tls => 'tls',
42             tls_ca => 'tls_ca',
43             trust_ca => 'tls_ca',
44             uri => 'uri',
45             );
46              
47             my %DEFAULTS = (
48             cypher_types => {
49             node => 'Neo4j::Driver::Type::Node',
50             relationship => 'Neo4j::Driver::Type::Relationship',
51             path => 'Neo4j::Driver::Type::Path',
52             point => 'Neo4j::Driver::Type::Point',
53             temporal => 'Neo4j::Driver::Type::Temporal',
54             },
55             die_on_error => 1,
56             );
57              
58              
59             sub new {
60 167     167 1 781500 my ($class, $config, @extra) = @_;
61            
62 167         712 my $self = bless { %DEFAULTS }, $class;
63 167         687 $self->{plugins} = Neo4j::Driver::Events->new;
64            
65 167 100       509 croak __PACKAGE__ . "->new() with multiple arguments unsupported" if @extra;
66 166 100       644 $config = { uri => $config } if ref $config ne 'HASH';
67 166   100     538 $config->{uri} //= ''; # force config() to call _check_uri()
68 166         434 return $self->config($config);
69             }
70              
71              
72             sub _check_uri {
73 186     186   337 my ($self) = @_;
74            
75 186         301 my $uri = $self->{uri};
76            
77 186 100       365 if ($uri) {
78 109 100       638 $uri = "[$uri]" if $uri =~ m{^[0-9a-f:]*::|^(?:[0-9a-f]+:){6}}i;
79 109 100 100     811 $uri =~ s|^|http://| if $uri !~ m{:|/} || $uri =~ m{^\[.+\]$};
80 109 100       255 $uri =~ s|^|http:| if $uri =~ m{^//};
81 109         380 $uri = URI->new($uri);
82            
83 109 100       13458 if ( ! $uri->scheme ) {
84 5         116 croak sprintf "Failed to parse URI '%s'", $uri;
85             }
86 104 100       2214 if ( $uri->scheme !~ m/^https?$|^bolt$/ ) {
87 6   50     87 croak sprintf "URI scheme '%s' unsupported; use 'http' or 'bolt'", $uri->scheme // "";
88             }
89            
90 98 100       1581 if (my $userinfo = $uri->userinfo(undef)) {
91 10         580 my @userinfo = $userinfo =~ m/^([^:]*):?(.*)/;
92 10         18 @userinfo = map { URI::Escape::uri_unescape $_ } @userinfo;
  20         151  
93 10         121 utf8::decode $_ for @userinfo;
94 10         23 $self->basic_auth(@userinfo);
95             }
96 98 100       5466 $uri->host('localhost') unless $uri->host;
97 98 100       6831 $uri->path('') if $uri->path_query eq '/';
98 98         1436 $uri->fragment(undef);
99             }
100             else {
101 77         321 $uri = URI->new("http://localhost");
102             }
103 175 100       20928 $uri->port( $NEO4J_DEFAULT_PORT{ $uri->scheme } ) if ! $uri->_port;
104            
105 175         17232 $self->{uri} = $uri;
106             }
107              
108              
109             sub basic_auth {
110 41     41 1 1584 my ($self, $username, $password) = @_;
111            
112 41 100       189 warnings::warnif deprecated => "Deprecated sequence: call basic_auth() before session()" if $self->{server_info};
113            
114             $self->{auth} = {
115 41         1506 scheme => 'basic',
116             principal => $username,
117             credentials => $password,
118             };
119            
120 41         91 return $self;
121             }
122              
123              
124             sub config {
125 332     332 1 34696 my ($self, @options) = @_;
126            
127 332 100 100     1333 @options = %{$options[0]} if @options == 1 && ref $options[0] eq 'HASH';
  169         545  
128 332 100       735 croak "config() without options unsupported" unless @options;
129            
130 330 100       722 if (@options < 2) {
131             # get config option
132 68         116 my $key = $options[0];
133 68 100       1559 croak "Unsupported config option: $key" unless grep m/^$key$/, keys %OPTIONS;
134 67         515 return $self->{$OPTIONS{$key}};
135             }
136            
137 262 100       550 croak "Unsupported sequence: call config() before session()" if $self->{server_info};
138 261         1691 my %options = $self->_parse_options('config', [keys %OPTIONS], @options);
139            
140             # set config option
141 255         1083 my @keys = reverse sort keys %options; # auth should take precedence over uri
142 255         473 foreach my $key (@keys) {
143 278         731 $self->{$OPTIONS{$key}} = $options{$key};
144 278 100       837 $self->_check_uri if $OPTIONS{$key} eq 'uri';
145             }
146 244         1339 return $self;
147             }
148              
149              
150             sub session {
151 176     176 1 62797 my ($self, @options) = @_;
152            
153 176         535 $self->{plugins}->{die_on_error} = $self->{die_on_error};
154 176 100       477 warnings::warnif deprecated => __PACKAGE__ . "->{die_on_error} is deprecated" unless $self->{die_on_error};
155 176 100       3256 warnings::warnif deprecated => __PACKAGE__ . "->{http_timeout} is deprecated; use config()" if defined $self->{http_timeout};
156 176   100     1350 $self->{timeout} //= $self->{http_timeout};
157            
158 176 100 100     525 @options = %{$options[0]} if @options == 1 && ref $options[0] eq 'HASH';
  2         8  
159 176         588 my %options = $self->_parse_options('session', ['database'], @options);
160            
161 175         978 my $session = Neo4j::Driver::Session->new($self);
162 167         745 return $session->_connect($options{database});
163             }
164              
165              
166             sub _parse_options {
167 437     437   1056 my (undef, $context, $supported, @options) = @_;
168            
169 437 100       1094 croak "Odd number of elements in $context options hash" if @options & 1;
170 435         1043 my %options = @options;
171            
172 435 100       866 warnings::warnif deprecated => "Config option ca_file is deprecated; use trust_ca" if $options{ca_file};
173 435 100       1642 warnings::warnif deprecated => "Config option cypher_types is deprecated" if $options{cypher_types};
174 435 100       1485 if ($options{cypher_params}) {
    100          
175 26 100       115 croak "Unimplemented cypher params filter '$options{cypher_params}'" if $options{cypher_params} ne v2;
176             }
177             elsif ($options{cypher_filter}) {
178 2         36 warnings::warnif deprecated => "Config option cypher_filter is deprecated; use cypher_params";
179 2 100       1710 croak "Unimplemented cypher filter '$options{cypher_filter}'" if $options{cypher_filter} ne 'params';
180 1         4 $options{cypher_params} = v2;
181             }
182 433 100       871 warnings::warnif deprecated => "Config option jolt is deprecated: Jolt is now enabled by default" if defined $options{jolt};
183 433 100       3174 warnings::warnif deprecated => "Config option net_module is deprecated; use plug-in interface" if defined $options{net_module};
184            
185 433         2190 my @unsupported = ();
186 433         888 foreach my $key (keys %options) {
187 373 100       7740 push @unsupported, $key unless grep m/^$key$/, @$supported;
188             }
189 433 100       1157 croak "Unsupported $context option: " . join ", ", sort @unsupported if @unsupported;
190            
191 430         1579 return %options;
192             }
193              
194              
195             sub plugin {
196             # uncoverable pod (experimental feature)
197 76     76 0 3654 my ($self, $package, @extra) = @_;
198            
199 76 100       217 croak "plugin() with more than one argument is unsupported" if @extra;
200 75         301 $self->{plugins}->_register_plugin($package);
201 75         247 return $self;
202             }
203              
204              
205             sub close {
206             # uncoverable pod (see Deprecations.pod)
207 1     1 0 2747 warnings::warnif deprecated => __PACKAGE__ . "->close() is deprecated";
208             }
209              
210              
211              
212              
213             package # private
214             URI::bolt;
215              
216 17     17   141 use parent 'URI::_server';
  17         31  
  17         95  
217              
218             # The server methods need to be available for bolt: URI instances
219             # even when the Neo4j-Bolt distribution is not installed.
220              
221            
222             1;
223              
224             __END__