File Coverage

blib/lib/Document/Transform/Backend/MongoDB.pm
Criterion Covered Total %
statement 28 63 44.4
branch 0 16 0.0
condition 0 6 0.0
subroutine 10 24 41.6
pod 10 10 100.0
total 48 119 40.3


line stmt bran cond sub pod time code
1             package Document::Transform::Backend::MongoDB;
2             BEGIN {
3 2     2   5113 $Document::Transform::Backend::MongoDB::VERSION = '1.110530';
4             }
5              
6             #ABSTRACT: Talk to a MongoDB via a simple interface
7              
8 2     2   41 use Moose;
  2         4  
  2         19  
9 2     2   14216 use namespace::autoclean;
  2         4  
  2         20  
10              
11 2     2   1585 use MongoDB;
  2         1775779  
  2         57  
12 2     2   1891 use MongoDBx::AutoDeref;
  2         832733  
  2         16  
13 2     2   110719 use Throwable::Error;
  2         5  
  2         50  
14 2     2   26 use MooseX::Params::Validate;
  2         4  
  2         25  
15 2     2   1085 use MooseX::Types::Moose(':all');
  2         5  
  2         22  
16 2     2   18271 use MooseX::Types::Structured(':all');
  2         5  
  2         20  
17 2     2   1188 use Moose::Util::TypeConstraints();
  2         4  
  2         3228  
