File Coverage

blib/lib/DR/Tarantool/Tuple.pm
Criterion Covered Total %
statement 66 71 92.9
branch 26 40 65.0
condition 6 18 33.3
subroutine 14 15 93.3
pod 6 6 100.0
total 118 150 78.6


line stmt bran cond sub pod time code
1 10     10   1596 use utf8;
  10         25  
  10         81  
2 10     10   299 use strict;
  10         23  
  10         329  
3 10     10   60 use warnings;
  10         20  
  10         503  
4              
5             =head1 NAME
6              
7             DR::Tarantool::Tuple - a tuple container for L<DR::Tarantool>
8              
9             =head1 SYNOPSIS
10              
11             my $tuple = new DR::Tarantool::Tuple([ 1, 2, 3]);
12             my $tuple = new DR::Tarantool::Tuple([ 1, 2, 3], $space);
13             my $tuple = unpack DR::Tarantool::Tuple([ 1, 2, 3], $space);
14              
15              
16             $tuple->next( $other_tuple );
17              
18             $f = $tuple->raw(0);
19              
20             $f = $tuple->name_field;
21              
22              
23             =head1 DESCRIPTION
24              
25             A tuple contains normalized (unpacked) fields. You can access the fields
26             by their indexes (see L<raw> function) or by their names (if they are
27             described in the space).
28              
29             Each tuple can contain references to L<next> tuple and L<iter>ator,
30             so that if the server returns more than one tuple, all of them
31             can be accessed.
32              
33             =head1 METHODS
34              
35             =cut
36              
37             package DR::Tarantool::Tuple;
38 10     10   5098 use DR::Tarantool::Iterator;
  10         31  
  10         390  
39 10     10   90 use Scalar::Util 'weaken', 'blessed';
  10         25  
  10         744  
40 10     10   56 use Carp;
  10         21  
  10         10748  
