File Coverage

lib/Apache/Solr/JSON.pm
Criterion Covered Total %
statement 24 121 19.8
branch 0 38 0.0
condition 0 45 0.0
subroutine 8 24 33.3
pod 5 7 71.4
total 37 235 15.7


line stmt bran cond sub pod time code
1             # Copyrights 2012-2025 by [Mark Overmeer].
2             # For other contributors see ChangeLog.
3             # See the manual pages for details on the licensing terms.
4             # Pod stripped from pm file by OODoc 2.03.
5             # This code is part of distribution Apache-Solr. Meta-POD processed with
6             # OODoc into POD and HTML manual-pages. See README.md
7             # Copyright Mark Overmeer. Licensed under the same terms as Perl itself.
8              
9             package Apache::Solr::JSON;{
10             our $VERSION = '1.11';
11             }
12              
13 2     2   156292 use base 'Apache::Solr';
  2         3  
  2         1713  
14              
15 2     2   19 use warnings;
  2         3  
  2         136  
16 2     2   10 use strict;
  2         3  
  2         70  
17              
18 2     2   9 use Log::Report qw(solr);
  2         3  
  2         36  
19              
20 2     2   1318 use Apache::Solr::Result ();
  2         4  
  2         59  
21 2     2   11 use HTTP::Request ();
  2         4  
  2         25  
22 2     2   1852 use JSON ();
  2         24954  
  2         104  
23 2     2   17 use Scalar::Util qw(blessed);
  2         4  
  2         2952  
24              
25              
26             sub init($)
27 0     0 0   { my ($self, $args) = @_;
28 0   0       $args->{format} ||= 'JSON';
29 0           $self->SUPER::init($args);
30              
31 0   0       $self->{ASJ_json} = $args->{json} || JSON->new->utf8;
32 0           $self;
33             }
34              
35             #---------------
36              
37 0     0 1   sub json() {shift->{ASJ_json}}
38              
39             #--------------------------
40              
41             sub _select($$)
42 0     0     { my ($self, $args, $params) = @_;
43              
44             # select may be called more than once, but do not add wt each time
45             # again.
46 0           my $endpoint = $self->endpoint('select', params => $params);
47 0           my $result = Apache::Solr::Result->new(%$args, params => $params, endpoint => $endpoint, core => $self);
48 0           $self->request($endpoint, $result);
49              
50 0 0         if(my $dec = $result->decoded)
51             { # JSON uses different names!
52 0           my $r = $dec->{result} = delete $dec->{response};
53 0           $r->{doc} = delete $r->{docs};
54             }
55 0           $result;
56             }
57              
58             sub _extract($$$)
59 0     0     { my ($self, $params, $data, $ct) = @_;
60 0           my $endpoint = $self->endpoint('update/extract', params => $params);
61 0           my $result = Apache::Solr::Result->new(params => $params, endpoint => $endpoint, core => $self);
62 0           $self->request($endpoint, $result, $data, $ct);
63 0           $result;
64             }
65              
66             sub _add($$$)
67 0     0     { my ($self, $docs, $attrs, $params) = @_;
68 0   0       $attrs ||= {};
69 0   0       $params ||= [];
70              
71 0           my $sv = $self->serverVersion;
72 0 0         $sv ge '3.1' or error __x"Solr version too old for updates in JSON syntax";
73              
74             # We cannot create HASHes with twice the same key in Perl, so cannot
75             # produce the syntax for adding multiple documents. Try to save it.
76             delete $attrs->{boost}
77 0 0 0       if $attrs->{boost} && $attrs->{boost}==1.0;
78              
79 0 0         $params = +{ @$params } if ref $params eq 'ARRAY';
80             exists $attrs->{$_} && ($params->{$_} = delete $attrs->{$_})
81 0   0       for qw/commit commitWithin overwrite boost/;
82              
83 0 0         my $endpoint = $self->endpoint(($sv lt '4.0' ? 'update/json' : 'update'), params => $params);
84 0           my $result = Apache::Solr::Result->new(params => $params, endpoint => $endpoint, core => $self);
85              
86 0           my $add;
87 0 0         if(@$docs==1)
    0          
88 0           { $add = +{ add => +{ %$attrs, doc => $self->_doc2json($docs->[0]) } }
89             }
90             elsif(keys %$attrs)
91             { # in combination with attributes only
92 0           error __x"Unable to add more than one doc with JSON interface";
93             }
94             else
95 0           { $add = [ map $self->_doc2json($_), @$docs ];
96             }
97              
98 0           $self->request($endpoint, $result, $add);
99 0           $result;
100             }
101              
102             sub _doc2json($)
103 0     0     { my ($self, $this) = @_;
104 0           my %doc;
105 0           foreach my $fieldname ($this->fieldNames)
106 0           { my @f;
107 0           foreach my $field ($this->fields($fieldname))
108 0   0       { my $update = $field->{update} || 'value';
109 0   0       my $boost = $field->{boost} || 1.0;
110              
111 0 0 0       undef $boost
112             if $boost > 0.9999 && $boost < 1.0001;
113              
114             push @f
115             , ! defined $boost && $update eq 'value'
116             ? $field->{content}
117             : defined $boost
118             ? +{ boost => $boost, $update => $field->{content} }
119 0 0 0       : +{ $update => $field->{content} };
    0          
120             }
121             # we have to combine multi-fields into ARRAYS
122 0 0         $doc{$fieldname} = @f > 1 ? \@f : $f[0];
123             }
124              
125 0           \%doc;
126             }
127              
128 0     0     sub _commit($) { my ($s, $attr) = @_; $s->simpleUpdate(commit => $attr) }
  0            
