File Coverage

blib/lib/Mojo/CouchDB/DB.pm
Criterion Covered Total %
statement 111 148 75.0
branch 34 56 60.7
condition 6 14 42.8
subroutine 29 36 80.5
pod 14 14 100.0
total 194 268 72.3


line stmt bran cond sub pod time code
1             package Mojo::CouchDB::DB;
2              
3 2     2   17 use Mojo::Base -base;
  2         7  
  2         15  
4              
5 2     2   359 use Mojo::URL;
  2         7  
  2         12  
6 2     2   98 use Mojo::UserAgent;
  2         4  
  2         14  
7 2     2   135 use Mojo::IOLoop;
  2         5  
  2         13  
8 2     2   129 use Mojo::JSON qw(encode_json);
  2         5  
  2         123  
9              
10 2     2   13 use Carp qw(croak carp);
  2         5  
  2         89  
11 2     2   1329 use URI;
  2         11457  
  2         65  
12 2     2   15 use Scalar::Util qw(reftype);
  2         16  
  2         116  
13 2     2   12 use Storable qw(dclone);
  2         5  
  2         4861  
14              
15             has ua => sub { Mojo::UserAgent->new };
16             has 'url';
17             has 'auth';
18              
19             sub all_docs {
20 2     2 1 83 my $self = shift;
21 2         8 my $query = $self->_to_query(shift);
22 0         0 return $self->_call('_all_docs' . $query, 'get')->result->json;
23             }
24              
25             sub all_docs_p {
26 2     2 1 73 my $self = shift;
27 2         9 my $query = $self->_to_query(shift);
28              
29             return $self->_call_p('_all_docs' . $query, 'get_p')
30 0     0   0 ->then(sub { return shift->res->json });
  0         0  
31             }
32              
33             sub create_db {
34 2     2 1 40 return shift->_call('', 'put');
35             }
36              
37             sub find {
38 2     2 1 88 my $self = shift;
39 2         5 my $sc = shift;
40 2         7 return $self->_find($sc)->_call('_find', 'post', $sc);
41             }
42              
43             sub find_p {
44 2     2 1 79 my $self = shift;
45 2         6 my $sc = shift;
46             return $self->_find($sc)->_call_p('_find', 'post_p', $sc)
47 2     0   12 ->then(sub { return shift->res->json });
  0         0  
48             }
49              
50             sub get {
51 5     5 1 117 my $self = shift;
52 5         13 my $id = shift;
53              
54 5         37 $id = $$id while (reftype($id));
55 4         15 return $self->_get($id)->_call("/$id", 'get');
56             }
57              
58             sub get_p {
59 0     0 1 0 my $self = shift;
60 0         0 my $id = shift;
61              
62 0         0 $id = $$id while (reftype($id));
63 0         0 return $self->_get($id)->_call_p("/$id", 'get');
64             }
65              
66             sub index {
67 2     2 1 73 my $self = shift;
68 2         3 my $idx = shift;
69              
70 2         7 return $self->_index($idx)->_call('_index', 'post', $idx);
71             }
72              
73             sub index_p {
74 2     2 1 69 my $self = shift;
75 2         4 my $idx = shift;
76              
77 2         7 return $self->_index($idx)->_call_p('_index', 'post_p', $idx);
78             }
79              
80             sub new {
81 2     2 1 366 my $self = shift->SUPER::new;
82 2         15 my $url = shift;
83 2         4 my $auth = shift;
84              
85 2 50       9 carp qq{No auth provided for $url. This may have been a mistake.} unless $auth;
86 2 50       7 croak qq{No path part found for database.} unless exists $url->path->parts->[0];
87              
88 2         52 $self->{auth} = $auth;
89 2         5 $self->{url} = $url;
90              
91 2         7 return $self;
92             }
93              
94             sub save {
95 4     4 1 82 my $self = shift;
96 4         7 my $doc = shift;
97 4         14 my $res = $self->_save($doc)->_call('', 'post', $doc);
98              
99 2         154 my $dc = dclone $doc;
100 2         8 $dc->{_id} = $res->{_id};
101 2         7 $dc->{_rev} = $res->{_rev};
102              
103 2         13 return $dc;
104             }
105              
106             sub save_p {
107 2     2 1 68 my $self = shift;
108 2         4 my $doc = shift;
109             return $self->_save($doc)->_call_p('', 'post_p', $doc)->then(sub {
110 0     0   0 my $res = shift;
111              
112 0         0 my $dc = dclone $doc;
113 0         0 $dc->{_id} = $res->{_id};
114 0         0 $dc->{_rev} = $res->{_rev};
115              
116 0         0 return $doc;
117 2         6 });
118             }
119              
120             sub save_many {
121 2     2 1 85 my $self = shift;
122 2         4 my $docs = shift;
123 2         7 return $self->_save_many($docs)->_call('/bulk_docs', 'post', {docs => $docs});
124             }
125              
126             sub save_many_p {
127 2     2 1 74 my $self = shift;
128 2         6 my $docs = shift;
129              
130 2         7 return $self->_save_many($docs)->_call_p('/bulk_docs', 'post_p', {docs => $docs});
131             }
132              
133             sub _call {
134 7     7   13 my $self = shift;
135 7         14 my $loc = shift;
136 7         11 my $method = shift;
137 7         22 my $body = shift;
138              
139 7 100 66     52 my $url = $loc && $loc ne '' ? $self->url->to_string . "$loc" : $self->url->to_string;
140              
141 7         2787 my $headers = {Authorization => $self->auth};
142              
143 7 100       63 my $r
144             = ($body
145             ? $self->ua->$method($url, $headers, 'json', $body)
146             : $self->ua->$method($url, $headers))->result;
147              
148             croak 'CouchDB encountered an error: ' . $r->json->{error}
149 7 50 66     137467 if $r->json and exists($r->json->{error});
150 7 100       3019 croak 'CouchDB encountered an error: ' . $r->code . ' ' . encode_json($r->json)
151             unless $r->is_success;
152              
153 6   100     129 return $r->json || {};
154             }
155              
156             sub _call_p {
157 0     0   0 my $self = shift;
158 0         0 my $loc = shift;
159 0         0 my $method = shift;
160 0         0 my $body = shift;
161              
162 0 0 0     0 my $url = $loc && $loc ne '' ? $self->url->to_string . "$loc" : $self->url->to_string;
163              
164 0         0 my $headers = {Authorization => $self->auth};
165              
166 0 0       0 if ($body) {
167             return $self->ua->$method($url, $headers, 'json', $body)->then(sub {
168 0     0   0 my $r = shift;
169              
170             croak 'CouchDB encountered an error: ' . $r->res->json->{error}
171 0 0       0 if (exists $r->res->json->{error});
172              
173 0         0 return $r->res->json;
174 0         0 });
175             }
176              
177             return $self->ua->$method($url, $headers)->then(sub {
178 0     0   0 my $r = shift;
179              
180             croak 'CouchDB encountered an error: ' . $r->res->json->{error}
181 0 0       0 if (exists $r->res->json->{error});
182 0 0       0 croak 'CouchDB encountered an error: '
183             . $r->res->code . ' '
184             . encode_json($r->res->json)
185             if (!$r->is_success);
186              
187 0         0 return $r->res->json;
188 0         0 });
189             }
190              
191             sub _find {
192 4     4   9 my $self = shift;
193 4         5 my $sc = shift;
194              
195 4 100       30 croak qq{Invalid type supplied for search criteria, expected hashref got: undef }
196             unless $sc;
197 2 50       31 croak qq{Invalid type supplied for search criteria, expected hashref got: scalar }
198             unless reftype $sc;
199 0 0       0 croak qq{Invalid type supplied for search criteria, expected hashref got: }
200             . reftype $sc
201             unless reftype($sc) eq 'HASH';
202              
203 0         0 return $self;
204             }
205              
206             sub _get {
207 4     4   6 my $self = shift;
208 4         6 my $id = shift;
209              
210 4 100       17 croak qq{Invalid type supplied for id, expected scalar got: undef} unless $id;
211              
212 3         13 return $self;
213             }
214              
215             sub _index {
216 4     4   11 my $self = shift;
217 4         26 my $idx = shift;
218              
219 4 100       45 croak qq{Invalid type supplied for index, expected hashref got: undef } unless $idx;
220 2 100       22 croak qq{Invalid type supplied for index, expected hashref got: scalar }
221             unless reftype $idx;
222 1 50       27 croak qq{Invalid type supplied for index, expected hashref got: } . reftype $idx
223             unless reftype($idx) eq 'HASH';
224              
225 0         0 return $self;
226             }
227              
228             sub _save {
229 6     6   12 my $self = shift;
230 6         10 my $doc = shift;
231              
232 6 100       71 croak qq{No save argument specified, expected hashref got: undef } unless $doc;
233 4 100       41 croak qq{Invalid type supplied for document, expected hashref got: scalar }
234             unless reftype $doc;
235 3 100       24 croak qq{Invalid type supplied for document, expected hashref got: } . (reftype $doc)
236             unless reftype($doc) eq 'HASH';
237 2 50       5 croak qq{Cannot call save without a document} unless (defined $doc);
238              
239 2         7 return $self;
240             }
241              
242             sub _save_many {
243 4     4   9 my $self = shift;
244 4         6 my $docs = shift;
245              
246 4 100       30 croak qq{Cannot save many without a documents} unless defined $docs;
247 2 100       19 croak
248             qq{Invalid type supplied for documents, expected arrayref of hashref's got: scalar }
249             unless reftype $docs;
250 1 50       18 croak qq{Invalid type supplied for documents, expected arrayref of hashref's got: }
251             . (reftype $docs)
252             unless (reftype($docs) eq 'ARRAY');
253              
254 0         0 return $self;
255             }
256              
257             sub _to_query {
258 4     4   8 my $self = shift;
259 4         7 my $query = shift;
260              
261 4 100       27 croak qq{Invalid type supplied for query, expected hashref got undef} unless $query;
262 2 50       27 croak qq{Invalid type supplied for query, expected hashref got scalar}
263             unless reftype $query;
264 0 0 0       croak qq{Invalid type supplied for query, expected hashref got: } . reftype($query)
265             unless $query && reftype($query) eq 'HASH';
266              
267 0           my $t_uri = URI->new('', 'http');
268 0           $t_uri->query_form(%$query);
269              
270 0           return $t_uri->query;
271             }
272              
273             1;
274              
275              
276             =encoding utf8
277              
278             =head1 NAME
279              
280             Mojo::CouchDB::DB
281              
282             =head1 SYNOPSIS
283              
284             # Create a Mojo::CouchDB::DB instance via Mojo::CouchDB
285             my $couch = Mojo::CouchDB->new('http://localhost:5984', 'username', 'password');
286              
287             my $books_db = $couch->db('books'); # Mojo::CouchDB::DB;
288              
289             # Do database stuff
290             my $dune_books = $books_db->find({ selector => { name => "Dune" } })->{docs};
291             # ...
292              
293             =head2 all_docs
294              
295             $db->all_docs({ limit => 10, skip => 5});
296              
297             Retrieves a list of all of the documents in the database. This is packaged as a hashref with
298             C: the offset of the query, C: the documents in the page, and C: the number of rows returned in the dataset.
299              
300             Optionally, can take a hashref of query parameters that correspond with the CouchDB L.
301              
302             =head2 all_docs_p
303              
304             $db->all_docs_p({ limit => 10, skip => 5 });
305              
306             See L<"all_docs">, except returns the result in a L.
307            
308             =head2 create_db
309              
310             $db->create_db
311              
312             Create the database, returns C<1> if succeeds or if it already exsits, else returns C.
313              
314             =head2 find
315              
316             $db->find($search_criteria);
317              
318             Searches for documents based on the search criteria specified. The search criteria hashref provided for searching must follow the CouchDB L<_find specification|https://docs.couchdb.org/en/stable/api/database/find.html#selector-syntax>.
319              
320             Returns a hashref with two fields: C and C. C contains an arrayref of found documents, while
321             C contains a hashref of various statistics about the query you ran to find the documents.
322              
323             =head2 find_p
324              
325             $db->find_p($search_criteria);
326              
327             See L<"find">, except returns the result asynchronously in a L.
328              
329             =head2 get
330              
331             $db->get($id);
332              
333             Finds a document by a given id. Dies if it can't find the document. Returns the document in hashref form.
334              
335             =head2 get_p
336              
337             $db->get_p($id);
338              
339             See L<"get">, except returns the result asynchronously in a L.
340              
341             =head2 index
342              
343             $db->index($idx);
344              
345             Creates an index, where C<$idx> is a hashref following the CouchDB L. Returns the result of the index creation.
346              
347             =head2 index_p
348              
349             $db->index_p($idx);
350              
351             See L<"index">, except returns the result asynchronously in a L.
352              
353             =head2 save
354              
355             $db->save($document);
356              
357             Saves a document (hashref) to the database. If the C<_id> field is provided, it will update if it already exists. If you provide both the C<_id> and C<_rev> field, that specific revision will be updated. Returns a hashref that corresponds to the CouchDB C specification.
358              
359             =head2 save_p
360              
361             $couch->save_p($document);
362              
363             Does the same as L<"save"> but instead returns the result asynchronously in a L.
364              
365             =head2 save_many
366              
367             $couch->save_many($documents);
368              
369             Saves an arrayref of documents (hashrefs) to the database. Each document follows the same rules as L<\"save">. Returns an arrayref of the documents you saved with the C<_id> and C<_rev> fields filled.
370              
371             =head2 save_many_p
372              
373             $couch->save_many_p($documents);
374              
375             See L<"save_many">, except returns the result asynchronously in a L.
376              
377             =head1 API
378              
379             =over 2
380              
381             =item * L
382              
383             =back
384              
385             =head1 AUTHOR
386              
387             Rawley Fowler, C.
388              
389             =head1 CREDITS
390              
391             =over 2
392              
393             =back
394              
395             =head1 LICENSE
396              
397             Copyright (C) 2023, Rawley Fowler and contributors.
398              
399             This program is free software, you can redistribute it and/or modify it under the terms of the Artistic License version 2.0.
400              
401             =head1 SEE ALSO
402              
403             L.
404              
405             =cut
406