File Coverage

blib/lib/SolarBeam/Response.pm
Criterion Covered Total %
statement 78 78 100.0
branch 19 24 79.1
condition 15 23 65.2
subroutine 9 9 100.0
pod 2 2 100.0
total 123 136 90.4


line stmt bran cond sub pod time code
1             package SolarBeam::Response;
2 4     4   13930 use Mojo::Base -base;
  4         6  
  4         29  
3              
4 4     4   2551 use Data::Page;
  4         21512  
  4         34  
5 4     4   718 use Mojo::JSON 'decode_json';
  4         76656  
  4         264  
6 4     4   2410 use Mojo::JSON::MaybeXS;
  4         27882  
  4         147  
7 4     4   25 use Mojo::Util 'decamelize';
  4         6  
  4         254  
8              
9 4   50 4   19 use constant DEBUG => $ENV{SOLARBEAM_DEBUG} || 0;
  4         5  
  4         4111  
10              
11             has docs => sub { +[] };
12             has error => undef;
13             has facet_dates => sub { +{} };
14             has facet_fields => sub { +{} };
15             has facet_queries => sub { +{} };
16             has facet_ranges => sub { +{} };
17             has num_found => 0;
18             has pager => sub { Data::Page->new };
19             has params => sub { +{} };
20             has query_time => 0;
21             has start => 0;
22             has terms => sub { +{} };
23              
24             sub facet_fields_as_hashes {
25 2     2 1 37 my $self = shift;
26              
27 2   33     11 return $self->{facet_fields_as_hashes} ||= do {
28 2         9 my $facet_fields = $self->facet_fields;
29 2         12 my %res;
30 2         7 for my $k (keys %$facet_fields) {
31 1 50       2 $res{$k} = {map { @$_{qw(value count)} } @{$facet_fields->{$k} || []}};
  2         8  
  1         6  
32             }
33 2         15 return \%res;
34             };
35             }
36              
37             sub parse {
38 15     15 1 19256 my ($self, $tx) = @_;
39 15         41 my $res = $tx->res;
40 15   100     116 my $data = $res->json || {};
41 15         1304 my $header = $data->{responseHeader};
42 15         23 my $response = $data->{response};
43 15         21 my $facets = $data->{facet_counts};
44 15         22 my $terms = $data->{terms};
45 15         15 my $field;
46              
47 15 100       38 if ($data->{error}) {
48 1   33     12 $self->error({code => $data->{error}{code} || $tx->res->code, message => $data->{error}{msg}});
49 1         7 return $self;
50             }
51              
52 14 100 100     46 if ($res->code and !$header) {
53 6         82 my $dom = $res->dom;
54              
55 6 100 66     38745 if ($dom and $dom->at('title')) {
56 2         571 $self->error({code => $res->code, message => $dom->at('title')->text});
57             }
58             else {
59 4   100     955 $self->error({code => $res->code, message => $res->body || 'Missing response headers.'});
60             }
61 6         563 return $self;
62             }
63              
64 8 100       75 if ($tx->error) {
65 3   100     45 $tx->error->{message} ||= 'Unknown error';
66 3         48 $self->error($tx->error);
67 3         58 return $self;
68             }
69              
70 5         150 for $field (keys %$header) {
71 14         69 my $method = decamelize ucfirst $field;
72 14 100       376 $self->$method($header->{$field}) if $self->can($method);
73             }
74              
75 5         29 for $field (keys %$response) {
76 13         71 my $method = decamelize ucfirst $field;
77 13 100       285 $self->$method($response->{$field}) if $self->can($method);
78             }
79              
80 5         36 for $field (keys %$facets) {
81 8 50       78 $self->$field($facets->{$field}) if $self->can($field);
82             }
83              
84 5         28 my $ff = $self->facet_fields;
85 5 50       24 if ($ff) {
86 5         12 for $field (keys %$ff) {
87 1         5 $ff->{$field} = $self->_build_count_list($ff->{$field});
88             }
89             }
90              
91 5 50       15 if ($self->facet_ranges) {
92 5         22 for $field (keys %{$self->facet_ranges}) {
  5         12  
93 1         8 my $range = $self->facet_ranges->{$field};
94 1         8 $range->{counts} = $self->_build_count_list($range->{counts});
95             }
96             }
97              
98 5 100       31 if ($terms) {
99 1         3 my $sane_terms = {};
100 1         5 for $field (keys %$terms) {
101 2         8 $sane_terms->{$field} = $self->_build_count_list($terms->{$field});
102             }
103 1         6 $self->terms($sane_terms);
104             }
105              
106 5 50 33     35 if (!$self->error && $response) {
107 5         67 $self->pager->total_entries($self->num_found);
108             }
109              
110 5         318 $self;
111             }
112              
113             sub _build_count_list {
114 4     4   9 my ($self, $list) = @_;
115 4         10 my @result = ();
116 4         16 for (my $i = 1; $i < @$list; $i += 2) {
117 130         575 push @result, {value => $list->[$i - 1], count => $list->[$i]};
118             }
119 4         31 return \@result;
120             }
121              
122             1;
123              
124             =encoding utf8
125              
126             =head1 NAME
127              
128             SolarBeam::Response - Represents a Solr search response
129              
130             =head1 SYNOPSIS
131              
132             use SolarBeam::Response;
133             my $tx = Mojo::UserAgent->new->post($solr_url, form => \%query);
134             my $res = SolarBeam::Response->new->parse($tx);
135              
136             if ($res->error) {
137             die sprintf "%s: %s", $res->error->{code} || 0, $res->error->{message};
138             }
139              
140             for my $doc (@{$res->docs}) {
141             say $doc->{surname};
142             }
143              
144             =head1 DESCRIPTION
145              
146             L holds the response from L or
147             L.
148              
149             =head1 ATTRIBUTES
150              
151             =head2 docs
152              
153             $array_ref = $self->docs;
154             $self = $self->docs([{}, ...]);
155              
156             Holds a list of the documents retrieved from Solr.
157              
158             =head2 error
159              
160             $hash_ref = $self->error;
161             $self = $self->error({message => "Error message", code => 500});
162              
163             Holds either a hash-ref with error details or C if no error is
164             detected. This attribute is modeled the same way as L,
165             but can also contain detailed error messages from the Solr server.
166              
167             =head2 facet_dates
168              
169             $hash_ref = $self->facet_dates;
170              
171             TODO.
172              
173             =head2 facet_fields
174              
175             $hash_ref = $self->facet_fields;
176              
177             TODO.
178              
179             =head2 facet_queries
180              
181             $hash_ref = $self->facet_queries;
182              
183             TODO.
184              
185             =head2 facet_ranges
186              
187             $hash_ref = $self->facet_ranges;
188              
189             TODO.
190              
191             =head2 num_found
192              
193             $int = $self->num_found;
194              
195             Holds the number of matching documents. This number can be higher than the
196             number of elements in L.
197              
198             =head2 pager
199              
200             $pager = $self->pager;
201             $self = $self->pager(Data::Page->new);
202              
203             Holds a L object.
204              
205             =head2 params
206              
207             $hash_ref = $self->params;
208              
209             Holds the search params sent to Solr.
210              
211             =head2 query_time
212              
213             $int = $self->query_time;
214              
215             The time the search took.
216              
217             =head2 start
218              
219             $int = $self->start;
220              
221             Offset of the search result.
222              
223             =head2 terms
224              
225             $hash_ref = $self->terms;
226              
227             TODO
228              
229             =head1 METHODS
230              
231             =head2 facet_fields_as_hashes
232              
233             $hash_ref = $self->facet_fields_as_hashes;
234              
235             Turns the arrays in L into hashes instead. Example:
236              
237             $self->facet_fields = {colors => [{value => "red", count => 42}]};
238             $self->facet_fields_as_hashes = {colors => {red => 42}}
239              
240             =head2 parse
241              
242             $self = $self->parse(Mojo::Transaction->new);
243              
244             Used to parse the result from a query. Will populate the different
245             L.
246              
247             =head1 SEE ALSO
248              
249             L.
250              
251             =cut