129 0     0     sub _optimize($) { my ($s, $attr) = @_; $s->simpleUpdate(optimize => $attr) }
  0            
130 0     0     sub _delete($$) { my $self = shift; $self->simpleUpdate(delete => @_) }
  0            
131 0     0     sub _rollback() { shift->simpleUpdate('rollback') }
132              
133             sub _terms($)
134 0     0     { my ($self, $terms) = @_;
135 0           my $endpoint = $self->endpoint('terms', params => $terms);
136 0           my $result = Apache::Solr::Result->new(params => $terms, endpoint => $endpoint, core => $self);
137 0           $self->request($endpoint, $result);
138              
139 0   0       my $table = $result->decoded->{terms} || {};
140 0 0         $table = {@$table} if ref $table eq 'ARRAY'; # bug in Solr 1.4
141              
142 0           while(my ($field, $terms) = each %$table)
143             { # repack array-of-pairs into array-of-arrays-of-pair
144 0           my @pairs = @$terms;
145 0           my @terms;
146 0           push @terms, [shift @pairs, shift @pairs] while @pairs;
147 0           $result->terms($field => \@terms);
148             }
149              
150 0           $result;
151             }
152              
153             #--------------------------
154              
155             sub request($$;$$)
156 0     0 1   { my ($self, $url, $result, $body, $body_ct) = @_;
157              
158 0 0 0       if(ref $body && ref $body ne 'SCALAR')
159 0   0       { $body_ct ||= 'application/json; charset=utf-8';
160 0           $body = \$self->json->encode($body);
161             }
162              
163             # Solr server 3.6.2 seems not to detect the JSON input from the
164             # body content, so requires this work-around
165             # https://solr.apache.org/guide/6_6/uploading-data-with-index-handlers.html#UploadingDatawithIndexHandlers-JSONUpdateConveniencePaths
166 0           $url =~ s!/update\?!/update/json?!;
167              
168 0           $self->SUPER::request($url, $result, $body, $body_ct);
169             }
170              
171             sub decodeResponse($)
172 0     0 0   { my ($self, $resp) = @_;
173              
174             # At least until Solr 4.0 response ct=text/plain while producing JSON
175 0           my $ct = $resp->content_type;
176 0 0         $ct =~ m/json/i
177             or error __x"Answer from solr server is not json but {type}", type => $ct;
178              
179 0   0       $self->json->decode($resp->decoded_content || $resp->content);
180             }
181              
182              
183             sub simpleUpdate($$;$)
184 0     0 1   { my ($self, $command, $attrs, $content) = @_;
185 0           my $sv = $self->serverVersion;
186 0 0         $sv ge '3.1' or error __x"Solr version too old for updates in JSON syntax";
187              
188 0   0       $attrs ||= {};
189 0           my $params = [ commit => delete $attrs->{commit} ];
190 0 0         my $endpoint = $self->endpoint(($sv lt '4.0' ? 'update/json' : 'update'), params => $params);
191 0           my $result = Apache::Solr::Result->new(params => $params, endpoint => $endpoint, core => $self);
192 0 0         my %params = (%$attrs, (!$content ? () : ref $content eq 'HASH' ? %$content : @$content));
    0          
193 0           my $doc = $self->simpleDocument($command, \%params);
194 0           $self->request($endpoint, $result, $doc);
195 0           $result;
196             }
197              
198              
199             sub simpleDocument($;$$)
200 0     0 1   { my ($self, $command, $attrs, $content) = @_;
201 0   0       $attrs ||= {};
202 0   0       $content ||= {};
203 0           +{ $command => { %$attrs, %$content } }
204             }
205              
206             sub endpoint($@)
207 0     0 1   { my ($self, $action, %args) = @_;
208 0   0       my $params = $args{params} ||= [];
209              
210 0 0 0       if(ref $params eq 'HASH') { $params->{wt} ||= 'json' }
  0            
211 0           else { $args{params} = [ wt => 'json', @$params ] }
212              
213 0           $self->SUPER::endpoint($action, %args);
214             }
215              
216             1;