File Coverage

blib/lib/Elastic/Model.pm
Criterion Covered Total %
statement 26 34 76.4
branch 6 16 37.5
condition 1 3 33.3
subroutine 11 13 84.6
pod 4 9 44.4
total 48 75 64.0


line stmt bran cond sub pod time code
1             package Elastic::Model;
2             $Elastic::Model::VERSION = '0.51';
3 23     23   3777483 use Moose 2.06 ();
  23         7243992  
  23         888  
4 23     23   221 use Moose::Exporter();
  23         33  
  23         391  
5 23     23   101 use Carp;
  23         38  
  23         1804  
6 23     23   23014 use namespace::autoclean;
  23         35442  
  23         154  
7              
8             Moose::Exporter->setup_import_methods(
9                 class_metaroles => { class => ['Elastic::Model::Meta::Class::Model'] },
10                 with_meta => [
11                     qw(has_namespace has_typemap override_classes
12             has_analyzer has_tokenizer has_filter has_char_filter
13             has_unique_index)
14                 ],
15                 also => 'Moose',
16             );
17              
18             #===================================
19             sub init_meta {
20             #===================================
21 23     23 0 2471     shift;
22 23         113     my $meta = Moose->init_meta(@_);
23 23         135292     Moose::Util::apply_all_roles( $meta, 'Elastic::Model::Role::Model' );
24             }
25              
26             #===================================
27             sub has_namespace {
28             #===================================
29 26     26 0 73090     my $meta = shift;
30 26 50       611     my $name = shift or croak "No namespace name passed to namespace";
31 26         259     my %params = ( types => @_ );
32              
33 26         63     my $types = $params{types};
34 26 50 33     301     croak "No types specified for namespace $name"
35                     unless $types && %$types;
36              
37 26         2017     $meta->add_namespace( $name => \%params );
38             }
39              
40             #===================================
41 11     11 0 808 sub has_typemap { shift->set_class( 'typemap', @_ ) }
42             #===================================
43              
44             #===================================
45             sub has_unique_index {
46             #===================================
47 0     0 0 0     my ( $meta, $val ) = @_;
48 0         0     $meta->unique_index($val);
49             }
50              
51             #===================================
52             sub override_classes {
53             #===================================
54 0     0 0 0     my $meta = shift;
55 0 0       0     my %classes = ref $_[0] eq 'HASH' ? %{ shift() } : @_;
  0         0  
56 0         0     for ( keys %classes ) {
57 0 0       0         croak "Unknown arg for classes ($_)"
58                         unless $meta->get_class($_);
59 0         0         $meta->set_class( $_ => $classes{$_} );
60                 }
61             }
62              
63             #===================================
64             sub has_analyzer {
65             #===================================
66 4 50   4 1 74     shift->add_analyzer( shift, ref $_[0] eq 'HASH' ? shift() : {@_} );
67             }
68             #===================================
69             sub has_tokenizer {
70             #===================================
71 1 50   1 1 21     shift->add_tokenizer( shift, ref $_[0] eq 'HASH' ? shift() : {@_} );
72             }
73             #===================================
74             sub has_filter {
75             #===================================
76 2 50   2 1 51     shift->add_filter( shift, ref $_[0] eq 'HASH' ? shift() : {@_} );
77             }
78              
79             #===================================
80             sub has_char_filter {
81             #===================================
82 1 50   1 1 27     shift->add_char_filter( shift, ref $_[0] eq 'HASH' ? shift() : {@_} );
83             }
84              
85             1;
86              
87             # ABSTRACT: A NoSQL document store with full text search for Moose objects using Elasticsearch as a backend.
88              
89             __END__
90            
91             =pod
92            
93             =encoding UTF-8
94            
95             =head1 NAME
96            
97             Elastic::Model - A NoSQL document store with full text search for Moose objects using Elasticsearch as a backend.
98            
99             =head1 VERSION
100            
101             version 0.51
102            
103             =head1 SYNOPSIS
104            
105             package MyApp;
106            
107             use Elastic::Model;
108            
109             has_namespace 'myapp' => {
110             user => 'MyApp::User',
111             post => 'MyApp::Post'
112             };
113            
114             has_typemap 'MyApp::TypeMap';
115            
116             # Setup custom analyzers
117            
118             has_filter 'edge_ngrams' => (
119             type => 'edge_ngram',
120             min_gram => 2,
121             max_gram => 10
122             );
123            
124             has_analyzer 'edge_ngrams' => (
125             tokenizer => 'standard',
126             filter => [ 'standard', 'lowercase', 'edge_ngrams' ]
127             );
128            
129             no Elastic::Model;
130            
131             =head1 DESCRIPTION
132            
133             Elastic::Model is a framework to store your Moose objects, which uses
134             Elasticsearch as a NoSQL document store and flexible search engine.
135            
136             It is designed to make it easy to start using Elasticsearch with minimal extra
137             code, but allows you full access to the rich feature set available in
138             Elasticsearch as soon as you are ready to use it.
139            
140             =head1 INTRODUCTION TO Elastic::Model
141            
142             If you are not familiar with L<Elastic::Model>, you should start by reading
143             L<Elastic::Manual::Intro>.
144            
145             The rest of the documentation on this page explains how to use the
146             L<Elastic::Model> module itself.
147            
148             =head1 BACKWARDS COMPATIBILITY BREAK
149            
150             B<NOTE:> This version of Elastic::Model uses L<Search::Elasticsearch>
151             and is intended for Elasticsearch 1.0 and above. However, it can be used
152             with Elasticsearch 0.90.x in "compatibility mode".
153            
154             B<< You can no longer use the old L<Search::Elasticsearch::Compat>. >>
155             See L<Elastic::Manual::Delta> for instructions.
156            
157             For a version of Elastic::Model which uses Search::Elasticsearch::Compat
158             please see L<https://metacpan.org/release/DRTECH/Elastic-Model-0.28>.
159            
160             =head1 USING ELASTIC::MODEL
161            
162             Your application needs a C<model> class to handle the relationship between
163             your object classes and the Elasticsearch cluster.
164            
165             Your model class is most easily defined as follows:
166            
167             package MyApp;
168            
169             use Elastic::Model;
170            
171             has_namespace 'myapp' => {
172             user => 'MyApp::User',
173             post => 'MyApp::Post'
174             };
175            
176             no Elastic::Model;
177            
178             This applies L<Elastic::Model::Role::Model> to your C<MyApp> class,
179             L<Elastic::Model::Meta::Class::Model> to C<MyApp>'s metaclass and exports
180             functions which help you to configure your model.
181            
182             Your model must define at least one L<namespace|Elastic::Manual::Terminology/Namespace>,
183             which tells Elastic::Model which
184             L<type|Elastic::Manual::Terminology/Type> (like a table in a DB) should be
185             handled by which of your classes. So the above declaration says:
186            
187             I<"For all L<indices|Elastic::Model::Terminology/Index> which belong to namespace
188             C<myapp>, objects of class C<MyApp::User> will be stored under the
189             L<type|Elastic::Model::Terminology/Type> C<user> in Elasticsearch.">
190            
191             =head2 Custom TypeMap
192            
193             Elastic::Model uses a L<TypeMap|Elastic::Model::TypeMap::Default> to figure
194             out how to inflate and deflate your objects, and how to configure them
195             in Elasticsearch.
196            
197             You can specify your own TypeMap using:
198            
199             has_typemap 'MyApp::TypeMap';
200            
201             See L<Elastic::Model::TypeMap::Base> for instructions on how to define
202             your own type-map classes.
203            
204             =head2 Custom unique key index
205            
206             If you have attributes whose values are
207             L<unique|Elastic::Manual::Attributes::Unique>, then you can customize the index
208             where these unique values are stored.
209            
210             has_unique_index 'myapp_unique';
211            
212             The default value is C<unique_key>.
213            
214             =head2 Custom analyzers
215            
216             Analysis is the process of converting full text into C<terms> or C<tokens> and
217             is one of the things that gives full text search its power. When storing text
218             in the Elasticsearch index, the text is first analyzed into terms/tokens.
219             Then, when searching, search keywords go through the same analysis process
220             to produce the terms/tokens which are then searched for in the index.
221            
222             Choosing the right analyzer for each field gives you enormous control over
223             how your data can be queried.
224            
225             There are a large number of built-in analyzers available, but frequently
226             you will want to define custom analyzers, which consist of:
227            
228             =over
229            
230             =item *
231            
232             zero or more character filters
233            
234             =item *
235            
236             a tokenizer
237            
238             =item *
239            
240             zero or more token filters
241            
242             =back
243            
244             L<Elastic::Model> provides sugar to make it easy to specify custom analyzers:
245            
246             =head3 has_char_filter
247            
248             Character filters can change the text before it gets tokenized, for instance:
249            
250             has_char_filter 'my_mapping' => (
251             type => 'mapping',
252             mappings => ['ph=>f','qu=>q']
253             );
254            
255             See L<Elastic::Model::Meta::Class::Model/Default character filters> for a list
256             of the built-in character filters.
257            
258             =head3 has_tokenizer
259            
260             A tokenizer breaks up the text into individual tokens or terms. For instance,
261             the C<pattern> tokenizer could be used to split text using a regex:
262            
263             has_tokenizer 'my_word_tokenizer' => (
264             type => 'pattern',
265             pattern => '\W+', # splits on non-word chars
266             );
267            
268             See L<Elastic::Model::Meta::Class::Model/Default tokenizers> for a list
269             of the built-in tokenizers.
270            
271             =head3 has_filter
272            
273             Any terms/tokens produced by the L</"has_tokenizer"> can the be passed through
274             multiple token filters. For instance, each term could be broken down into
275             "edge ngrams" (eg 'foo' => 'f','fo','foo') for partial matching.
276            
277             has_filter 'my_ngrams' => (
278             type => 'edge_ngram',
279             min_gram => 1,
280             max_gram => 10,
281             );
282            
283             See L<Elastic::Model::Meta::Class::Model/Default token filters> for a list
284             of the built-in character token filters.
285            
286             =head3 has_analyzer
287            
288             Custom analyzers can be defined by combining character filters, a tokenizer and
289             token filters, some of which could be built-in, and some defined by the
290             keywords above.
291            
292             For instance:
293            
294             has_analyzer 'partial_word_analyzer' => (
295             type => 'custom',
296             char_filter => ['my_mapping'],
297             tokenizer => ['my_word_tokenizer'],
298             filter => ['lowercase','stop','my_ngrams']
299             );
300            
301             See L<Elastic::Model::Meta::Class::Model/Default analyzers> for a list
302             of the built-in analyzers.
303            
304             =head2 Overriding Core Classes
305            
306             If you would like to override any of the core classes used by L<Elastic::Model>,
307             then you can do so as follows:
308            
309             override_classes (
310             domain => 'MyApp::Domain',
311             store => 'MyApp::Store'
312             );
313            
314             The defaults are:
315            
316             =over
317            
318             =item *
319            
320             C<namespace> C<-----------> L<Elastic::Model::Namespace>
321            
322             =item *
323            
324             C<domain> C<--------------> L<Elastic::Model::Domain>
325            
326             =item *
327            
328             C<store> C<---------------> L<Elastic::Model::Store>
329            
330             =item *
331            
332             C<view> C<----------------> L<Elastic::Model::View>
333            
334             =item *
335            
336             C<scope> C<---------------> L<Elastic::Model::Scope>
337            
338             =item *
339            
340             C<results> C<-------------> L<Elastic::Model::Results>
341            
342             =item *
343            
344             C<cached_results> C<------> L<Elastic::Model::Results::Cached>
345            
346             =item *
347            
348             C<scrolled_results> C<----> L<Elastic::Model::Results::Scrolled>
349            
350             =item *
351            
352             C<result> C<--------------> L<Elastic::Model::Result>
353            
354             =item *
355            
356             C<bulk> C<----------------> L<Elastic::Model::Bulk>
357            
358             =back
359            
360             =head1 SEE ALSO
361            
362             =over
363            
364             =item *
365            
366             L<Elastic::Model::Role::Model>
367            
368             =item *
369            
370             L<Elastic::Manual>
371            
372             =item *
373            
374             L<Elastic::Doc>
375            
376             =back
377            
378             =head1 AUTHOR
379            
380             Clinton Gormley <drtech@cpan.org>
381            
382             =head1 COPYRIGHT AND LICENSE
383            
384             This software is copyright (c) 2015 by Clinton Gormley.
385            
386             This is free software; you can redistribute it and/or modify it under
387             the same terms as the Perl 5 programming language system itself.
388            
389             =cut
390