File Coverage

lib/Neo4j/Driver/Record.pm
Criterion Covered Total %
statement 59 59 100.0
branch 20 20 100.0
condition 9 9 100.0
subroutine 13 13 100.0
pod 2 3 100.0
total 103 104 100.0


line stmt bran cond sub pod time code
1 20     20   225 use v5.12;
  20         64  
2 20     20   122 use warnings;
  20         64  
  20         1534  
3              
4             package Neo4j::Driver::Record 1.02;
5             # ABSTRACT: Container for Cypher result values
6              
7              
8 20     20   105 use Carp qw(croak);
  20         27  
  20         1226  
9 20     20   130 use List::Util qw(first);
  20         30  
  20         1199  
10              
11 20     20   8992 use Neo4j::Driver::ResultSummary;
  20         48  
  20         884  
12              
13              
14             # Check if the given value was created as a number. Older Perls lack stable
15             # tracking of numbers vs. strings, but a quirk of bitwise string operators
16             # can be used to determine whether the scalar contains a number (see perlop).
17             # That isn't quite the same, but it should be good enough for us.
18             # (original idea from https://github.com/makamaka/JSON-PP/commit/87bd6a4)
19             sub _SvNIOKp {
20 20     20   133 no warnings 'numeric';
  20         45  
  20         3973  
21 7     7   2959 return length( (my $string = '') & shift );
22             }
23             *created_as_number = $^V ge v5.36 ? \&builtin::created_as_number : \&_SvNIOKp;
24              
25              
26             sub get {
27 262     262 1 86698 my ($self, $field) = @_;
28            
29 262 100       773 if ( ! defined $field ) {
30             warnings::warnif ambiguous =>
31             sprintf "Ambiguous get() on %s with multiple fields", __PACKAGE__
32 73 100       107 if @{$self->{row}} > 1;
  73         317  
33 73         1898 return $self->{row}->[0];
34             }
35            
36 189         473 my $index = $self->{field_names_cache}->{$field};
37 189 100 100     3131 return $self->{row}->[$index] if defined $index && length $field;
38            
39             # At this point, it looks like the given $field is both a valid name and
40             # a valid index, which should be pretty rare.
41             # Callers usually specify the field as a literal in the method call, so we
42             # can DWIM and disambiguate by using Perl's created_as_number() built-in.
43            
44 20     20   127 no if $^V ge v5.36, 'warnings', 'experimental::builtin';
  20         29  
  20         13098  
45 47 100       168 if ( created_as_number($field) ) {
46             croak sprintf "Field %s not present in query result", $field
47 35 100 100     225 unless $field == int $field && $field >= 0 && $field < @{$self->{row}};
  33   100     124  
48 32         267 return $self->{row}->[$field];
49             }
50            
51 12         28 my $field_names = $self->{field_names_cache}->{''};
52 12     21   107 $index = first { $field eq $field_names->[$_] } 0 .. $#$field_names;
  21         44  
53 12 100       183 croak sprintf "Field '%s' not present in query result", $field
54             unless defined $index;
55 7         29 return $self->{row}->[$index];
56             }
57              
58              
59             sub data {
60 5     5 1 837 my ($self) = @_;
61            
62 5 100       33 return $self->{hash} if exists $self->{hash};
63            
64 4         8 my $field_names = $self->{field_names_cache}->{''};
65 4         7 my %data;
66 4         30 $data{ $field_names->[$_] } = $self->{row}->[$_] for 0 .. $#$field_names;
67 4         31 return $self->{hash} = \%data;
68             }
69              
70              
71             # Parse the field names (result column keys) provided by the server and
72             # return them as a hash ref for fast index lookups
73             sub _field_names_cache {
74 232     232   514 my ($result) = @_;
75            
76 232         454 my $field_names = $result->{columns};
77 232         644 my $cache = { '' => $field_names };
78 232         912 for my $index (0 .. $#$field_names) {
79 495         880 my $name = $field_names->[$index];
80            
81             # Create lookup cache for both index and field name to the index.
82             # Skip ambiguous index/name pairs.
83            
84 495 100       967 if ( exists $cache->{$name} ) {
85 7         14 delete $cache->{$name};
86             }
87             else {
88 488         1341 $cache->{$name} = $index;
89             }
90            
91 495 100       2486 if ( exists $cache->{$index} ) {
92 113         296 delete $cache->{$index};
93             }
94             else {
95 382         1041 $cache->{$index} = $index;
96             }
97             }
98            
99 232         831 return $cache;
100             }
101              
102             # The field names (column keys / ex ResultColumns) are stored in a hash ref.
103             # For each field, there are entries with keys for the name and the column index
104             # in the result record array. The value is always the column index.
105             # For example, for `RETURN 1 AS foo`, it would look like this:
106             # $cache = { 'foo' => 0, '0' => 0 };
107              
108             # Exceptionally, index/name collisions can occur (see record-ambiguous.t).
109             # The field names lookup cache is limited to cases where no ambiguity exists.
110             # A reference to the original list of field names is kept in
111             # the entry '' (empty string). Neo4j doesn't allow zero-length
112             # field names, so '' itself is never ambiguous.
113              
114              
115             sub summary {
116             # uncoverable pod (see consume)
117 2     2 0 814 my ($self) = @_;
118 2         84 warnings::warnif deprecated => "summary() in Neo4j::Driver::Record is deprecated; use consume() in Neo4j::Driver::Result instead";
119            
120 2 100       1212 croak 'Summary unavailable for Record retrieved with fetch() or list(); use consume() in Neo4j::Driver::Result' unless $self->{_summary};
121 1         7 return $self->{_summary};
122             }
123              
124              
125             1;
126              
127             __END__