File Coverage

blib/lib/Elastic/Model/Role/Model.pm
Criterion Covered Total %
statement 98 267 36.7
branch 4 100 4.0
condition 4 39 10.2
subroutine 75 101 74.2
pod 21 23 91.3
total 202 530 38.1


line stmt bran cond sub pod time code
1             package Elastic::Model::Role::Model;
2             $Elastic::Model::Role::Model::VERSION = '0.52';
3 23     23   37897 use Moose::Role;
  23         108537  
  23         107  
4 23     23   125054 use Carp;
  23         55  
  23         1573  
5 23     23   15974 use Elastic::Model::Types qw(ES);
  23         82  
  23         166  
6 23     23   151773 use Search::Elasticsearch 1.20 ();
  23         833  
  23         637  
7 23     23   128 use Class::Load qw(load_class);
  23         48  
  23         1397  
8 23     23   223 use Moose::Util qw(does_role);
  23         46  
  23         261  
9 23     23   4575 use MooseX::Types::Moose qw(:all);
  23         46  
  23         192  
10 23     23   216002 use Elastic::Model::UID();
  23         102  
  23         856  
11 23     23   18202 use Elastic::Model::Deleted();
  23         94  
  23         828  
12 23     23   174 use Scalar::Util qw(blessed refaddr weaken);
  23         42  
  23         1602  
13 23     23   946 use List::MoreUtils qw(uniq);
  23         50  
  23         284  
14 23     23   16342 use JSON();
  23         64189  
  23         1060  
15             our $JSON = JSON->new->canonical->utf8;
16              
17 23     23   131 use namespace::autoclean;
  23         43  
  23         168  
