File Coverage

lib/Neo4j/Driver.pm
Criterion Covered Total %
statement 125 125 100.0
branch 70 70 100.0
condition 18 19 94.7
subroutine 22 22 100.0
pod 4 6 100.0
total 239 242 99.5


line stmt bran cond sub pod time code
1 17     17   628604 use 5.010;
  17         151  
2 17     17   155 use strict;
  17         36  
  17         425  
3 17     17   94 use warnings;
  17         30  
  17         463  
4 17     17   8790 use utf8;
  17         212  
  17         95  
5              
6             package Neo4j::Driver;
7             # ABSTRACT: Neo4j community graph database driver for Bolt and HTTP
8             $Neo4j::Driver::VERSION = '0.40';
9              
10 17     17   972 use Carp qw(croak);
  17         32  
  17         1146  
11              
12 17     17   1889 use URI 1.25;
  17         19909  
  17         433  
13 17     17   6314 use Neo4j::Driver::Events;
  17         36  
  17         479  
14 17     17   6690 use Neo4j::Driver::Session;
  17         67  
  17         640  
15              
16 17     17   7008 use Neo4j::Driver::Type::Node;
  17         42  
  17         573  
17 17     17   6751 use Neo4j::Driver::Type::Relationship;
  17         40  
  17         513  
18 17     17   6258 use Neo4j::Driver::Type::Path;
  17         41  
  17         510  
19 17     17   6080 use Neo4j::Driver::Type::Point;
  17         35  
  17         484  
