File Coverage

lib/Neo4j/Driver.pm
Criterion Covered Total %
statement 101 101 100.0
branch 66 66 100.0
condition 11 11 100.0
subroutine 18 18 100.0
pod 5 5 100.0
total 201 201 100.0


line stmt bran cond sub pod time code
1 20     20   1238590 use v5.12;
  20         93  
2 20     20   108 use warnings;
  20         31  
  20         1759  
3              
4             package Neo4j::Driver 1.02;
5             # ABSTRACT: Neo4j community graph database driver for Bolt and HTTP
6              
7              
8 20     20   146 use Carp qw(croak);
  20         37  
  20         1780  
9 20     20   152 use List::Util 1.33 qw(none);
  20         503  
  20         2169  
10              
11 20     20   2161 use URI 1.25;
  20         29906  
  20         758  
12 20     20   8256 use Neo4j::Driver::Events;
  20         79  
  20         692  
13 20     20   8229 use Neo4j::Driver::Session;
  20         75  
  20         37003  
14              
15              
16             my %NEO4J_DEFAULT_PORT = (
17             bolt => 7687,
18             http => 7474,
19             https => 7473,
20             );
21              
22             my %OPTIONS = (
23             auth => 'auth',
24             cypher_params => 'cypher_params_v2',
25             concurrent_tx => 'concurrent_tx',
26             encrypted => 'encrypted',
27             max_transaction_retry_time => 'max_transaction_retry_time',
28             timeout => 'timeout',
29             tls => 'encrypted',
30             tls_ca => 'trust_ca',
31             trust_ca => 'trust_ca',
32             uri => 'uri',
33             );
34              
35              
36             sub new {
37 184     184 1 3769002 my ($class, $config, @extra) = @_;
38            
39 184         614 my $self = bless {}, $class;
40 184         1085 $self->{events} = Neo4j::Driver::Events->new;
41            
42 184 100       688 croak __PACKAGE__ . "->new() with multiple arguments unsupported" if @extra;
43 183 100       911 $config = { uri => $config } if ref $config ne 'HASH';
44 183   100     813 $config->{uri} //= ''; # force config() to call _check_uri()
45 183         794 return $self->config($config);
46             }
47              
48              
49             sub _check_uri {
50 200     200   415 my ($self) = @_;
51            
52 200         504 my $uri = $self->{config}->{uri};
53            
54 200 100       499 if ($uri) {
55 119 100       1145 $uri = "[$uri]" if $uri =~ m{^[0-9a-f:]*::|^(?:[0-9a-f]+:){6}}i;
56 119 100 100     1309 $uri =~ s|^|neo4j://| if $uri !~ m{:|/} || $uri =~ m{^\[.+\]$};
57 119 100       398 $uri =~ s|^|neo4j:| if $uri =~ m{^//};
58 119         729 $uri = URI->new($uri);
59            
60 119 100       26294 $uri->scheme or croak
61             sprintf "Failed to parse URI '%s'", $uri;
62 114 100       3625 $uri->scheme =~ m/^(?:https?|bolt|neo4j)$/i or croak
63             sprintf "URI scheme '%s' unsupported; use 'bolt', 'http', or 'neo4j'", $uri->scheme;
64            
65 110 100       2426 if (my $userinfo = $uri->userinfo(undef)) {
66 10         1079 my @userinfo = $userinfo =~ m/^([^:]*):?(.*)/;
67 10         28 @userinfo = map { URI::Escape::uri_unescape $_ } @userinfo;
  20         278  
68 10         153 utf8::decode $_ for @userinfo;
69 10         46 $self->basic_auth(@userinfo);
70             }
71 110 100       9190 $uri->host('127.0.0.1') unless $uri->host;
72 110 100       14805 $uri->path('') if $uri->path_query eq '/';
73 110         14403 $uri->fragment(undef);
74             }
75             else {
76 81         536 $uri = URI->new("neo4j://127.0.0.1");
77             }
78 191 100       33913 $uri->port( $NEO4J_DEFAULT_PORT{ $uri->scheme } ) if ! $uri->_port;
79            
80 191         10738 $self->{config}->{uri} = $uri;
81             }
82              
83              
84             sub _fix_neo4j_uri {
85 40     40   911 my ($self) = @_;
86            
87 40 100       177 croak "The concurrent_tx config option may only be used with http:/https: URIs" if $self->{config}->{concurrent_tx};
88            
89 39         113 my $uri = $self->{config}->{uri};
90 39 100       358 $uri->scheme( exists $INC{'Neo4j/Bolt.pm'} ? 'bolt' : $self->{config}->{encrypted} ? 'https' : 'http' );
    100          
91 39 100       16414 $uri->port( $NEO4J_DEFAULT_PORT{ $uri->scheme } ) if ! $uri->_port;
92             }
93              
94              
95             sub basic_auth {
96 36     36 1 1825 my ($self, $username, $password) = @_;
97            
98 36 100       212 croak "Unsupported sequence: call basic_auth() before session()" if $self->{server_info};
99            
100             $self->{config}->{auth} = {
101 34         279 scheme => 'basic',
102             principal => $username,
103             credentials => $password,
104             };
105            
106 34         123 return $self;
107             }
108              
109              
110             sub config {
111 1185     1185 1 186197 my ($self, @options) = @_;
112            
113 1185 100 100     5059 @options = %{$options[0]} if @options == 1 && ref $options[0] eq 'HASH';
  186         665  
114 1185 100       2550 croak "config() without options unsupported" unless @options;
115            
116 1183 100       2511 if (@options < 2) {
117             # get config option
118 909         1340 my $key = $options[0];
119 909 100   4551   5587 croak sprintf "Unsupported config option: %s", $key if none {$_ eq $key} keys %OPTIONS;
  4551         6638  
120 905         10143 return $self->{config}->{$OPTIONS{$key}};
121             }
122            
123 274 100       836 croak "Unsupported sequence: call config() before session()" if $self->{server_info};
124 273         2286 my %options = $self->_parse_options('config', [keys %OPTIONS], @options);
125            
126             # set config option
127 262         1247 my @keys = reverse sort keys %options; # auth should take precedence over uri
128 262         633 foreach my $key (@keys) {
129 288         1093 $self->{config}->{$OPTIONS{$key}} = $options{$key};
130 288 100       3279 $self->_check_uri if $OPTIONS{$key} eq 'uri';
131             }
132 253         1871 return $self;
133             }
134              
135              
136             sub session {
137 187     187 1 3175709 my ($self, @options) = @_;
138            
139 187 100 100     762 @options = %{$options[0]} if @options == 1 && ref $options[0] eq 'HASH';
  2         9  
140 187         798 my %options = $self->_parse_options('session', ['database'], @options);
141            
142 186 100       1099 $self->_fix_neo4j_uri if $self->{config}->{uri}->scheme eq 'neo4j';
143            
144 185         10707 my $session = Neo4j::Driver::Session->new($self);
145 176         1244 return $session->_connect($options{database});
146             }
147              
148              
149             sub _parse_options {
150 460     460   1473 my (undef, $context, $supported, @options) = @_;
151            
152 460 100       1386 croak sprintf "Odd number of elements in %s options hash", $context if @options & 1;
153 458         1280 my %options = @options;
154            
155 458 100       1187 warnings::warnif deprecated => "Config option tls is deprecated; use encrypted" if $options{tls};
156 458 100       2227 warnings::warnif deprecated => "Config option tls_ca is deprecated; use trust_ca" if $options{tls_ca};
157            
158 458 100       8696 if ($options{cypher_params}) {
159             $options{cypher_params} =~ m<^(?:\x02|v2)$> or croak
160 20 100       214 sprintf "Unimplemented cypher params filter '%s'", $options{cypher_params};
161             }
162            
163 457     1583   1132 my @unsupported = grep { my $key = $_; none {$_ eq $key} @$supported } keys %options;
  404         646  
  404         2383  
  1583         3568  
164 457 100       1299 @unsupported and croak
165             sprintf "Unsupported %s option: %s", $context, join ", ", sort @unsupported;
166            
167 448         1749 return %options;
168             }
169              
170              
171             sub plugin {
172 85     85 1 8443 my ($self, $plugin, @extra) = @_;
173            
174 85 100       254 croak "plugin() with more than one argument is unsupported" if @extra;
175 84 100       287 croak "Unsupported sequence: call plugin() before session()" if $self->{server_info};
176 83         527 $self->{events}->_register_plugin($plugin);
177 83         366 return $self;
178             }
179              
180              
181              
182              
183             package # private
184             URI::bolt;
185              
186 20     20   224 use parent 'URI::_server';
  20         40  
  20         112  
187              
188             # The server methods need to be available for bolt: URI instances
189             # even when the Neo4j-Bolt distribution is not installed.
190              
191              
192             1;
193              
194             __END__