File Coverage

blib/lib/Catmandu/Store/Solr/Bag.pm
Criterion Covered Total %
statement 27 72 37.5
branch 0 20 0.0
condition 0 14 0.0
subroutine 9 18 50.0
pod 0 6 0.0
total 36 130 27.6


line stmt bran cond sub pod time code
1             package Catmandu::Store::Solr::Bag;
2              
3 3     3   19 use Catmandu::Sane;
  3         6  
  3         26  
4 3     3   656 use Catmandu::Util qw(:is);
  3         5  
  3         758  
5 3     3   21 use Carp qw(confess);
  3         5  
  3         151  
6 3     3   795 use Catmandu::Hits;
  3         45946  
  3         92  
7 3     3   1353 use Catmandu::Store::Solr::Searcher;
  3         7  
  3         94  
8 3     3   1443 use Catmandu::Store::Solr::CQL;
  3         8  
  3         91  
9 3     3   19 use Catmandu::Error;
  3         7  
  3         84  
10 3     3   15 use Moo;
  3         5  
  3         20  
11 3     3   1174 use MooX::Aliases;
  3         6  
  3         25  
12              
13             our $VERSION = "0.0304";
14              
15             with 'Catmandu::Bag';
16             with 'Catmandu::CQLSearchable';
17             with 'Catmandu::Buffer';
18              
19             has cql_mapping => (is => 'ro');
20              
21             has bag_key => (is => 'lazy', alias => 'bag_field');
22              
23             sub _build_bag_key {
24 0     0     $_[0]->store->bag_key;
25             }
26              
27             sub generator {
28 0     0 0   my ($self) = @_;
29 0           my $store = $self->store;
30 0           my $name = $self->name;
31 0           my $limit = $self->buffer_size;
32 0           my $bag_field = $self->bag_field;
33 0           my $query = qq/$bag_field:"$name"/;
34             sub {
35 0     0     state $start = 0;
36 0           state $hits;
37 0 0 0       unless ($hits && @$hits) {
38             $hits = $store->solr->search(
39             $query,
40             {
41             start => $start,
42             rows => $limit,
43             defType => "lucene",
44             facet => "false",
45             spellcheck => "false"
46             }
47 0           )->content->{response}{docs};
48 0           $start += $limit;
49             }
50 0   0       my $hit = shift(@$hits) || return;
51 0           $self->map_fields($hit);
52 0           $hit;
53 0           };
54             }
55              
56             sub count {
57 0     0 0   my ($self) = @_;
58 0           my $name = $self->name;
59 0           my $bag_field = $self->bag_field;
60 0           my $res = $self->store->solr->search(
61             qq/$bag_field:"$name"/,
62             {
63             rows => 0,
64             facet => "false",
65             spellcheck => "false",
66             defType => "lucene",
67             }
68             );
69 0           $res->content->{response}{numFound};
70             }
71              
72             sub get {
73             my ($self, $id) = @_;
74             my $name = $self->name;
75             my $id_field = $self->id_field;
76             my $bag_field = $self->bag_field;
77             my $res = $self->store->solr->search(
78             qq/$bag_field:"$name" AND $id_field:"$id"/,
79             {
80             rows => 1,
81             facet => "false",
82             spellcheck => "false",
83             defType => "lucene",
84             }
85             );
86             my $hit = $res->content->{response}{docs}->[0] || return;
87             $self->map_fields($hit);
88             $hit;
89             }
90              
91             sub add {
92             my ($self, $data) = @_;
93              
94             my $bag_field = $self->bag_field;
95              
96             my @fields = (WebService::Solr::Field->new($bag_field => $self->name));
97              
98             for my $key (keys %$data) {
99             next if $key eq $bag_field;
100             my $val = $data->{$key};
101             if (is_array_ref($val)) {
102             is_value($_) && push @fields,
103             WebService::Solr::Field->new($key => $_)
104             foreach @$val;
105             }
106             elsif (is_value($val)) {
107             push @fields, WebService::Solr::Field->new($key => $val);
108             }
109             }
110              
111             $self->buffer_add(WebService::Solr::Document->new(@fields));
112              
113             if ($self->buffer_is_full) {
114             $self->commit;
115             }
116             }
117              
118             sub delete {
119             my ($self, $id) = @_;
120             my $name = $self->name;
121             my $id_field = $self->id_field;
122             my $bag_field = $self->bag_field;
123             $self->store->solr->delete_by_query(
124             qq/$bag_field:"$name" AND $id_field:"$id"/);
125             }
126              
127             sub delete_all {
128             my ($self) = @_;
129             my $name = $self->name;
130             my $bag_field = $self->bag_field;
131             $self->store->solr->delete_by_query(qq/$bag_field:"$name"/);
132             }
133              
134             sub delete_by_query {
135             my ($self, %args) = @_;
136             my $name = $self->name;
137             my $bag_field = $self->bag_field;
138             $self->store->solr->delete_by_query(
139             qq/$bag_field:"$name" AND ($args{query})/);
140             }
141              
142             sub commit {
143             my ($self) = @_;
144             my $solr = $self->store->solr;
145             my $err;
146             if ($self->buffer_used) {
147             eval {$solr->add($self->buffer)} or push @{$err ||= []}, $@;
148             $self->clear_buffer;
149             }
150             unless ($self->store->{_tx}) {
151             eval {$solr->commit} or push @{$err ||= []}, $@;
152             }
153              
154             if (defined $err && $self->store->on_error eq 'throw') {
155             Catmandu::Error->throw($err->[0]);
156             }
157             }
158              
159             sub search {
160             my ($self, %args) = @_;
161              
162             my $query = delete $args{query};
163             my $start = delete $args{start};
164             my $limit = delete $args{limit};
165             my $bag = delete $args{reify};
166              
167             my $name = $self->name;
168             my $id_field = $self->id_field;
169             my $bag_field = $self->bag_field;
170              
171             my $bag_fq = qq/{!type=lucene}$bag_field:"$name"/;
172              
173             if ($args{fq}) {
174             if (is_array_ref($args{fq})) {
175             $args{fq} = [$bag_fq, @{$args{fq}}];
176             }
177             else {
178             $args{fq} = [$bag_fq, $args{fq}];
179             }
180             }
181             else {
182             $args{fq} = $bag_fq;
183             }
184              
185             my $res = $self->store->solr->search($query,
186             {%args, start => $start, rows => $limit});
187              
188             my $set = $res->content->{response}{docs};
189              
190             if ($bag) {
191             $set = [map {$bag->get($_->{$id_field})} @$set];
192             }
193             else {
194             $self->map_fields($_) for (@$set);
195             }
196              
197             my $hits = Catmandu::Hits->new(
198             {
199             limit => $limit,
200             start => $start,
201             total => $res->content->{response}{numFound},
202             hits => $set,
203             }
204             );
205              
206             if ($res->facet_counts) {
207             $hits->{facets} = $res->facet_counts;
208             }
209              
210             if ($res->spellcheck) {
211             $hits->{spellcheck} = $res->spellcheck;
212             }
213             if ($res->content->{highlighting}) {
214             $hits->{highlighting} = $res->content->{highlighting};
215             }
216              
217             $hits;
218             }
219              
220             sub searcher {
221             my ($self, %args) = @_;
222             Catmandu::Store::Solr::Searcher->new(%args, bag => $self);
223             }
224              
225             sub translate_sru_sortkeys {
226 0     0 0   my ($self, $sortkeys) = @_;
227             join(',',
228 0           grep {defined $_} map {$self->_translate_sru_sortkey($_)} split /\s+/,
  0            
  0            
229             $sortkeys);
230             }
231              
232             sub _translate_sru_sortkey {
233 0     0     my ($self, $sortkey) = @_;
234 0           my ($field, $schema, $asc) = split /,/, $sortkey;
235 0 0         $field || return;
236 0 0         if (my $map = $self->cql_mapping) {
237 0           $field = lc $field;
238             $field =~ s/(?<=[^_])_(?=[^_])//g
239 0 0         if $map->{strip_separating_underscores};
240 0   0       $map = $map->{indexes} || return;
241 0   0       $map = $map->{$field} || return;
242 0 0         $map->{sort} || return;
243 0 0 0       if (ref $map->{sort} && $map->{sort}{field}) {
    0          
    0          
244 0           $field = $map->{sort}{field};
245             }
246             elsif (ref $map->{field}) {
247 0           $field = $map->{field}->[0];
248             }
249             elsif ($map->{field}) {
250 0           $field = $map->{field};
251             }
252             }
253 0   0       $asc //= 1;
254 0 0         "${field} " . ($asc ? "asc" : "desc");
255             }
256              
257             sub translate_cql_query {
258 0     0 0   my ($self, $query) = @_;
259 0           Catmandu::Store::Solr::CQL->new(mapping => $self->cql_mapping)
260             ->parse($query);
261             }
262              
263             sub normalize_query {
264 0 0   0 0   $_[1] || "{!type=lucene}*:*";
265             }
266              
267             sub map_fields {
268 0     0 0   my ($self, $item) = @_;
269 0           delete $item->{$self->bag_field};
270             }
271              
272             =head1 SEE ALSO
273              
274             L<Catmandu::Bag>, L<Catmandu::Searchable>
275              
276             =cut
277              
278             1;