41             $Carp::Internal{ (__PACKAGE__) }++;
42              
43              
44             =head2 new
45              
46             A constructor.
47              
48             my $t = DR::Tarantool::Tuple->new([1, 2, 3]);
49             my $t = DR::Tarantool::Tuple->new([1, 2, 3], $space);
50              
51             =cut
52              
53             sub new :method {
54 7     7 1 18 my ($class, $tuple, $space) = @_;
55              
56 7 50       16 $class = ref $class if ref $class;
57              
58             # hack to replace default autoload
59 7 50 33     60 $class = $space->tuple_class if $space and $class eq __PACKAGE__;
60              
61 7 50 33     62 croak 'wrong space' if defined $space and !blessed $space;
62              
63 7 50       21 croak 'tuple must be ARRAYREF [of ARRAYREF]' unless 'ARRAY' eq ref $tuple;
64 7 50       19 croak "tuple can't be empty" unless @$tuple;
65              
66 7 100       24 $tuple = [ $tuple ] unless 'ARRAY' eq ref $tuple->[0];
67              
68 7   33     58 my $iterator = DR::Tarantool::Iterator->new(
69             $tuple,
70             data => $space,
71             item_class => ref($class) || $class,
72             item_constructor => '_new'
73             );
74              
75 7   33     60 return bless {
76             idx => 0,
77             iterator => $iterator,
78             } => ref($class) || $class;
79             }
80              
81              
82             sub _new {
83 16     16   26 my ($class, $item, $idx, $iterator) = @_;
84 16   33     161 return bless {
85             idx => $idx,
86             iterator => $iterator,
87             } => ref($class) || $class;
88             }
89              
90              
91             =head2 unpack
92              
93             Another way to construct a tuple.
94              
95             my $t = DR::Tarantool::Tuple->unpack([1, 2, 3], $space);
96              
97             =cut
98              
99             sub unpack :method {
100 1     1 1 3 my ($class, $tuple, $space) = @_;
101 1 50       7 croak 'wrong space' unless blessed $space;
102 1 50       4 return undef unless defined $tuple;
103 1 50       5 croak 'tuple must be ARRAYREF [of ARRAYREF]' unless 'ARRAY' eq ref $tuple;
104 1 50       10 return undef unless @$tuple;
105              
106 1 50       5 if ('ARRAY' eq ref $tuple->[0]) {
107 0         0 my @tu;
108              
109 0         0 push @tu => $space->unpack_tuple($_) for @$tuple;
110 0         0 return $class->new(\@tu, $space);
111             }
112              
113 1         6 return $class->new($space->unpack_tuple($tuple), $space);
114             }
115              
116              
117             =head2 raw
118              
119             Return raw data from the tuple.
120              
121             my $array = $tuple->raw;
122              
123             my $field = $tuple->raw(0);
124              
125             =cut
126              
127             sub raw :method {
128 37     37 1 3337 my ($self, $fno) = @_;
129              
130 37         142 my $item = $self->{iterator}->raw_item( $self->{idx} );
131              
132 37 100       89 return $item unless defined $fno;
133              
134 34 50       121 croak 'wrong field number' unless $fno =~ /^-?\d+$/;
135              
136 34 50       74 return undef if $fno < -@$item;
137 34 100       75 return undef if $fno >= @$item;
138 32         191 return $item->[ $fno ];
139             }
140              
141              
142             =head2 next
143              
144             Append or return the next tuple, provided there is more than one
145             tuple in the result set.
146              
147             my $next_tuple = $tuple->next;
148              
149             =cut
150              
151             sub next :method {
152              
153 5     5 1 15 my ($self, $tuple) = @_;
154              
155 5         10 my $iterator = $self->{iterator};
156 5         7 my $idx = $self->{idx} + 1;
157              
158             # if tuple is exists next works like 'iterator->push'
159 5 100       18 if ('ARRAY' eq ref $tuple) {
160 2         8 $iterator->push( $tuple );
161 2         5 $idx = $iterator->count - 1;
162             }
163              
164 5 50       13 return undef unless $idx < $iterator->count;
165              
166 5         26 my $next = bless {
167             idx => $idx,
168             iterator => $iterator,
169             } => ref($self);
170              
171 5         17 return $next;
172             }
173              
174              
175             =head2 iter
176              
177             Return an iterator object associated with the tuple.
178              
179              
180             my $iterator = $tuple->iter;
181              
182             my $iterator = $tuple->iter('MyTupleClass', 'new');
183              
184             while(my $t = $iterator->next) {
185             # the first value of $t and $tuple are the same
186             ...
187             }
188              
189             =head3 Arguments
190              
191             =over
192              
193             =item package (optional)
194              
195             =item method (optional)
196              
197             If 'package' and 'method' are present, $iterator->L<next> method
198             constructs objects using C<< $package->$method( $next_tuple ) >>
199              
200             If 'method' is not present and 'package' is present, the iterator
201             blesses the raw array with 'package'.
202              
203             =back
204              
205             =cut
206              
207             sub iter :method {
208 6     6 1 591 my ($self, $class, $method) = @_;
209              
210 6         11 my $iterator = $self->{iterator};
211              
212 6 100       14 if ($class) {
213             return $self->{iterator}->clone(
214             item_class => $class,
215             item_constructor => sub {
216 6     6   9 my ($c, $item, $idx) = @_;
217              
218 6 100       12 if ($method) {
219 2         9 my $bitem = bless {
220             idx => $idx,
221             iterator => $iterator,
222             } => ref($self);
223              
224              
225 2         12 return $c->$method( $bitem );
226             }
227 4   33     44 return bless [ @$item ] => ref($c) || $c;
228             }
229 2         17 );
230             }
231              
232 4         16 return $self->{iterator};
233             }
234              
235              
236             =head2 tail
237              
238             Return the tail of the tuple (array of unnamed fields). The function always
239             returns B<ARRAYREF> (as L<raw>).
240              
241             =cut
242              
243             sub tail {
244 1     1 1 3 my ($self) = @_;
245 1         4 my $space = $self->{iterator}->data;
246 1         5 my $raw = $self->raw;
247              
248 1 50       9 return [ @$raw[ $space->tail_index .. $#$raw ] ] if $space;
249 0           return $raw;
250             }
251              
252              
253              
254 0     0     sub DESTROY { }
255              
256              
257             =head1 COPYRIGHT AND LICENSE
258              
259             Copyright (C) 2011 Dmitry E. Oboukhov <unera@debian.org>
260             Copyright (C) 2011 Roman V. Nikolaev <rshadow@rambler.ru>
261              
262             This program is free software, you can redistribute it and/or
263             modify it under the terms of the Artistic License.
264              
265             =head1 VCS
266              
267             The project is placed git repo on github:
268             L<https://github.com/dr-co/dr-tarantool/>.
269              
270             =cut
271              
272             1;