File Coverage

blib/lib/Elastic/Model/SearchBuilder.pm
Criterion Covered Total %
statement 32 46 69.5
branch 7 26 26.9
condition 1 2 50.0
subroutine 10 17 58.8
pod n/a
total 50 91 54.9


line stmt bran cond sub pod time code
1             package Elastic::Model::SearchBuilder;
2             $Elastic::Model::SearchBuilder::VERSION = '0.51';
3 12     12   401337 use strict;
  12         20  
  12         399  
4 12     12   50 use warnings;
  12         15  
  12         314  
5 12     12   9561 use ElasticSearch::SearchBuilder 0.18;
  12         109367  
  12         484  
6 12     12   8030 use parent 'ElasticSearch::SearchBuilder';
  12         3224  
  12         58  
7 12     12   882 use Carp;
  12         18  
  12         7221  
8              
9             #===================================
10             sub _hashpair_ElasticDocREF {
11             #===================================
12 0     0   0     my ( $self, $type, $k, $v ) = @_;
13 0         0     $self->_uid_to_terms( $type, $k, $v->uid );
14             }
15              
16             #===================================
17             sub _hashpair_ElasticUIDREF {
18             #===================================
19 0     0   0     my ( $self, $type, $k, $v ) = @_;
20 0         0     $self->_uid_to_terms( $type, $k, $v );
21             }
22              
23             #===================================
24             sub _filter_field_terms {
25             #===================================
26 123     123   3019     my ( $self, $k, $op, $val ) = @_;
27              
28                 return $self->_SWITCH_refkind(
29                     "Filter field operator -$op",
30                     $val,
31                     { ElasticDocREF =>
32 0     0   0                 sub { $self->_uid_to_terms( 'filter', $k, $val->uid ) },
33                         ElasticUIDREF =>
34 0     0   0                 sub { $self->_uid_to_terms( 'filter', $k, $val ) },
35                         FALLBACK => sub {
36 123     123   1365                 $self->SUPER::_filter_field_terms( $k, $op, $val );
37                         },
38                     }
39 123         1060     );
40             }
41              
42             #===================================
43             sub _query_field_match {
44             #===================================
45 108     108   3050     my $self = shift;
46 108         204     my ( $k, $op, $val ) = @_;
47              
48                 return $self->_SWITCH_refkind(
49                     "Query field operator -$op",
50                     $val,
51                     { ElasticDocREF =>
52 0     0   0                 sub { $self->_uid_to_terms( 'query', $k, $val->uid ) },
53                         ElasticUIDREF =>
54 0     0   0                 sub { $self->_uid_to_terms( 'query', $k, $val ) },
55                         FALLBACK => sub {
56 108     108   1583                 $self->SUPER::_query_field_match( $k, $op, $val );
57                         },
58                     }
59 108         1247     );
60             }
61              
62             #===================================
63             sub _uid_to_terms {
64             #===================================
65 0     0   0     my ( $self, $type, $k, $uid ) = @_;
66 0         0     my @clauses;
67 0         0     for (qw(index type id)) {
68 0 0       0         my $val = $uid->$_ or croak "UID missing ($_)";
69 0         0         push @clauses, { term => { "${k}.uid.$_" => $val } };
70                 }
71 0 0       0     return $type eq 'query'
72                     ? { bool => { must => \@clauses } }
73                     : { and => \@clauses }
74              
75             }
76              
77             #===================================
78             sub _refkind {
79             #===================================
80 4174     4174   3330748     my ( $self, $data ) = @_;
81              
82 4174 100       9164     return 'UNDEF' unless defined $data;
83              
84 3899 0       10027     my $ref
    0          
    0          
    50          
85                     = !Scalar::Util::blessed($data) ? ref $data
86                     : !$data->can('does') ? ''
87                     : $data->does('Elastic::Model::Role::Doc') ? 'ElasticDoc'
88                     : $data->isa('Elastic::Model::UID') ? 'ElasticUID'
89                     : '';
90              
91 3899 100       7873     return 'SCALAR' unless $ref;
92              
93 2792         2954     my $n_steps = 1;
94 2792         5486     while ( $ref eq 'REF' ) {
95 6         10         $data = $$data;
96 6 0       17         $ref
    0          
    0          
    50          
97                         = !Scalar::Util::blessed($data) ? ref $data
98                         : !$data->can('does') ? ''
99                         : $data->does('Elastic::Model::Role::Doc') ? 'ElasticDoc'
100                         : $data->isa('Elastic::Model::UID') ? 'ElasticUID'
101                         : '';
102 6 50       16         $n_steps++ if $ref;
103                 }
104              
105 2792   50     11549     return ( $ref || 'SCALAR' ) . ( 'REF' x $n_steps );
106             }
107              
108             1;
109              
110             # ABSTRACT: An Elastic::Model specific subclass of L<ElasticSearch::SearchBuilder>
111              
112             __END__
113            
114             =pod
115            
116             =encoding UTF-8
117            
118             =head1 NAME
119            
120             Elastic::Model::SearchBuilder - An Elastic::Model specific subclass of L<ElasticSearch::SearchBuilder>
121            
122             =head1 VERSION
123            
124             version 0.51
125            
126             =head1 DESCRIPTION
127            
128             L<Elastic::Model::SearchBuilder> is a sub-class of L<ElasticSearch::SearchBuilder>
129             to add automatic handling of L<Elastic::Doc> and L<Elastic::Model::UID>
130             values.
131            
132             This document just explains the functionality that
133             L<Elastic::Model::SearchBuilder> adds.
134            
135             B<For the full SearchBuilder docs, see L<ElasticSearch::SearchBuilder>>.
136            
137             =head1 THE PROBLEM
138            
139             Consider this class (where C<MyApp::User> is also an
140             L<Elastic::Doc> class):
141            
142             package MyApp::Comment;
143            
144             use Elastic::Doc;
145            
146             has 'user' => (
147             is => 'ro',
148             isa => 'MyApp::User,
149             );
150            
151             has 'text' => (
152             is => 'ro',
153             isa => 'Str',
154             );
155            
156             We can create a comment as follows:
157            
158             $domain->create(
159             comment => {
160             text => 'I like Elastic::Model',
161             user => $user,
162             }
163             );
164            
165             The C<comment> object would be stored in Elasticsearch as something like this:
166            
167             {
168             text => "I like Elastic::Model",
169             user => {
170             uid => {
171             index => 'myapp',
172             type => 'user',
173             id => 'abcdefg',
174             },
175             .... any other user fields....
176             }
177             }
178            
179             In order to search for any comments by user C<$user>, you would need to do this:
180            
181             $view->type('comment')
182             ->filterb(
183             'user.uid.index' => $user->uid->index,
184             'user.uid.type' => $user->uid->type,
185             'user.uid.id' => $user->uid->id,
186             )
187             ->search;
188            
189             =head1 THE SOLUTION
190            
191             With L<Elastic::Model::SearchBuilder>, you can do it as follows:
192            
193             $view->type('comment')
194             ->filterb( user => $user )
195             ->search;
196            
197             Or with the C<UID>:
198            
199             $view->type('comment')
200             ->filterb( user => $user->uid )
201             ->search;
202            
203             =head1 FURTHER EXAMPLES
204            
205             =head2 Query or Filter
206            
207             This works for both queries and filters, eg:
208            
209             $view->queryb ( user => $user )->search;
210             $view->filterb( user => $user )->search;
211            
212             =head2 Doc or UID
213            
214             You can use either the doc/object itself, or an L<Elastic::Model::UID> object:
215            
216             $uid = $user->uid;
217             $view->queryb ( user => $uid )->search;
218             $view->filterb( user => $uid )->search;
219            
220             =head2 Negating queries:
221            
222             $view->queryb ( user => { '!=' => $user })->search;
223             $view->filterb( user => { '!=' => $user })->search;
224            
225             =head2 "IN" queries
226            
227             $view->queryb ( user => \@users )->search;
228             $view->filterb( user => \@users )->search;
229            
230             =head2 "NOT IN" queries
231            
232             $view->queryb ( user => { '!=' => \@users })->search;
233             $view->filterb( user => { '!=' => \@users })->search;
234            
235             =head1 AUTHOR
236            
237             Clinton Gormley <drtech@cpan.org>
238            
239             =head1 COPYRIGHT AND LICENSE
240            
241             This software is copyright (c) 2015 by Clinton Gormley.
242            
243             This is free software; you can redistribute it and/or modify it under
244             the same terms as the Perl 5 programming language system itself.
245            
246             =cut
247