File Coverage

blib/lib/WebService/Solr/Tiny.pm
Criterion Covered Total %
statement 47 49 95.9
branch 4 4 100.0
condition 4 10 40.0
subroutine 10 10 100.0
pod 4 4 100.0
total 69 77 89.6


line stmt bran cond sub pod time code
1             package WebService::Solr::Tiny 0.002;
2              
3 6     6   1369408 use v5.20;
  6         51  
4 6     6   33 use warnings;
  6         12  
  6         192  
5 6     6   3185 use experimental qw/lexical_subs postderef signatures/;
  6         21613  
  6         31  
6              
7 6     6   1486 use Exporter 'import';
  6         11  
  6         284  
8 6     6   3153 use URI::Query::FromHash 0.003;
  6         5670  
  6         43  
9              
10             our @EXPORT_OK = qw/solr_escape solr_query/;
11              
12 2     2 1 3017 sub new ( $class, %args ) {
  2         7  
  2         14  
  2         4  
13 2         6 my $self = bless \%args, $class;
14              
15             $self->{agent} //=
16 2   33     13 do { require HTTP::Tiny; HTTP::Tiny->new( keep_alive => 1 ) };
  0         0  
  0         0  
17             $self->{decoder} //=
18 2   33     10 do { require JSON::PP; \&JSON::PP::decode_json };
  2         1453  
  2         28559  
19 2   50     16 $self->{default_args} //= {};
20 2   50     11 $self->{url} //= 'http://localhost:8983/solr/select';
21              
22 2         8 $self;
23             }
24              
25 4     4 1 7008 sub search ( $self, $q = '', %args ) {
  4         8  
  4         9  
  4         11  
  4         8  
26             my $reply = $self->{agent}->get( $self->{url} . '?' .
27 4         31 hash2query { $self->{default_args}->%*, q => $q, %args } );
28              
29 4 100       322 unless ( $reply->{success} ) {
30 1         6 require Carp;
31              
32 1         165 Carp::croak("Solr request failed - $reply->{content}");
33             }
34              
35 3         11 $self->{decoder}( $reply->{content} );
36             }
37              
38 62     62 1 7568 sub solr_escape ( $q ) { $q =~ s/([\Q+-&|!(){}[]^"~*?:\\\E])/\\$1/gr }
  61         81  
  61         88  
  61         444  
39              
40             # For solr_query
41             my ( %struct, %value, %op );
42 33 100   33 1 18181 sub solr_query ( $x ) { $struct{ARRAY}->( ref $x eq 'ARRAY' ? $x : [ $x ] ) }
  33         56  
  33         48  
  33         124  
43              
44             my sub dispatch ( $table, $name, @args ) {
45             ( $table->{$name} // die "Cannot dispatch to $name" )->(@args);
46             }
47              
48             my sub pair ( $k, $v ) {
49             # If it's an array ref, the first element MAY be an operator:
50             # [ -and => { -require => 'X' }, { -require => 'Y' } ]
51             if ( ref $v eq 'ARRAY' && ( $v->[0] // '' ) =~ /^-(AND|OR)$/i ) {
52             my ( $op, undef, @val ) = ( uc $1, @$v );
53             return sprintf '(%s)',
54             join " $op ", map '(' . $struct{HASH}->({ $k => $_ }) . ')', @val;
55             }
56              
57             dispatch( \%value, ref $v || 'SCALAR', $k, $v );
58             }
59              
60             $struct{HASH} = sub( $x ) {
61             join ' AND ', map {
62             /^-(.+)/ ? dispatch( \%op, $1, $x->{$_} ) : pair( $_, $x->{$_} )
63             } sort keys %$x;
64             };
65              
66             $struct{ARRAY} = sub ( $x ) {
67             '(' . join( ' OR ', map dispatch( \%struct, ref $_, $_ ), @$x ) . ')';
68             };
69              
70             $value{SCALAR} = sub ( $k, $v ) {
71             my $value = ref $v ? $$v : ( '"' . solr_escape($v) . '"' );
72             "$k:$value" =~ s/^://r;
73             };
74              
75             $value{HASH} = sub ( $k, $v ) {
76             join ' AND ',
77             map dispatch( \%op, s/^-(.+)/$1/r, $k, $v->{$_} ), sort keys %$v;
78             };
79              
80             $value{ARRAY} = sub ( $k, $v ) {
81             '(' . join( ' OR ', map $value{SCALAR}->( $k, $_ ), @$v ) . ')';
82             };
83              
84             $op{default} = sub ( $v ) { pair( '', $v ) };
85             $op{require} = sub ( $k, $v ) { qq(+$k:") . solr_escape($v) . '"' };
86             $op{prohibit} = sub ( $k, $v ) { qq(-$k:") . solr_escape($v) . '"' };
87             $op{range} = sub ( $k, $v ) { "$k:[$v->[ 0 ] TO $v->[ 1 ]]" };
88             $op{range_exc} = sub ( $k, $v ) { "$k:{$v->[ 0 ] TO $v->[ 1 ]}" };
89             $op{range_inc} = $op{range};
90              
91             $op{boost} = sub ( $k, $extra ) {
92             my ( $v, $boost ) = @$extra;
93             sprintf '%s:"%s"^%s', $k, solr_escape($v), $boost;
94             };
95              
96             $op{fuzzy} = sub ( $k, $extra ) {
97             my ( $v, $dist ) = @$extra;
98             sprintf '%s:%s~%s', $k, solr_escape($v), $dist;
99             };
100              
101             $op{proximity} = sub ( $k, $extra ) {
102             my ( $v, $dist ) = @$extra;
103             sprintf '%s:"%s"~%s', $k, solr_escape($v), $dist;
104             };
105              
106 6     6   9870 no URI::Query::FromHash;
  6         15  
  6         27  
107              
108             1;