18             my @wrapped_classes = qw(
19             domain namespace store view scope
20             results cached_results scrolled_results result bulk
21             );
22              
23             #===================================
24             sub BUILD {
25             #===================================
26 24     24 0 54689     my $self = shift;
27 24         971     my $es = $self->es;
28 24 50       337     if ( $es->isa('Search::Elasticsearch::Client::0_90::Direct') ) {
29 0         0         $self->_set_result_class(
30                         $self->_wrap_class('Elastic::Model::0_90::Result') );
31 0         0         $self->_set_store_class(
32                         $self->_wrap_class('Elastic::Model::0_90::Store') );
33                 }
34 24         995     $self->doc_class_wrappers;
35 24         150     return $self;
36              
37             }
38              
39             for my $class (@wrapped_classes) {
40             #===================================
41                 has "${class}_class" => (
42             #===================================
43                     isa => Str,
44                     is => 'ro',
45                     lazy => 1,
46                     writer => "_set_${class}_class",
47                     default => sub { shift->wrap_class($class) }
48                 );
49             }
50              
51             #===================================
52             has 'typemap' => (
53             #===================================
54                 is => 'ro',
55                 isa => Str,
56                 default => sub { shift->wrap_class('typemap') }
57             );
58              
59             #===================================
60             has [ 'deflators', 'inflators' ] => (
61             #===================================
62                 isa => HashRef,
63                 is => 'ro',
64                 default => sub { {} }
65             );
66              
67             #===================================
68             has 'store' => (
69             #===================================
70                 does => 'Elastic::Model::Role::Store',
71                 is => 'ro',
72                 lazy => 1,
73                 builder => '_build_store'
74             );
75              
76             #===================================
77             has 'es' => (
78             #===================================
79                 isa => ES,
80                 is => 'ro',
81                 lazy => 1,
82                 builder => '_build_es',
83                 coerce => 1,
84             );
85              
86             #===================================
87             has '_unique_index' => (
88             #===================================
89                 isa => Str,
90                 is => 'ro',
91                 lazy => 1,
92                 builder => '_build_unique_index',
93             );
94              
95             #===================================
96             has 'doc_class_wrappers' => (
97             #===================================
98                 is => 'ro',
99                 isa => HashRef,
100                 traits => ['Hash'],
101                 lazy => 1,
102                 builder => '_build_doc_class_wrappers',
103                 handles => {
104                     class_for => 'get',
105                     knows_class => 'exists'
106                 }
107             );
108              
109             #===================================
110             has 'namespaces' => (
111             #===================================
112                 is => 'ro',
113                 isa => HashRef,
114                 traits => ['Hash'],
115                 builder => '_build_namespaces',
116                 handles => { namespace => 'get' }
117             );
118              
119             #===================================
120             has '_domain_cache' => (
121             #===================================
122                 isa => HashRef,
123                 is => 'bare',
124                 traits => ['Hash'],
125                 default => sub { {} },
126              
127             # TODO clear domain cache when changing indices/aliases?
128                 handles => {
129                     _get_domain => 'get',
130                     _cache_domain => 'set',
131                 },
132             );
133              
134             #===================================
135             has '_domain_namespace' => (
136             #===================================
137                 is => 'ro',
138                 isa => HashRef,
139                 traits => ['Hash'],
140                 lazy => 1,
141                 builder => '_build_domain_namespace',
142                 clearer => 'clear_domain_namespace',
143                 handles => { _get_domain_namespace => 'get', }
144             );
145              
146             #===================================
147             has 'current_scope' => (
148             #===================================
149                 is => 'rw',
150                 isa => 'Elastic::Model::Scope',
151                 weak_ref => 1,
152                 clearer => 'clear_current_scope',
153                 predicate => 'has_current_scope',
154             );
155              
156             #===================================
157 1     1   36 sub _build_store { $_[0]->store_class->new( es => $_[0]->es ) }
158 24     24   284 sub _build_es { Search::Elasticsearch->new( client => '1_0::Direct' ) }
159             #===================================
160              
161             #===================================
162             sub _build_unique_index {
163             #===================================
164 0     0   0     my $self = shift;
165 0         0     my $index = Class::MOP::class_of($self)->unique_index;
166 0         0     $self->store->bootstrap_uniques( index => $index );
167 0         0     return $index;
168             }
169              
170             #===================================
171             sub _build_namespaces {
172             #===================================
173 24     24   28102     my $self = shift;
174 24         111     my $conf = Class::MOP::class_of($self)->namespaces;
175 24         64     my %namespaces;
176 24         896     my $ns_class = $self->namespace_class;
177 24         198     while ( my ( $name, $args ) = each %$conf ) {
178 52         159         my $types = $args->{types};
179                     my %classes
180 52         260             = map { $_ => $self->class_for( $types->{$_} ) } keys %$types;
  336         15437  
181                     $namespaces{$name} = $ns_class->new(
182                         name => $name,
183                         types => \%classes,
184 52   100     2991             fixed_domains => $args->{fixed_domains} || []
185                     );
186                 }
187 24         202     \%namespaces;
188             }
189              
190             #===================================
191             sub _build_doc_class_wrappers {
192             #===================================
193 24     24   65     my $self = shift;
194 24         119     my $namespaces = Class::MOP::class_of($self)->namespaces;
195 172         976     +{ map { $_ => $self->wrap_doc_class($_) }
196 24         101         map { values %{ $_->{types} } } values %$namespaces
  28         75  
  28         215  
197                 };
198             }
199              
200             #===================================
201             sub _build_domain_namespace {
202             #===================================
203 0     0   0     my $self = shift;
204 0         0     my $namespaces = $self->namespaces;
205 0         0     my %domains;
206              
207 0         0     for my $name ( keys %$namespaces ) {
208 0         0         my $ns = $namespaces->{$name};
209 0         0         for my $domain ( $namespaces->{$name}->all_domains ) {
210                         croak "Cannot map domain ($domain) to namespace ($name). "
211                             . "It is already mapped to namespace ("
212                             . $domains{$domain}->name . ")."
213 0 0       0                 if $domains{$domain};
214 0         0             $domains{$domain} = $ns;
215                     }
216                 }
217 0         0     \%domains;
218             }
219              
220             #===================================
221             sub namespace_for_domain {
222             #===================================
223 0     0 1 0     my ( $self, $domain ) = @_;
224 0         0     my $ns;
225 0 0       0     $ns = $self->_get_domain_namespace($domain) and return $ns;
226 0         0     $self->clear_domain_namespace;
227 0 0       0     $self->_get_domain_namespace($domain)
228                     or croak "No namespace found for domain ($domain). ";
229             }
230              
231             #===================================
232             sub all_live_indices {
233             #===================================
234 0     0 1 0     my $self = shift;
235 0         0     return map { $_->all_live_indices } values %{ $self->namespaces };
  0         0  
  0         0  
236             }
237              
238             #===================================
239             sub wrap_doc_class {
240             #===================================
241 172     172 1 398     my $self = shift;
242 172         415     my $class = shift;
243              
244 172         1001     load_class($class);
245              
246 172 50       18783940     croak "Class ($class) does not do Elastic::Model::Role::Doc. "
247                     . "Please add : use Elastic::Doc;\n\n"
248                     unless Moose::Util::does_role( $class, 'Elastic::Model::Role::Doc' );
249              
250 172         54928     $self->_wrap_class($class);
251             }
252              
253             #===================================
254             sub wrap_class {
255             #===================================
256 62     62 1 161     my $self = shift;
257 62   50     296     my $name = shift || '';
258 62 50       380     my $class = $self->meta->get_class($name)
259                     or croak "Unknown class for ($name)";
260              
261 62         336     $self->_wrap_class($class);
262             }
263              
264             #===================================
265             sub _wrap_class {
266             #===================================
267 234     234   601     my $self = shift;
268 234         709     my $class = shift;
269 234         1134     load_class($class);
270              
271 234         9244     my $meta
272                     = Moose::Meta::Class->create(
273                     Class::MOP::class_of($self)->wrapped_class_name($class),
274                     superclasses => [$class] );
275              
276 234         602484     weaken( my $weak_model = $self );
277 234     76   1786     $meta->add_method( model => sub {$weak_model} );
  76     76   2246  
        76      
        76      
        76      
        76      
        76      
        54      
        54      
        54      
        34      
        34      
        22      
        22      
        22      
        22      
        22      
        22      
        22      
        22      
        22      
        22      
        22      
        22      
        22      
278 234     1153   12376     $meta->add_method( original_class => sub {$class} );
  1153     1153   3054  
        1153      
        1153      
        1153      
        1153      
        1153      
        1118      
        1118      
        1118      
        84      
        84      
        22      
        22      
        22      
        22      
        22      
        22      
        22      
        22      
        22      
        22      
        22      
        22      
        22      
279 234         10603     $meta->make_immutable;
280              
281 234         534821     return $meta->name;
282             }
283              
284             #===================================
285             sub domain {
286             #===================================
287 0     0 1 0     my $self = shift;
288 0 0       0     my $name = shift or croak "No domain name passed to domain()";
289 0         0     my $domain;
290              
291 0 0       0     $domain = $self->_get_domain($name) and return $domain;
292 0 0       0     my $ns = $self->namespace_for_domain($name)
293                     or croak "Unknown domain name ($name)";
294              
295 0         0     $domain = $self->domain_class->new(
296                     name => $name,
297                     namespace => $ns
298                 );
299 0         0     return $self->_cache_domain( $name => $domain );
300             }
301              
302             #===================================
303 1     1 1 40 sub view { shift->view_class->new(@_) }
304             #===================================
305              
306             #===================================
307             sub new_scope {
308             #===================================
309 0     0 1 0     my $self = shift;
310                 my @args
311 0 0       0         = $self->has_current_scope ? ( parent => $self->current_scope ) : ();
312 0         0     $self->current_scope( $self->scope_class->new(@args) );
313             }
314              
315             #===================================
316             sub detach_scope {
317             #===================================
318 0     0 1 0     my ( $self, $scope ) = @_;
319 0         0     my $current = $self->current_scope;
320 0 0 0     0     return unless $current && refaddr($current) eq refaddr($scope);
321 0         0     my $parent = $scope->parent;
322 0 0       0     return $self->clear_current_scope unless $parent;
323 0         0     $self->current_scope($parent);
324             }
325              
326             #===================================
327             sub get_doc {
328             #===================================
329 0     0 1 0     my ( $self, %args ) = @_;
330                 my $uid = $args{uid}
331 0 0       0         or croak "No UID passed to get_doc()";
332              
333 0         0     my $ns = $self->namespace_for_domain( $uid->index );
334 0         0     my $scope = $self->current_scope;
335 0         0     my $source = $args{source};
336              
337 0         0     my $object;
338 0 0 0     0     $object = $scope->get_object( $ns->name, $uid )
339                     if $scope && !$source;
340              
341 0 0       0     unless ($object) {
342 0 0 0     0         unless ( $source || $uid->from_store ) {
343 0 0       0             $source = $self->get_doc_source(%args) or return;
344                     }
345 0         0         my $class = $ns->class_for_type( $uid->type );
346 0         0         $object = $class->meta->new_stub( $uid, $source );
347 0 0       0         $object = $scope->store_object( $ns->name, $object )
348                         if $scope;
349                 }
350 0         0     $object;
351             }
352              
353             #===================================
354             sub get_doc_source {
355             #===================================
356 0     0 1 0     my ( $self, %args ) = @_;
357              
358 0         0     my $uid = delete $args{uid};
359 0 0       0     my $result = $self->store->get_doc( $uid, %args ) or return;
360 0         0     $uid->update_from_store($result);
361 0         0     return $result->{_source};
362             }
363              
364             #===================================
365             sub new_partial_doc {
366             #===================================
367 0     0 1 0     my ( $self, %args ) = @_;
368                 my $uid = $args{uid}
369 0 0       0         or croak "No UID passed to new_partial_doc()";
370              
371                 my $source = $args{partial_source}
372 0 0       0         or croak "No (partial_source) passed to new_partial_doc()";
373              
374 0         0     my $ns = $self->namespace_for_domain( $uid->index );
375              
376 0         0     my $class = $ns->class_for_type( $uid->type );
377 0         0     return $class->meta->new_stub( $uid, $source );
378             }
379              
380             #===================================
381             sub doc_exists {
382             #===================================
383 0     0 1 0     my ( $self, %args ) = @_;
384                 my $uid = delete $args{uid}
385 0 0       0         or croak "No UID passed to doc_exists()";
386 0         0     return $self->store->doc_exists( $uid, %args );
387             }
388              
389             #===================================
390             sub save_doc {
391             #===================================
392 0     0 1 0     my ( $self, %args ) = @_;
393              
394 0         0     my $doc = delete $args{doc};
395 0         0     my $uid = $doc->uid;
396              
397 0 0       0     croak "Cannot save partial doc type ("
398                     . $uid->type
399                     . ") id ("
400                     . $uid->id . ")"
401                     if $uid->is_partial;
402              
403 0         0     my $data = $self->deflate_object($doc);
404              
405                 my $action
406                     = ( $uid->from_store or $uid->id and defined $args{version} )
407 0 0 0     0         ? 'index_doc'
408                     : 'create_doc';
409              
410 0         0     my $on_unique = delete $args{on_unique};
411 0         0     my $on_conflict = delete $args{on_conflict};
412              
413 0 0       0     my $unique = $self->_update_unique_keys( $doc, $action, $on_unique )
414                     or return;
415              
416 0 0       0     my $result = eval { $self->store->$action( $uid, $data, %args ) } or do {
  0         0  
417 0         0         my $error = $@;
418 0         0         $unique->{rollback}->();
419 0         0         return $self->_handle_error( $error, $on_conflict, $doc );
420                 };
421              
422 0         0     $unique->{commit}->();
423              
424 0         0     $uid->update_from_store($result);
425 0         0     $doc->_set_source($data);
426              
427 0 0       0     my $scope = $self->current_scope
428                     or return $doc;
429              
430 0         0     my $ns = $self->namespace_for_domain( $uid->index );
431 0         0     return $scope->store_object( $ns->name, $doc );
432             }
433              
434             my $noops = {
435                 commit => sub { },
436                 rollback => sub { }
437             };
438              
439             #===================================
440             sub _update_unique_keys {
441             #===================================
442 0     0   0     my ( $self, $doc, $action, $on_unique ) = @_;
443 0         0     my $meta = Class::MOP::class_of($doc);
444 0 0       0     my $uniques = $meta->unique_keys
445                     or return $noops;
446              
447 0         0     my $from_store = $doc->uid->from_store;
448              
449 0 0 0     0     croak "Cannot overwrite a new doc of class ("
450                     . $doc->original_class
451                     . ") because it has unique keys"
452                     if $action eq 'index_doc' and not $from_store;
453              
454 0         0     my ( %old, %new );
455 0         0     for my $key ( keys %$uniques ) {
456 0         0         my $unique_key = $uniques->{$key};
457 0         0         my $new = $doc->$key;
458 23     23   58048         no warnings 'uninitialized';
  23         48  
  23         15787  
459              
460 0 0       0         if ($from_store) {
461 0         0             my $old = $doc->_source->{$key};
462 0 0       0             next if $old eq $new;
463 0 0       0             $old{$unique_key} = $old if length $old;
464                     }
465              
466 0 0       0         $new{$unique_key} = $new if length $new;
467                 }
468              
469 0         0     my $uniq = $self->_unique_index;
470 0         0     my $store = $self->store;
471              
472 0 0       0     if ( my %failed
473                     = $store->create_unique_keys( index => $uniq, keys => \%new ) )
474                 {
475 0 0       0         if ($on_unique) {
476 0         0             $on_unique->( $doc, \%failed );
477 0         0             return;
478                     }
479                     croak "Unique keys already exist: "
480 0         0             . join( ', ', map { $_ . '/' . $failed{$_} } sort keys %failed );
  0         0  
481              
482                 }
483                 return {
484                     commit => sub {
485 0     0   0             $store->delete_unique_keys( index => $uniq, keys => \%old );
486                     },
487                     rollback => sub {
488 0     0   0             $store->delete_unique_keys( index => $uniq, keys => \%new );
489                     },
490 0         0     };
491             }
492              
493             #===================================
494             sub _handle_error {
495             #===================================
496 0     0   0     my ( $self, $error, $on_conflict, $original ) = @_;
497 0   0     0     $error ||= 'Unknown error';
498              
499 0 0 0     0     die $error
500                     unless $on_conflict
501                     and $error->is('Conflict');
502              
503 0         0     my $new;
504 0 0       0     if ( my $current_version = $error->{vars}{current_version} ) {
505                     my $uid = Elastic::Model::UID->new(
506 0         0             %{ $original->uid->read_params },
  0         0  
507                         version => $current_version,
508                         from_store => 1
509                     );
510 0         0         $new = $self->get_doc( uid => $uid );
511              
512                 }
513                 else {
514 0         0         $new = $self->get_doc( uid => $original->uid->clone );
515                 }
516              
517 0         0     $on_conflict->( $original, $new );
518              
519 0         0     return;
520             }
521              
522             #===================================
523             sub delete_doc {
524             #===================================
525 0     0 1 0     my ( $self, %args ) = @_;
526                 my $uid = delete $args{uid}
527 0 0       0         or croak "No UID passed to delete_doc()";
528              
529 0         0     my $unique = $self->_delete_unique_keys($uid);
530 0 0       0     my $result = $self->store->delete_doc( $uid, %args )
531                     or return;
532 0         0     $unique->{commit}->();
533              
534 0         0     $uid->update_from_store($result);
535              
536 0 0       0     if ( my $scope = $self->current_scope ) {
537 0         0         my $ns = $self->namespace_for_domain( $uid->index );
538 0         0         $scope->delete_object( $ns->name, $uid );
539                 }
540 0         0     return $uid;
541             }
542              
543             #===================================
544             sub _delete_unique_keys {
545             #===================================
546 0     0   0     my ( $self, $uid ) = @_;
547              
548 0 0       0     my $doc = $self->get_doc( uid => $uid, ignore => 404 )
549                     or return $noops;
550              
551 0         0     my $meta = Class::MOP::class_of($doc);
552 0 0       0     my $uniques = $meta->unique_keys or return $noops;
553              
554 0         0     my %old;
555 0         0     for my $key ( keys %$uniques ) {
556 23     23   131         no warnings 'uninitialized';
  23         45  
  23         18335  
557 0         0         my $old = $doc->_source->{$key};
558 0 0       0         $old{ $uniques->{$key} } = $old if length $old;
559                 }
560 0         0     my $uniq = $self->_unique_index;
561 0         0     my $store = $self->store;
562                 return {
563                     commit => sub {
564 0     0   0             $store->delete_unique_keys(
565                             index => $uniq,
566                             keys => \%old
567                         );
568                     },
569 0         0     };
570             }
571              
572             #===================================
573 0     0 1 0 sub bulk { shift->bulk_class->new(@_) }
574             #===================================
575              
576             #===================================
577 0     0 1 0 sub search { shift->store->search(@_) }
578             #===================================
579              
580             #===================================
581             sub deflate_object {
582             #===================================
583 0     0 1 0     my $self = shift;
584 0 0       0     my $object = shift or die "No object passed to deflate()";
585 0 0       0     my $class = blessed $object
586                     or die "deflate() can only deflate objects";
587 0         0     $self->deflator_for_class($class)->($object);
588             }
589              
590             #===================================
591             sub deflator_for_class {
592             #===================================
593 0     0 1 0     my $self = shift;
594 0         0     my $class = shift;
595 0   0     0     $class = $self->class_for($class) || $class;
596 0   0     0     return $self->deflators->{$class} ||= do {
597 0 0       0         die "Class $class is not an Elastic class."
598                         unless does_role( $class, 'Elastic::Model::Role::Doc' );
599 0         0         $self->typemap->class_deflator($class);
600                 };
601             }
602              
603             #===================================
604             sub inflate_object {
605             #===================================
606 0     0 1 0     my $self = shift;
607 0 0       0     my $object = shift or die "No object passed to inflate()";
608 0 0       0     my $hash = shift or die "No hash pashed to inflate()";
609 0         0     $self->inflator_for_class( blessed $object)->( $object, $hash );
610             }
611              
612             #===================================
613             sub inflator_for_class {
614             #===================================
615 0     0 1 0     my $self = shift;
616 0         0     my $class = shift;
617 0   0     0     $class = $self->class_for($class) || $class;
618 0   0     0     return $self->inflators->{$class} ||= do {
619 0 0       0         die "Class $class is not an Elastic class."
620                         unless does_role( $class, 'Elastic::Model::Role::Doc' );
621 0         0         $self->typemap->class_inflator($class);
622                 };
623             }
624              
625             #===================================
626             sub map_class {
627             #===================================
628 9     9 1 14     my $self = shift;
629 9         17     my $class = shift;
630 9   33     424     $class = $self->class_for($class) || $class;
631              
632 9 50       44     die "Class $class is not an Elastic class."
633                     unless does_role( $class, 'Elastic::Model::Role::Doc' );
634              
635 9         3102     my $meta = $class->original_class->meta;
636              
637                 my %mapping = (
638 9         153         %{ $meta->mapping },
  9         381  
639                     $self->typemap->class_mapping($class),
640                     dynamic => 'strict',
641                     _timestamp => { enabled => 1, path => 'timestamp' },
642                     numeric_detection => 1,
643                 );
644 9         25     delete $mapping{type};
645 9         65     return \%mapping;
646             }
647              
648             #===================================
649 0     0 0   sub json {$JSON}
650             #===================================
651              
652             1;
653              
654             =pod
655            
656             =encoding UTF-8
657            
658             =head1 NAME
659            
660             Elastic::Model::Role::Model - The role applied to your Model
661            
662             =head1 VERSION
663            
664             version 0.52
665            
666             =head1 SYNOPSIS
667            
668             use MyApp;
669            
670             my $es = Search::Elasticsearch->new(
671             client => '1_0::Direct',
672             nodes => 'es.domain.com:9200'
673             );
674             my $model = MyApp->new( es => $es );
675            
676             my $namespace = $model->namespace('myapp');
677             my $domain = $model->domain('my_domain');
678             my $view = $model->view();
679            
680             my $scope = $model->new_scope;
681            
682             =head1 DESCRIPTION
683            
684             A "Model" is the Boss Object, which ties an instance of your application to
685             a particular Elasticsearch cluster. You can have multiple instances of your
686             Model class which connect to different clusters.
687            
688             C<Elastic::Model::Role::Model> is applied to your Model class when you
689             include the line:
690            
691             use Elastic::Model;
692            
693             See L<Elastic::Model> for more about how to setup your Model class.
694            
695             =head1 COMMONLY USED METHODS
696            
697             =head2 new()
698            
699             Usually, the only parameter that you need to pass to C<new()> is C<es>,
700             which contains your L<Search::Elasticsearch> connection.
701            
702             $es = Search::Elasticsearch->new( nodes => 'es1.domain.com:9200' );
703             $model = MyApp->new( es => $es );
704            
705             If the C<es> parameter is omitted, then it will default to a L<Search::Elasticsearch>
706             connection to C<localhost:9200>.
707            
708             $model = MyApp->new(); # localhost:9200
709            
710             =head2 namespace()
711            
712             $namespace = $model->namespace($name);
713            
714             Returns the L<Elastic::Model::Namespace> instance corresponding to
715             C<$name>. The namespace must have been configured via
716             L<Elastic::Model/has_namespace>.
717            
718             Use a C<$namespace> to create, delete and update
719             L<indices|Elastic::Manual::Terminology/Index> and
720             L<index aliases|Elastic::Manual::Terminology/Alias>.
721            
722             =head2 domain()
723            
724             $domain = $model->domain($name);
725            
726             Returns an L<Elastic::Model::Domain> instance where C<$name> is the name
727             of an L<index|Elastic::Manual::Terminology/Index> or
728             L<index alias|Elastic::Manual::Terminology/Alias> (which points at a single
729             index) and is known to one of the L</namespaces>.
730            
731             Use a C<$domain> to create, retrieve, update or delete individual
732             objects/documents.
733            
734             =head2 view()
735            
736             $view = $model->view(%args);
737            
738             Creates a new L<Elastic::Model::View> instance. Any args are passed on to
739             L<Elastic::Model::View/"new()">.
740            
741             Use a C<$view> to query your documents. Views can be multi-domain and
742             multi-type.
743            
744             =head2 new_scope()
745            
746             $scope = $model->new_scope();
747            
748             Creates a new L<Elastic::Model::Scope> instance (in-memory cache). If there is
749             an existing scope, then the new scope inherits from the existing scope.
750            
751             $scope = $model->new_scope(); # scope_1
752             $scope = $model->new_scope(); # scope_2, inherits from scope_1
753             undef $scope; # scope_2 and scope_1 are destroyed
754            
755             Scopes are optional unless you have attributes which are weakened.
756            
757             See L<Elastic::Model::Scoping> and L<Elastic::Model::Scope> to read more about
758             how scopes work.
759            
760             =head1 OTHER METHODS AND ATTRIBUTES
761            
762             These methods and attributes, while public, are usually used only by internal
763             modules. They are documented here for completeness.
764            
765             =head2 CRUD
766            
767             =head3 get_doc()
768            
769             Normally, you want to use L<Elastic::Model::Domain/"get()"> rather than this
770             method.
771            
772             $doc = $model->get_doc(uid => $uid);
773             $doc = $model->get_doc(uid => $uid, ignore => 404, ...);
774            
775             C<get_doc()> tries to retrieve the object corresponding to the
776             L<$uid|Elastic::Model::UID>, first from the L</current_scope()> (if there is one)
777             or from any of its parents. Failing that, it tries to retrieve the doc
778             from the L</store>. If it finds the doc, then
779             it stores it in the current scope (again, if there is one), otherwise it
780             throws an error.
781            
782             C<get_doc()> also accepts an optional C<$source> parameter which is
783             used internally for inflating search results.
784             See L<Elastic::Model::Scope> for a more detailed explanation.
785            
786             Any other args are passed on to L<Elastic::Model::Store/get_doc()>.
787            
788             =head3 get_doc_source()
789            
790             $doc = $model->get_doc_source(uid => $uid);
791             $doc = $model->get_doc_source(uid => $uid, ignore => 404, ...);
792            
793             Calls L<Elastic::Model::Store/"get_doc()"> and returns the raw source hashref
794             as stored in Elasticsearch for the doc with the corresponding
795             L<$uid|Elastic::Model::UID>. Throws an error if it doesn't exist.
796            
797             Any other args are passed on to L<Elastic::Model::Store/get_doc()>.
798            
799             =head3 doc_exists()
800            
801             $bool = $model->doc_exists( uid => $uid, %args );
802            
803             Calls L<Elastic::Model::Role::Store/doc_exists()> to check whether the doc
804             exists.
805            
806             =head3 save_doc()
807            
808             Normally, you want to use L<Elastic::Model::Role::Doc/"save()"> rather than this
809             method.
810            
811             $doc = $model->save_doc(doc => $doc, %args);
812            
813             Saves C<$doc> to Elasticsearch by calling
814             L<Elastic::Model::Store/"index_doc()"> (if the C<$doc> was originally loaded
815             from Elasticsearch), or L<Elastic::Model::Store/"create_doc()">, which
816             will throw an error if a doc with the same C<index|type|id> already
817             exists.
818            
819             Any C<%args> are passed on to L<index_doc()|Elastic::Model::Store/"index_doc()"> or
820             L<create_doc()|Elastic::Model::Store/"create_doc()">.
821            
822             If there is a L</current_scope()> then the object is also stored there.
823            
824             Also see the L<Elastic::Model::Role::Doc/on_conflict> and
825             L<Elastic::Model::Role::Doc/on_unique> parameters.
826            
827             =head3 delete_doc()
828            
829             $uid = $model->delete_doc(uid => $uid, ignore => 404, ...)
830            
831             Calls L<Elastic::Model::Store/delete_doc()> and returns the updated
832             L<Elastic::Model::UID> object. Throws an error if it doesn't exist.
833             If there is a L</current_scope()> then an L<Elastic::Model::Deleted> object
834             is stored there.
835            
836             =head3 search()
837            
838             Normally, you want to use L<Elastic::Model::View> rather than this
839             method.
840            
841             $results = $model->search(%args)
842            
843             Passes C<%args> through to L<Elastic::Model::Store/"search()">
844            
845             =head3 new_partial_doc()
846            
847             part_doc = $model->new_partial_doc(
848             uid => $uid,
849             partial_source => \%source
850             );
851            
852             Creates an instance of a partial doc (ie an object which contains only some of
853             the values stored in Elasticsearch). These partial docs are useful when
854             your objects are large, and you need to display search results which
855             require only a few attributes, instead of the whole object.
856            
857             Attempting to save a partial doc will cause an error to be thrown.
858            
859             You shouldn't need to call this method yourself.
860            
861             =head3 bulk()
862            
863             Returns a new instance of L<Elastic::Model::Bulk> for fast indexing
864             of multiple docs in batches.
865            
866             $bulk = $model->bulk(
867             size => 1000,
868             on_conflict => sub {...},
869             on_error => sub {...},
870             on_success => sub {...}
871             );
872            
873             =head2 Miscellaneous
874            
875             =head3 namespaces
876            
877             \%namespaces = $model->namespaces;
878            
879             A hashref whose keys are the namespace names, and whose values are the
880             corresponding L<Elastic::Model::Namespace> instances.
881            
882             =head3 namespace_for_domain()
883            
884             $namespace = $model->namespace_for_domain($domain_name)
885            
886             Returns the L<Elastic::Model::Namespace> object which corresponds to the
887             C<$domain_name>. If the index (or alias) name is not yet known to the
888             C<$model>, it will update the known domain list from the namespace objects.
889            
890             =head3 all_live_indices()
891            
892             @indices = $model->all_live_indices();
893            
894             Queries Elasticsearch to find all existing indices related to all namespaces
895             known to the model.
896            
897             =head3 es
898            
899             $es = $model->es
900            
901             Returns the L<Search::Elasticsearch> instance that was passed to L</"new()">.
902            
903             =head3 store
904            
905             $store = $model->store
906            
907             Returns the L<Elastic::Model::Store> instance.
908            
909             =head2 Deflation, Inflation And Mapping
910            
911             =head3 typemap
912            
913             $typemap_class = $model->typemap;
914            
915             Elastic::Model uses L<Elastic::Model::TypeMap::Default> (after
916             L<wrapping|/wrap_class()> it) to figure out how
917             to deflate and inflate your objects, and how to configure (map) them in
918             Elasticsearch.
919            
920             You can specify your own type-map class in your model configuration with
921             L<has_typemap|Elastic::Model/Custom TypeMap>. See
922             L<Elastic::Model::TypeMap::Base> for instructions on how to define
923             your own type-map classes.
924            
925             =head3 deflator_for_class()
926            
927             $deflator = $model->deflator_for_class($class);
928            
929             Returns a code-ref that knows how to deflate a class which does
930             L<Elastic::Model::Role::Doc>, and caches the deflator in L</"deflators">.
931            
932             =head3 deflate_object()
933            
934             $hash = $model->deflate_object($object);
935            
936             Uses the deflator returned by L</"deflator_for_class()"> to deflate
937             an object which does L<Elastic::Model::Role::Doc> into a hash ref
938             suitable for conversion to JSON.
939            
940             =head3 deflators
941            
942             $deflators = $model->deflators
943            
944             A hashref which caches all of the deflators which have been generated by
945             L</"deflator_for_class()">.
946            
947             =head3 inflator_for_class()
948            
949             $inflator = $model->inflator_for_class($class);
950            
951             Returns a code-ref that knows how to inflate a plain hashref into the correct
952             attribute values for a class which does L<Elastic::Model::Role::Doc>,
953             and caches the inflator in L</"inflators">.
954            
955             =head3 inflate_object()
956            
957             $object = $model->inflate_object($object,$hash);
958            
959             Uses the inflator returned by L</"inflator_for_class()"> to inflate
960             the attribute values of C<$object> from the value stored in C<$hash>.
961            
962             =head3 inflators
963            
964             $inflators = $model->inflators
965            
966             A hashref which caches all of the inflators which have been generated by
967             L</"inflator_for_class()">.
968            
969             =head3 map_class()
970            
971             $mapping = $model->map_class($class);
972            
973             Returns the type mapping / schema for a class which does
974             L<Elastic::Model::Role::Doc>, suitable for passing to Elasticsearch.
975            
976             =head2 Scoping
977            
978             Also see L</"new_scope()"> and L<Elastic::Model::Scope>.
979            
980             =head3 current_scope()
981            
982             $scope = $model->current_scope($scope);
983            
984             Read/write accessor for the current scope. Throws an exception if no scope
985             is currently set.
986            
987             =head3 detach_scope()
988            
989             $model->detach_scope($scope);
990            
991             Removes the passed in C<$scope> if it is the current scope. Replaces
992             the current scope with its parent scope, if there is one. L</"detach_scope()">
993             is called automatically when a scope goes out of scope:
994            
995             {
996             my $scope = $model->new_scope;
997             # do work
998             }
999             # current scope is removed
1000            
1001             =head3 has_current_scope()
1002            
1003             $bool = $model->has_current_scope
1004            
1005             Returns a true or false value signalling whether a L</"current_scope()">
1006             exists.
1007            
1008             =head3 clear_current_scope()
1009            
1010             $model->clear_current_scope
1011            
1012             Clears the L</"current_scope()">
1013            
1014             =head2 Core classes
1015            
1016             The following core classes are used internally by Elasticsearch, after
1017             being wrapped by L</wrap_class()>, which pins the new anonymous class
1018             to the current C<$model> instance. An instance of the wrapped class
1019             can be created with, eg:
1020            
1021             $domain = $model->domain_class->new(%args);
1022            
1023             If you would like to override any of the core classes, then you can specify
1024             them in your model setup using
1025             L<override_classes|Elastic::Model/Overriding Core Classes>.
1026            
1027             =head3 Default core classes:
1028            
1029             =over
1030            
1031             =item *
1032            
1033             C<domain_class> C<--------------> L<Elastic::Model::Domain>
1034            
1035             =item *
1036            
1037             C<store_class> C<---------------> L<Elastic::Model::Store>
1038            
1039             =item *
1040            
1041             C<view_class> C<----------------> L<Elastic::Model::View>
1042            
1043             =item *
1044            
1045             C<scope_class> C<---------------> L<Elastic::Model::Scope>
1046            
1047             =item *
1048            
1049             C<results_class> C<-------------> L<Elastic::Model::Results>
1050            
1051             =item *
1052            
1053             C<cached_results_class> C<------> L<Elastic::Model::Results::Cached>
1054            
1055             =item *
1056            
1057             C<scrolled_results_class> C<----> L<Elastic::Model::Results::Scrolled>
1058            
1059             =item *
1060            
1061             C<result_class> C<--------------> L<Elastic::Model::Result>
1062            
1063             =back
1064            
1065             =head3 wrap_class()
1066            
1067             $wrapped_class = $model->wrap_class($class)
1068            
1069             Wraps a class in an anonymous class and adds two methods: C<model()> (which
1070             returns the current C<$model> instance, and C<original_class())>, which
1071             returns the name of the wrapped class:
1072            
1073             $model = $wrapped_class->model
1074             $class = $wrapped_class->original_class;
1075            
1076             =head3 wrap_doc_class()
1077            
1078             Like L</"wrap_class()">, but specifically for classes which do
1079             L<Elastic::Model::Role::Doc>.
1080            
1081             =head3 doc_class_wrappers
1082            
1083             $wrapped_classes = $model->doc_class_wrappers
1084            
1085             A hashref of all wrapped doc classes (ie those classes which do
1086             L<Elastic::Model::Role::Doc>). The keys are the original class names, and
1087             the values are the wrapped class names.
1088            
1089             =head3 class_for()
1090            
1091             $wrapped_class = $model->class_for($class);
1092            
1093             Returns the name of the wrapped class which corresponds to C<$class>.
1094            
1095             =head3 knows_class()
1096            
1097             $bool = $model->knows_class($class);
1098            
1099             Returns a true or false value to signal whether doc C<$class> has been wrapped.
1100            
1101             =head1 AUTHOR
1102            
1103             Clinton Gormley <drtech@cpan.org>
1104            
1105             =head1 COPYRIGHT AND LICENSE
1106            
1107             This software is copyright (c) 2015 by Clinton Gormley.
1108            
1109             This is free software; you can redistribute it and/or modify it under
1110             the same terms as the Perl 5 programming language system itself.
1111            
1112             =cut
1113              
1114             __END__
1115            
1116             # ABSTRACT: The role applied to your Model
1117            
1118