File Coverage

lib/ElasticSearchX/Model/Generator.pm
Criterion Covered Total %
statement 14 21 66.6
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 20 27 74.0


line stmt bran cond sub pod time code
1 2     2   25217 use strict;
  2         6  
  2         80  
2 2     2   12 use warnings;
  2         3  
  2         111  
3              
4             package ElasticSearchX::Model::Generator;
5             BEGIN {
6 2     2   69 $ElasticSearchX::Model::Generator::AUTHORITY = 'cpan:KENTNL';
7             }
8             {
9             $ElasticSearchX::Model::Generator::VERSION = '0.1.8';
10             }
11              
12             # ABSTRACT: Create a suite of ESX::Model classes from an existing mapping.
13              
14 2     2   1730 use Moo;
  2         78406  
  2         14  
15              
16              
17              
18             use Sub::Exporter -setup => {
19             exports => [
20             generate_model => sub {
21 0         0 my $class = __PACKAGE__;
22 0         0 my $call = $class->can('new');
23             return sub {
24 0         0 unshift @_, $class;
25 0         0 goto $call;
26 0         0 };
27             },
28 2         31 ]
29 2     2   7255 };
  2         33880  
30 2     2   3165 use MooseX::Has::Sugar qw( rw ro required );
  0            
  0            
