File Coverage

blib/lib/Couchbase/Couch/Handle.pm
Criterion Covered Total %
statement 71 157 45.2
branch 0 22 0.0
condition n/a
subroutine 24 42 57.1
pod 1 3 33.3
total 96 224 42.8


line stmt bran cond sub pod time code
1             package Couchbase::Couch::Handle;
2             ##
3             # This is mainly an (abstract) base class for all handle objects.
4 4     4   20 use strict;
  4         6  
  4         133  
5 4     4   18 use warnings;
  4         10  
  4         96  
6 4     4   18 use Couchbase::Client::IDXConst;
  4         4  
  4         1144  
7 4     4   18 use Carp qw(cluck);
  4         10  
  4         172  
8 4     4   1340 use Data::Dumper;
  4         16459  
  4         274  
9              
10             BEGIN {
11 4     4   22 require XSLoader;
12 4         18503 XSLoader::load('Couchbase::Client', '2.0.0_1');
13             }
14              
15              
16             # This does some boilerplate initialization, ensuring that our private
17             # fields are initialized. Subclasses usually override this method and end up
18             # calling this via SUPER
19             sub _perl_initialize {
20 0     0     my $self = shift;
21 0           $self->info->_priv([]);
22              
23             # These two statements declare the callbacks.
24             # The CALLBACK_DATA and CALLBACK_COMPLETE correspond to the handlers which
25             # will be invoked by libcouchbase for the respective events.
26             # These callbacks should warn.
27              
28 0           $self->info->[COUCHIDX_CALLBACK_DATA] = \&default_data_callback;
29 0           $self->info->[COUCHIDX_CALLBACK_COMPLETE] = \&default_complete_callback;
30 0           return $self;
31             }
32              
33             # Convenience function
34 0     0 1   sub path { shift->info->path }
35             sub default_data_callback {
36 0     0 0   cluck "Got unhandled data callback";
37 0           print Dumper($_[1]);
38             }
39             sub default_complete_callback {
40 0     0 0   print Dumper($_[1]);
41 0           cluck "Got unhandled completion callback..";
42             }
43              
44             # This is the primary class for an iterator receiving a stream of bytes,
45             # and incrementally returning a JSON object (specifically, a view row) as its
46             # atomic unit.
47             package Couchbase::Couch::Handle::ViewIterator;
48 4     4   34 use strict;
  4         8  
  4         145  
49 4     4   20 use warnings;
  4         4  
  4         159  
50 4     4   1128 use Constant::Generate [qw(ITERBUF JSNDEC JSNROOT)], -prefix => 'FLD_';
  4         7489  
  4         40  
51 4     4   779 use Couchbase::Client::IDXConst;
  4         7  
  4         1072  
52 4     4   2451 use JSON::SL;
  4         3153  
  4         148  
53 4     4   27 use Couchbase::Couch::Handle;
  4         4  
  4         81  
54 4     4   1424 use Couchbase::Couch::ViewRow;
  4         8  
  4         225  
55 4     4   20 use Data::Dumper;
  4         5  
  4         176  
56              
57 4     4   17 use base qw(Couchbase::Couch::Handle);
  4         4  
  4         2085  