20 17     17   6002 use Neo4j::Driver::Type::Temporal;
  17         36  
  17         28806  
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             );
56              
57              
58             sub new {
59 167     167 1 745243 my ($class, $config, @extra) = @_;
60            
61 167         756 my $self = bless { config => { %DEFAULTS }, die_on_error => 1 }, $class;
62 167         664 $self->{plugins} = Neo4j::Driver::Events->new;
63            
64 167 100       489 croak __PACKAGE__ . "->new() with multiple arguments unsupported" if @extra;
65 166 100       597 $config = { uri => $config } if ref $config ne 'HASH';
66 166   100     525 $config->{uri} //= ''; # force config() to call _check_uri()
67 166         371 return $self->config($config);
68             }
69              
70              
71             sub _check_uri {
72 186     186   345 my ($self) = @_;
73            
74 186         299 my $uri = $self->{config}->{uri};
75            
76 186 100       388 if ($uri) {
77 109 100       626 $uri = "[$uri]" if $uri =~ m{^[0-9a-f:]*::|^(?:[0-9a-f]+:){6}}i;
78 109 100 100     844 $uri =~ s|^|http://| if $uri !~ m{:|/} || $uri =~ m{^\[.+\]$};
79 109 100       260 $uri =~ s|^|http:| if $uri =~ m{^//};
80 109         393 $uri = URI->new($uri);
81            
82 109 100       13469 if ( ! $uri->scheme ) {
83 5         119 croak sprintf "Failed to parse URI '%s'", $uri;
84             }
85 104 100       2279 if ( $uri->scheme !~ m/^https?$|^bolt$/ ) {
86 6   50     103 croak sprintf "URI scheme '%s' unsupported; use 'http' or 'bolt'", $uri->scheme // "";
87             }
88            
89 98 100       1584 if (my $userinfo = $uri->userinfo(undef)) {
90 10         573 my @userinfo = $userinfo =~ m/^([^:]*):?(.*)/;
91 10         21 @userinfo = map { URI::Escape::uri_unescape $_ } @userinfo;
  20         147  
92 10         121 utf8::decode $_ for @userinfo;
93 10         21 $self->basic_auth(@userinfo);
94             }
95 98 100       5231 $uri->host('localhost') unless $uri->host;
96 98 100       6756 $uri->path('') if $uri->path_query eq '/';
97 98         1437 $uri->fragment(undef);
98             }
99             else {
100 77         343 $uri = URI->new("http://localhost");
101             }
102 175 100       21603 $uri->port( $NEO4J_DEFAULT_PORT{ $uri->scheme } ) if ! $uri->_port;
103            
104 175         17287 $self->{config}->{uri} = $uri;
105             }
106              
107              
108             sub basic_auth {
109 41     41 1 1652 my ($self, $username, $password) = @_;
110            
111 41 100       207 warnings::warnif deprecated => "Deprecated sequence: call basic_auth() before session()" if $self->{server_info};
112            
113             $self->{config}->{auth} = {
114 41         1511 scheme => 'basic',
115             principal => $username,
116             credentials => $password,
117             };
118            
119 41         101 return $self;
120             }
121              
122              
123             sub config {
124 1478     1478 1 53770 my ($self, @options) = @_;
125            
126 1478 100 100     5136 @options = %{$options[0]} if @options == 1 && ref $options[0] eq 'HASH';
  169         512  
127 1478 100       2684 croak "config() without options unsupported" unless @options;
128            
129 1476 100       2491 if (@options < 2) {
130             # get config option
131 1214         1432 my $key = $options[0];
132 1214 100       24465 croak "Unsupported config option: $key" unless grep m/^$key$/, keys %OPTIONS;
133 1213   100     10641 return $self->{$OPTIONS{$key}} // $self->{config}->{$OPTIONS{$key}};
134             }
135            
136 262 100       594 croak "Unsupported sequence: call config() before session()" if $self->{server_info};
137 261         1533 my %options = $self->_parse_options('config', [keys %OPTIONS], @options);
138            
139             # set config option
140 255         1109 my @keys = reverse sort keys %options; # auth should take precedence over uri
141 255         498 foreach my $key (@keys) {
142 278         744 $self->{config}->{$OPTIONS{$key}} = $options{$key};
143 278 100       809 $self->_check_uri if $OPTIONS{$key} eq 'uri';
144             }
145 244         1445 return $self;
146             }
147              
148              
149             sub session {
150 177     177 1 58072 my ($self, @options) = @_;
151            
152 177 100       517 if (! $self->{server_info}) {
153 89         883 warnings::warnif deprecated => sprintf "Internal API %s->{%s} may be unavailable in Neo4j::Driver 1.00", __PACKAGE__, $_ for grep { $self->{$_} } @OPTIONS{ sort keys %OPTIONS };
  1335         1809  
154             }
155            
156 177         463 $self->{plugins}->{die_on_error} = $self->{die_on_error};
157 177 100       466 warnings::warnif deprecated => __PACKAGE__ . "->{die_on_error} is deprecated" unless $self->{die_on_error};
158 177 100       3310 warnings::warnif deprecated => __PACKAGE__ . "->{http_timeout} is deprecated; use config()" if defined $self->{http_timeout};
159 177   100     1337 $self->{config}->{timeout} //= $self->{http_timeout};
160            
161 177 100 100     497 @options = %{$options[0]} if @options == 1 && ref $options[0] eq 'HASH';
  2         7  
162 177         624 my %options = $self->_parse_options('session', ['database'], @options);
163            
164 176         925 my $session = Neo4j::Driver::Session->new($self);
165 168         775 return $session->_connect($options{database});
166             }
167              
168              
169             sub _parse_options {
170 438     438   1026 my (undef, $context, $supported, @options) = @_;
171            
172 438 100       1005 croak "Odd number of elements in $context options hash" if @options & 1;
173 436         940 my %options = @options;
174            
175 436 100       931 warnings::warnif deprecated => "Config option ca_file is deprecated; use trust_ca" if $options{ca_file};
176 436 100       1613 warnings::warnif deprecated => "Config option cypher_types is deprecated" if $options{cypher_types};
177 436 100       1269 if ($options{cypher_params}) {
    100          
178 26 100       128 croak "Unimplemented cypher params filter '$options{cypher_params}'" if $options{cypher_params} ne v2;
179             }
180             elsif ($options{cypher_filter}) {
181 2         49 warnings::warnif deprecated => "Config option cypher_filter is deprecated; use cypher_params";
182 2 100       2133 croak "Unimplemented cypher filter '$options{cypher_filter}'" if $options{cypher_filter} ne 'params';
183 1         3 $options{cypher_params} = v2;
184             }
185 434 100       847 warnings::warnif deprecated => "Config option jolt is deprecated: Jolt is now enabled by default" if defined $options{jolt};
186 434 100       3205 warnings::warnif deprecated => "Config option net_module is deprecated; use plug-in interface" if defined $options{net_module};
187            
188 434         2286 my @unsupported = ();
189 434         953 foreach my $key (keys %options) {
190 373 100       7947 push @unsupported, $key unless grep m/^$key$/, @$supported;
191             }
192 434 100       1208 croak "Unsupported $context option: " . join ", ", sort @unsupported if @unsupported;
193            
194 431         2042 return %options;
195             }
196              
197              
198             sub plugin {
199             # uncoverable pod (experimental feature)
200 76     76 0 3384 my ($self, $package, @extra) = @_;
201            
202 76 100       222 croak "plugin() with more than one argument is unsupported" if @extra;
203 75         297 $self->{plugins}->_register_plugin($package);
204 75         254 return $self;
205             }
206              
207              
208             sub close {
209             # uncoverable pod (see Deprecations.pod)
210 1     1 0 2824 warnings::warnif deprecated => __PACKAGE__ . "->close() is deprecated";
211             }
212              
213              
214              
215              
216             package # private
217             URI::bolt;
218              
219 17     17   163 use parent 'URI::_server';
  17         48  
  17         120  
220              
221             # The server methods need to be available for bolt: URI instances
222             # even when the Neo4j-Bolt distribution is not installed.
223              
224            
225             1;
226              
227             __END__