31             use Sub::Quote qw( quote_sub );
32              
33              
34             has mapping_url => rw, required;
35             has base_dir => rw, required;
36              
37              
38             has generator_base_class => rw, default => quote_sub(q{ 'ElasticSearchX::Model::Generator' });
39             has generated_base_class => rw, default => quote_sub(q{ 'MyModel' });
40              
41              
42             has document_generator_class => is => lazy =>,;
43             has attribute_generator_class => is => lazy =>,;
44             has typename_translator_class => is => lazy =>,;
45              
46              
47             has document_generator => is => lazy =>,;
48             has attribute_generator => is => lazy =>,;
49             has typename_translator => is => lazy =>,;
50              
51              
52             has _mapping_content => is => lazy =>,;
53             has _ua => is => lazy =>,;
54             has _mapping_data => is => lazy =>,;
55              
56              
57             sub _build__ua {
58             require HTTP::Tiny;
59             return HTTP::Tiny->new();
60             }
61              
62              
63             sub _build_document_generator_class {
64             my $self = shift;
65             return $self->generator_base_class . '::DocumentGenerator';
66             }
67              
68              
69             sub _build_document_generator {
70             my $self = shift;
71             require Module::Runtime;
72             return Module::Runtime::use_module( $self->document_generator_class )->new( generator_base => $self, );
73             }
74              
75              
76             sub _build_attribute_generator_class {
77             my $self = shift;
78             return $self->generator_base_class . '::AttributeGenerator';
79             }
80              
81              
82             sub _build_attribute_generator {
83             my $self = shift;
84             require Module::Runtime;
85             return Module::Runtime::use_module( $self->attribute_generator_class )->new( generator_base => $self );
86             }
87              
88              
89             sub _build_typename_translator_class {
90             my $self = shift;
91             return $self->generator_base_class . '::TypenameTranslator';
92             }
93              
94              
95             sub _build_typename_translator {
96             my $self = shift;
97             require Module::Runtime;
98             return Module::Runtime::use_module( $self->typename_translator_class )->new( generator_base => $self );
99             }
100              
101              
102             sub _build__mapping_content {
103             my $self = shift;
104             my $response = $self->_ua->get( $self->mapping_url );
105             if ( not $response->{success} ) {
106             require Carp;
107             Carp::confess( sprintf qq[Failed to fetch mapping:\n\tstatus=%s\n\treason=%s\n], $response->{status}, $response->{reason} );
108             }
109             if ( exists $response->{headers}->{'content-length'}
110             and length $response->{content} != $response->{headers}->{'content-length'} )
111             {
112             require Carp;
113             Carp::confess(
114             sprintf qq[Content length did not match expected length, _mapping failed to fetch completely.\n\tgot=%s\n\texpected%s\n],
115             length $response->{content},
116             $response->{headers}->{'Content-Length'}
117             );
118             }
119             if ( not exists $response->{headers}->{'content-length'} ) {
120             if ( not exists $response->{headers}->{'transfer-encoding'} or $response->{headers}->{'transfer-encoding'} ne 'chunked' ) {
121             require Carp;
122             Carp::carp(q[No content length and no transfer-encoding=chunked, data could be broken]);
123             }
124             }
125             return $response->{content};
126             }
127              
128              
129             sub _build__mapping_data {
130             my $self = shift;
131             my $content = $self->_mapping_content;
132             require JSON;
133             return JSON->new()->utf8(1)->decode($content);
134             }
135              
136              
137             ## no critic ( RequireArgUnpacking ProhibitBuiltinHomonyms )
138             sub index_names {
139             return keys %{ $_[0]->_mapping_data };
140             }
141              
142              
143             sub index {
144             if ( $_[1] eq q{} ) {
145             return $_[0]->_mapping_data;
146             }
147             return $_[0]->_mapping_data->{ $_[1] };
148             }
149              
150              
151             sub type_names {
152             my ( $self, $index ) = @_;
153             return keys %{ $self->index($index) };
154             }
155              
156              
157             sub type {
158             my ( $self, $index, $type ) = @_;
159             return $self->index($index)->{$type};
160             }
161              
162              
163             sub property_names {
164             my ( $self, $index, $type ) = @_;
165             return keys %{ $self->properties( $index, $type ) };
166             }
167              
168              
169             sub properties {
170             my ( $self, $index, $type ) = @_;
171             return $self->type( $index, $type )->{properties};
172             }
173              
174              
175             sub property {
176             my ( $self, $index, $type, $property ) = @_;
177             return $self->properties( $index, $type )->{$property};
178             }
179              
180              
181             sub documents {
182             my ( $self, @indices ) = @_;
183             if ( not @indices ) {
184             @indices = $self->index_names;
185             }
186             my @documents;
187             for my $index (@indices) {
188             for my $typename ( $self->type_names($index) ) {
189             push @documents,
190             $self->document_generator->generate(
191             index => $index,
192             typename => $typename,
193             typedata => $self->type( $index, $typename ),
194             );
195             }
196             }
197             return @documents;
198             }
199              
200             no Moo;
201              
202             1;
203              
204             __END__
205              
206             =pod
207              
208             =encoding UTF-8
209              
210             =head1 NAME
211              
212             ElasticSearchX::Model::Generator - Create a suite of ESX::Model classes from an existing mapping.
213              
214             =head1 VERSION
215              
216             version 0.1.8
217              
218             =head1 SYNOPSIS
219              
220             use ElasticSearchX::Model::Generator qw( generate_model );
221              
222             my $instance = generate_model(
223             mapping_url => 'http://someserver:port/path/_mapping',
224             generated_base_class => 'MyModel',
225             base_dir => "../path/to/export/dir/"
226             );
227              
228             for my $document ( $instance->documents ) {
229             # Write the document to disk
230             $document->write();
231             # Alternatively, load the generated document into memory avoiding writing to disk
232             $document->evaluate();
233             }
234              
235             =head1 DESCRIPTION
236              
237             B<ALPHA Code>: This class at present only contains code sufficient for very simple package generation for use in creating a model from an existing mapping for the purposes of search.
238              
239             =head1 EXPORTS
240              
241             =head2 generate_model
242              
243             this is just a sugar syntax for ESX:M:G->new() you can elect to import to make your code slightly shorter.
244              
245             =head1 METHODS
246              
247             =head2 index_names
248              
249             @names = $esmg->index_names
250              
251             returns the names of all indexes specified in the C<_mapping>
252              
253             =head2 index
254              
255             $data = $esmg->index('') # If indexes are not in the data set
256             $data = $esmg->index('cpan_v1') # if indexes are in the data set
257              
258             Returns the data set nested under the specified index.
259              
260             =head2 type_names
261              
262             @names = $esmg->type_names( $index )
263             @names = $esmg->type_names('') # return all types defined in an index-free dataset.
264             @names = $esmg->type_names('cpan_v1') # return all types in the cpan_v1 index.
265              
266             =head2 type
267              
268             $data = $esmg->type( $index, $type )
269             $data = $esmg->type( '', 'File' ) # get type 'File' from an index-free dataset
270             $data = $esmg->type( 'cpan_v1', 'File' ) # get type 'File' from the cpan_v1 index
271              
272             =head2 property_names
273              
274             @names = $esmg->property_names( $index, $type )
275              
276             =head2 properties
277              
278             $properties = $esmg->properties( $index, $type )
279              
280             =head2 property
281              
282             $property = $esmg->property( $index, $type, $propertyname )
283              
284             =head2 documents
285              
286             @documents = $esmg->documents(); # all documents for all indexes
287             @documents = $esmg->documents('cpan_v1'); # all documents for cpan_v1
288             @documents = $esmg->documents(''); # all documents for an index-free dataset.
289              
290             =head1 ATTRIBUTES
291              
292             =head2 mapping_url
293              
294             rw, required
295              
296             =head2 base_dir
297              
298             rw, required
299              
300             =head2 generator_base_class
301              
302             rw, default: ElasticSearchX::Model::Generator
303              
304             =head2 generated_base_class
305              
306             rw, default: MyModel
307              
308             =head2 document_generator_class
309              
310             lazy
311              
312             =head2 attribute_generator_class
313              
314             lazy
315              
316             =head2 typename_translator_class
317              
318             lazy
319              
320             =head2 document_generator
321              
322             lazy
323              
324             =head2 attribute_generator
325              
326             lazy
327              
328             =head2 typename_translator
329              
330             lazy
331              
332             =head1 PRIVATE ATTRIBUTES
333              
334             =head2 _mapping_content
335              
336             lazy
337              
338             =head2 _ua
339              
340             lazy
341              
342             =head2 _mapping_data
343              
344             lazy
345              
346             =head1 PRIVATE METHODS
347              
348             =head2 _build__ua
349              
350             returns an C<HTTP::Tiny> instance.
351              
352             =head2 _build_document_generator_class
353              
354             generator_base_class + '::DocumentGenerator'
355              
356             =head2 _build_document_generator
357              
358             returns an instance of C<$document_generator_class>
359              
360             =head2 _build_attribute_generator_class
361              
362             generator_base_class + '::AttributeGenerator'
363              
364             =head2 _build_attribute_generator
365              
366             returns an instance of C<$attribute_generator_class>
367              
368             =head2 _build_typename_translator_class
369              
370             generator_base_class + '::TypenameTranslator'
371              
372             =head2 _build_typename_translator
373              
374             returns an instance of C<$typename_translator_class>
375              
376             =head2 _build__mapping_content
377              
378             returns the content of the URL at C<mapping_url>
379              
380             =head2 _build__mapping_data
381              
382             returns the decoded data from C<JSON> stored in C<_mapping_content>
383              
384             =head1 AUTHOR
385              
386             Kent Fredric <kentfredric@gmail.com>
387              
388             =head1 COPYRIGHT AND LICENSE
389              
390             This software is copyright (c) 2013 by Kent Fredric <kentfredric@gmail.com>.
391              
392             This is free software; you can redistribute it and/or modify it under
393             the same terms as the Perl 5 programming language system itself.
394              
395             =cut