18              
19              
20              
21             has $_.'_constraint' =>
22             (
23             is => 'ro',
24             isa => 'Moose::Meta::TypeConstraint',
25             builder => '_build_'.$_.'_constraint',
26             lazy => 1,
27             ) for qw/document transform/;
28              
29             sub _build_document_constraint
30             {
31 0     0     my ($self) = @_;
32              
33             return Moose::Util::TypeConstraints::subtype
34             ({
35             as => HashRef,
36             where => sub
37             {
38 0 0   0     exists($_->{$self->document_id_key}) &&
39             not exists($_->{$self->reference_id_key})
40             },
41 0           });
42             }
43              
44             sub _build_transform_constraint
45             {
46 0     0     my ($self) = @_;
47              
48             return Moose::Util::TypeConstraints::subtype
49             ({
50             as => HashRef,
51             where => sub
52             {
53 0 0 0 0     exists($_->{$self->transform_id_key}) &&
      0        
54             exists($_->{$self->reference_id_key}) &&
55             exists($_->{operations}) &&
56             (ArrayRef[Dict[path => Str, value => Defined]])->check($_->{operations});
57             },
58 0           });
59             }
60              
61              
62             has host =>
63             (
64             is => 'ro',
65             isa => Str,
66             predicate => 'has_host',
67             );
68              
69              
70             has connection =>
71             (
72             is => 'ro',
73             isa => 'MongoDB::Connection',
74             default => sub
75             {
76             my $self = shift;
77             unless($self->has_host)
78             {
79             Throwable::Error->throw
80             ({
81             message => 'host must be provided to use the default ' .
82             'connection constructor'
83             });
84             }
85             return MongoDB::Connection->new(host => $self->host)
86             },
87             lazy => 1,
88             );
89              
90              
91             has database_name =>
92             (
93             is => 'ro',
94             isa => Str,
95             predicate => 'has_database_name',
96             );
97              
98              
99             has database =>
100             (
101             is => 'ro',
102             isa => 'MongoDB::Database',
103             default => sub
104             {
105             my $self = shift;
106             unless($self->has_database_name)
107             {
108             Throwable::Error->throw
109             ({
110             message => 'database must be provided to use the default ' .
111             'db constructor'
112             });
113             }
114             return $self->connection->get_database($self->database_name);
115             },
116             lazy => 1,
117             );
118              
119              
120             has document_collection =>
121             (
122             is => 'ro',
123             isa => Str,
124             predicate => 'has_document_collection',
125             );
126              
127              
128             has documents =>
129             (
130             is => 'ro',
131             isa => 'MongoDB::Collection',
132             default => sub
133             {
134             my $self = shift;
135             unless($self->has_document_collection)
136             {
137             Throwable::Error->throw
138             ({
139             message => 'document_collection must be provided to use the ' .
140             'default docs constructor'
141             });
142             }
143              
144             return $self->database->get_collection($self->document_collection);
145             },
146             lazy => 1,
147             );
148              
149              
150             has transform_collection =>
151             (
152             is => 'ro',
153             isa => Str,
154             predicate => 'has_transform_collection',
155             );
156              
157              
158             has transforms =>
159             (
160             is => 'ro',
161             isa => 'MongoDB::Collection',
162             default => sub
163             {
164             my $self = shift;
165             unless($self->has_transform_collection)
166             {
167             Throwable::Error->throw
168             ({
169             message => 'transform_collection must be provided to use the ' .
170             'default transforms constructor'
171             });
172             }
173              
174             return $self->database->get_collection($self->transform_collection);
175             },
176             lazy => 1,
177             );
178              
179              
180             sub fetch_document_from_key
181             {
182 0     0 1   my ($self, $key) = pos_validated_list
183             (
184             \@_,
185             {isa => __PACKAGE__},
186             {isa => Defined},
187             );
188              
189 0           return $self->documents->find_one({$self->document_id_key => $key});
190             }
191              
192              
193             sub fetch_transform_from_key
194             {
195 0     0 1   my ($self, $key) = pos_validated_list
196             (
197             \@_,
198             {isa => __PACKAGE__},
199             {isa => Defined},
200             );
201              
202 0           my $val = $self->transforms->find_one({$self->transform_id_key => $key});
203 0           return $val;
204             }
205              
206              
207             sub fetch_document_from_transform
208             {
209 0     0 1   my $self = shift;
210 0           my ($transform) = pos_validated_list
211             (
212             \@_,
213             {isa => $self->transform_constraint},
214             );
215 0           return $transform->{$self->reference_id_key}->fetch();
216             }
217              
218              
219              
220 0     0 1   sub fetch_transform_from_document { }
221              
222              
223             sub store_document
224             {
225 0     0 1   my $self = shift;
226 0           my ($item, $safe) = pos_validated_list
227             (
228             \@_,
229             {isa => $self->document_constraint},
230             {isa => Bool, optional => 1}
231             );
232              
233 0 0         unless(exists($item->{_id}))
234             {
235 0 0         $self->documents->insert($item, ($safe ? {safe => 1} : ()) );
236             }
237              
238             $self->documents->update(
239 0 0         {$self->document_id_key => $item->{$self->document_id_key}},
240             $item, ($safe ? {safe => 1} : ())
241             );
242             }
243              
244              
245             sub store_transform
246             {
247 0     0 1   my $self = shift;
248 0           my ($item, $safe) = pos_validated_list
249             (
250             \@_,
251             {isa => $self->transform_constraint},
252             {isa => Bool, optional => 1}
253             );
254              
255 0 0         unless(exists($item->{_id}))
256             {
257 0 0         $self->transforms->insert($item, ($safe ? {safe => 1} : ()) );
258             }
259              
260             $self->transforms->update(
261 0 0         {$self->transform_id_key => $item->{$self->transform_id_key}},
262             $item, ($safe ? {safe => 1} : ())
263             );
264             }
265              
266              
267             sub has_document
268             {
269 0     0 1   my ($self, $key) = pos_validated_list
270             (
271             \@_,
272             {isa => __PACKAGE__},
273             {isa => Defined},
274             );
275              
276 0           return defined($self->documents->find_one({$self->document_id_key => $key}));
277             }
278              
279              
280             sub has_transform
281             {
282 0     0 1   my ($self, $key) = pos_validated_list
283             (
284             \@_,
285             {isa => __PACKAGE__},
286             {isa => Defined},
287             );
288              
289 0           return defined($self->transforms->find_one({$self->transform_id_key => $key}));
290             }
291              
292              
293             sub is_same_document
294             {
295 0     0 1   my $self = shift;
296 0           my ($doc1, $doc2) = validated_list
297             (
298             \@_,
299             {isa => $self->document_constraint},
300             {isa => $self->document_constraint},
301             );
302              
303 0           return $doc1->{$self->document_id_key} eq $doc2->{$self->document_id_key};
304             }
305              
306              
307             sub is_same_transform
308             {
309 0     0 1   my $self = shift;
310 0           my ($tra1, $tra2) = pos_validated_list
311             (
312             \@_,
313             {isa => $self->transform_constraint},
314             {isa => $self->transform_constraint},
315             );
316              
317 0           return $tra1->{$self->transform_id_key} eq $tra2->{$self->transform_id_key};
318             }
319              
320             with 'Document::Transform::Role::Backend';
321              
322              
323              
324              
325             has '+'.$_.'_id_key' =>
326             (
327             default => '_id'
328             ) for qw/document transform/;
329              
330             has '+reference_id_key' => ( default => 'source' );
331              
332             __PACKAGE__->meta->make_immutable();
333             1;
334              
335              
336             =pod
337              
338             =head1 NAME
339              
340             Document::Transform::Backend::MongoDB - Talk to a MongoDB via a simple interface
341              
342             =head1 VERSION
343              
344             version 1.110530
345              
346             =head1 SYNOPSIS
347              
348             use Document::Transform::Backend::MongoDB;
349              
350             my $backend = Document::Transform::Backend::MongoDB->new(
351             host => $ENV{MONGOD}
352             database_name => 'foo',
353             transform_collection => 'transforms',
354             document_collection => 'documents');
355              
356             my $doc = $backend->fetch_document_from_key(
357             MongoDB::OID->new(value => 'deadbeef'));
358              
359             =head1 DESCRIPTION
360              
361             So you need Document::Transform to talk MongoDB. You're in luck, bucko, because this module is your godsend. And it comes by default! Now, there are a couple of different ways to instantiate this and different levels of attributes that can be filled. You can plug in the collections, you can plug in collection names and a database instance, you can plug in collection names, a database name, and connection instance. And if you don't have any instances then some connection info, database name, and collection names are all you need! So it is like you pick your level of support when calling into a PBS telethon.
362              
363             =head1 PUBLIC_ATTRIBUTES
364              
365             =head2 document_constraint
366              
367             is: ro, isa: Moose::Meta::TypeConstraint
368             builder: _build_document_constraint, lazy: 1
369              
370             This attribute implements
371             L<Document::Transform::Role::Backend/document_constraint> and provides a
372             meaningful type constraint built using L</document_id_key> in the where clause
373             to check for the appropriate keys in the data structure that represents a
374             document.
375              
376             =head2 transform_constraint
377              
378             is: ro, isa: Moose::Meta::TypeConstraint
379             builder: _build_transform_constraint, lazy: 1
380              
381             This attribute implements
382             L<Document::Transform::Role::Backend/transform_constraint> and provides a
383             meaningful type constraint built using L</transform_id_key> in the where clause
384             to check for the appropriate keys in the data structure that represents a
385             transform.
386              
387             =head2 host
388              
389             is: ro, isa: Str
390              
391             host contains the host string provided to the MongoDB::Connection constructor.
392              
393             =head2 connection
394              
395             is: ro, isa: MongoDB::Connection, lazy: 1
396              
397             This attribute holds the MongoDB connection object. If this isn't provided and
398             it is accessed, a connection will be constructed using the L</host> attribute.
399              
400             =head2 database_name
401              
402             is: ro, isa: Str
403              
404             If the collections are not provided, this attribute must be provided as a means
405             to access the collections named in the L</transform_collection> and
406             L</document_collection>
407              
408             =head2 database
409              
410             is: ro, isa: MongoDB::Database, lazy: 1
411              
412             This attribute holds the MongoDB data in which the transform and document
413             collections are held. If this isn't provided in the constructor, one will be
414             constructed using the value from L</database_name>. If there is no value, an
415             exception will be thrown.
416              
417             =head2 document_collection
418              
419             is: ro, isa: Str
420              
421             If a collection is not passed to L</documents>, this attribute will be used to
422             access a collection from the L</database>.
423              
424             =head2 documents
425              
426             is: ro, isa: MongoDB::Collection, lazy: 1
427              
428             This attribute holds the collection from MongoDB that should be the documents
429             that should be fetched for transformation. If a collection is not passed to the
430             constructor, one will be pulled from the database using the value from
431             L</document_collection>
432              
433             =head2 transform_collection
434              
435             is: ro, isa: Str
436              
437             If a collection is not passed to L</transforms>, this attribute will be used to
438             access a collection from the L</database>.
439              
440             =head2 transforms
441              
442             is: ro, isa: MongoDB::Collection, lazy: 1
443              
444             This attribute holds the collection from MongoDB that should be the transforms
445             that should be fetched for transformation. If a collection is not passed to the
446             constructor, one will be pulled from the database using the value from
447             L</transform_collection>
448              
449             =head2 document_id_key
450              
451             is: ro, isa: Str,
452             default: '_id',
453              
454             =head2 transform_id_key
455              
456             is: ro, isa: Str,
457             +default: '_id',
458              
459             =head2 reference_id_key
460              
461             is: ro, isa: Str,
462             +default: 'source',
463              
464             This attribute holds the key used in the transform to reference the document to
465             which this transform should occur.
466              
467             =head1 PUBLIC_METHODS
468              
469             =head2 fetch_document_from_key
470              
471             (Defined)
472              
473             This method implements the
474             L<Docoument::Transform::Role::Backend/fetch_document_from_key> method. It takes
475             a single key that should match a document within the documents collection with
476             the right L</document_id_key> attribute.
477              
478             =head2 fetch_transform_from_key
479              
480             (Defined)
481              
482             This method implements the
483             L<Docoument::Transform::Role::Backend/fetch_transform_from_key> method. It
484             takes a single key that should match a transform within the transforms
485             collection with the right L</transform_id_key> attribute.
486              
487             =head2 fetch_document_from_transform
488              
489             (Transform)
490              
491             This method implements the
492             L<Docoument::Transform::Role::Backend/fetch_document_from_transform> method. It
493             takes a Transform defined by L</transform_constraint> that has DBRef to a document
494             stored with in the L</reference_id_key> attribute of the transform.
495              
496             =head2 fetch_transform_from_document
497              
498             This method is a no-op implementation of
499             L<Docoument::Transform::Role::Backend/fetch_transform_from_document>.
500              
501             =head2 store_document
502              
503             This method implements the L</Document::Transform::Role::Backend/store_document>
504             method with one key notable option. In addition to the document to store, a
505             second boolean value can be passed to denote whether a "safe" insert/update
506             should take place.
507              
508             This method makes use of L</document_id_key> to perform an update of the
509             document.
510              
511             =head2 store_transform
512              
513             This method implements the L</Document::Transform::Role::Backend/store_transform>
514             method with one key notable option. In addition to the transform to store, a
515             second boolean value can be passed to denote whether a "safe" insert/update
516             should take place.
517              
518             This method makes use of L</transform_id_key> to perform an update of the
519             transform.
520              
521             =head2 has_document
522              
523             (Defined)
524              
525             This method implements L<Document::Transform::Role::Backend/has_document>.
526             Simply provide a key and it will check Mongo if such a document exists using
527             L</document_id_key>
528              
529             =head2 has_transform
530              
531             (Defined)
532              
533             This method implements L<Document::Transform::Role::Backend/has_transform>.
534             Simply provide a key and it will check Mongo if such a transform exists using
535             L</transform_id_key>
536              
537             =head2 is_same_document
538              
539             (Document, Document)
540              
541             This method implements L<Document::Transform::Role::Backend/is_same_document>.
542             It does a string comparison between the two documents values stored in
543             L</document_id_key>. If using the default '_id' value for L</document_id_key>,
544             this will stringify the MongoDB::OID objects down to their hex key and compare
545             them.
546              
547             =head2 is_same_transform
548              
549             (Transform, Transform)
550              
551             This method implements L<Transform::Transform::Role::Backend/is_same_transform>.
552             It does a string comparison between the two transforms values stored in
553             L</transform_id_key>. If using the default '_id' value for L</transform_id_key>,
554             this will stringify the MongoDB::OID objects down to their hex key and compare
555             them.
556              
557             =head1 AUTHOR
558              
559             Nicholas R. Perez <nperez@cpan.org>
560              
561             =head1 COPYRIGHT AND LICENSE
562              
563             This software is copyright (c) 2010 by Infinity Interactive.
564              
565             This is free software; you can redistribute it and/or modify it under
566             the same terms as the Perl 5 programming language system itself.
567              
568             =cut
569              
570              
571             __END__
572