File Coverage

blib/lib/SolarBeam/Response.pm
Criterion Covered Total %
statement 79 79 100.0
branch 19 24 79.1
condition 15 23 65.2
subroutine 9 9 100.0
pod 2 2 100.0
total 124 137 90.5


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