58              
59              
60             sub _perl_initialize {
61 0     0     my $self = shift;
62 0           my %options = @_;
63 0           $self->SUPER::_perl_initialize(%options);
64              
65 0           my $priv = $self->info->_priv;
66              
67             # Establish our JSON::SL object.
68 0           $priv->[FLD_JSNDEC] = JSON::SL->new();
69              
70             $priv->[FLD_JSNDEC]->root_callback(sub {
71 0 0   0     if ($_[0]) {
72 0           $priv->[FLD_JSNROOT] = $_[0]
73             }
74 0           });
75              
76             # Set the path for objects we wish to receive. Anything under "rows": [ ..]
77             # is a result for the user
78 0           $priv->[FLD_JSNDEC]->set_jsonpointer(["/rows/^"]);
79              
80             # This array reference will serve as a FIFO queue. A user will receive
81             # objects from the head, while JSON::SL will write parsed JSON objects
82             # to its tail.
83 0           $priv->[FLD_ITERBUF] = [];
84              
85             # Set up our callbacks..
86 0           $self->info->[COUCHIDX_CALLBACK_DATA] = \&_cb_data;
87 0           $self->info->[COUCHIDX_CALLBACK_COMPLETE] = \&_cb_complete;
88              
89 0           return $self;
90             }
91              
92              
93             # This is called when new data arrives,
94             # in C-speak, this is called from call_to_perl
95             sub _cb_data {
96             # the first argument is the handle, second is a special informational
97             # structure (which also contains our private data) and the third is
98             # a bunch of bytes
99 0     0     my ($self,$info,$bytes) = @_;
100 0 0         return unless defined $bytes;
101              
102 0           my $sl = $info->_priv->[FLD_JSNDEC];
103 0           my $buf = $info->_priv->[FLD_ITERBUF];
104              
105             # pass some more data into JSON::SL
106 0           my @results = $sl->feed($bytes);
107              
108             # check to see what our result count was for this stream of bytes. If we have
109             # received at least one extra object, then we can be assured the user has
110             # enough data, and therefore we can signal to the C code to stop the event
111             # loop (or decrement the wait count)
112 0           my $rescount = scalar @results;
113              
114             # This converts results (as raw JSON::SL results) into more sugary
115             # objects for Couch
116 0           foreach (@results) {
117 0           my $o = $_->{Value};
118 0           bless $o, "Couchbase::Couch::ViewRow";
119 0           $o->_cbo($self->info->[COUCHIDX_CBO]);
120 0           push @$buf, $o;
121             }
122              
123 0 0         if ($rescount) {
124             # if we have enough data, it is time to signal to the C code that
125             # the internal event loop should be unreferenced (i.e. we no longer
126             # need to wait for this operation to complete)
127 0           $self->_iter_pause;
128             }
129             }
130              
131 0     0     sub _cb_complete {
132             # hrrm.. not sure what to put here?
133             }
134              
135             # convenience method. Returns the 'total_rows' field.
136             sub count {
137 0     0     my $self = shift;
138 0           $self->info->_extract_item_count($self->info->_priv->[FLD_JSNROOT]);
139 0           return $self->info->count;
140             }
141              
142             # User level entry point to the iterator.
143             sub next {
144 0     0     my $self = shift;
145 0           my $rows = $self->info->_priv->[FLD_ITERBUF];
146 0           my $is_wantarray = wantarray();
147              
148             my $return_stuff = sub {
149 0 0   0     if ($is_wantarray) {
150 0           my @ret = @$rows;
151 0           @$rows = ();
152 0           return @ret;
153             }
154 0           return shift @$rows;
155 0           };
156              
157             # First we checked if there are remaining items in the row queue. If there are
158             # then we don't need to do any network I/O, but simply pop an item and
159             # return.
160 0 0         if (@$rows) {
161 0           return $return_stuff->();
162             }
163              
164             # so there's nothing in the queue. See if we can get something from the
165             # network.
166 0           my $rv = $self->_iter_step;
167              
168             # a true return value means we can wait for extra data
169 0 0         if ($rv) {
170 0 0         die "Iteration stopped but got nothing in buffer" unless @$rows;
171 0           return $return_stuff->();
172             }
173              
174             # if $rv is false, then we cannot wait for more data (either error, terminated)
175             # or some other condition. In this case we finalize the resultset metadata
176 0           $self->info->_extract_row_errors($self->info->_priv->[FLD_JSNROOT]);
177              
178             # TODO: does this line actually do anything?
179 0           return $return_stuff->();
180             }
181              
182             # convenience method to return any remaining JSON not parsed or extracted.
183             sub remaining_json {
184 0     0     my $self = shift;
185 0           return $self->info->_priv->[FLD_JSNROOT];
186             }
187              
188             # This handle simply 'slurps' data. It has three modes
189             # 1) Raw - Just slurp the stream of bytes and return it
190             # 2) JSONized - Slurp the stream and convert it into JSON, but don't do anything else
191             # 3) Resultset - Slurp the stream, and treat it as a resultset of JSON view rows
192             package Couchbase::Couch::Handle::Slurpee;
193 4     4   17 use strict;
  4         7  
  4         99  
194 4     4   18 use warnings;
  4         2  
  4         163  
195 4     4   2509 use JSON;
  4         33839  
  4         18  
196 4     4   574 use Couchbase::Client::IDXConst;
  4         5  
  4         1062  
197 4     4   20 use base qw(Couchbase::Couch::Handle);
  4         5  
  4         871  
198              
199             sub slurp_raw {
200 0     0     my ($self,@args) = @_;
201 0           $self->SUPER::slurp(@args);
202 0           $self->info;
203             }
204              
205             sub slurp_jsonized {
206 0     0     my ($self,@args) = @_;
207 0           $self->slurp_raw(@args);
208 0           my $info = $self->info;
209 0 0         if ($info->value) {
210 0           $info->[RETIDX_VALUE] = decode_json($info->[RETIDX_VALUE]);
211 0           $info->_extract_row_errors($info->value);
212             }
213 0           return $info;
214             }
215              
216             sub slurp {
217 0     0     my ($self,@args) = @_;
218 0           $self->slurp_raw(@args);
219 0           $self->info->_extract_view_results;
220 0           return $self->info;
221             }
222              
223             # This isn't used by anything (yet), but might be handy for attachments -
224             # iterates through the response, but does not parse it.
225             package Couchbase::Couch::Handle::RawIterator;
226 4     4   18 use strict;
  4         4  
  4         90  
227 4     4   15 use warnings;
  4         4  
  4         97  
228 4     4   38 use Couchbase::Client::IDXConst;
  4         6  
  4         899  
229 4     4   17 use base qw(Couchbase::Couch::Handle);
  4         5  
  4         731  
230              
231             sub _cb_data {
232 0     0     my ($self,$info,$bytes) = @_;
233 0 0         if ($bytes) {
234 0           $self->info->[RETIDX_VALUE] .= $bytes;
235 0           $self->_iter_pause();
236             }
237             }
238              
239             sub _perl_initialize {
240 0     0     my $self = shift;
241 0           $self->info->[COUCHIDX_CALLBACK_DATA] =\&cb_data;
242             }
243              
244             sub next {
245 0     0     my $self = shift;
246 0           my $ret = delete $self->info->[RETIDX_VALUE];
247 0 0         if ($ret) {
248 0           return $ret;
249             }
250 0 0         if ($self->_iter_step) {
251 0           return delete $self->info->[RETIDX_VALUE];
252             }
253 0           return;
254             }
255             1;
256              
257             __END__