File Coverage

blib/lib/Mandel.pm
Criterion Covered Total %
statement 65 70 92.8
branch 15 20 75.0
condition 2 3 66.6
subroutine 15 17 88.2
pod 6 6 100.0
total 103 116 88.7


line stmt bran cond sub pod time code
1             package Mandel;
2              
3             =head1 NAME
4              
5             Mandel - Async model layer for MongoDB objects using Mango
6              
7             =head1 VERSION
8              
9             0.29
10              
11             =head1 SYNOPSIS
12              
13             # create your custom model class
14             package MyModel;
15             use Mojo::Base "Mandel";
16             1;
17              
18             # create a document class
19             package MyModel::Cat;
20             use Mandel::Document;
21             use Types::Standard 'Str';
22             field name => ( isa => Str, builder => sub { "value" } );
23             field 'type';
24             belongs_to person => 'MyModel::Person';
25             1;
26              
27             # create another document class
28             package MyModel::Person;
29             use Mandel::Document;
30             use Types::Standard 'Int';
31             field [qw( name )];
32             field age => ( isa => Int );
33             has_many cats => 'MyModel::Cat';
34             has_one favorite_cat => 'MyModel::Cat';
35             1;
36              
37             # use the model in your application
38             package main;
39             my $connection = MyModel->connect("mongodb://localhost/my_db");
40             my $persons = $connection->collection('person');
41              
42             my $p1 = $persons->create({ name => 'Bruce', age => 30 });
43             $p1->save(sub {
44             my($p1, $err) = @_;
45             });
46              
47             $persons->count(sub {
48             my($persons, $err, $n_persons) = @_;
49             });
50              
51             $persons->all(sub {
52             my($persons, $err, $objs) = @_;
53             for my $p (@$objs) {
54             $p->age(25)->save(sub {});
55             }
56             });
57              
58             $persons->search({ name => 'Bruce' })->single(sub {
59             my($persons, $err, $person) = @_;
60              
61             $person->cats(sub {
62             my($person, $err, $cats) = @_;
63             $_->remove(sub {}) for @$cats;
64             });
65              
66             $person->remove(sub {
67             my($person, $err) = @_;
68             });
69             });
70              
71             =head1 DESCRIPTION
72              
73             THIS IS ALPHA SOFTWARE! THE API MAY BE CHANGED AT ANY TIME!
74             PLEASE CONTACT ME IF YOU HAVE ANY COMMENTS OR FEEDBACK.
75              
76             L is an async object-document-mapper. It allows you to work with your
77             MongoDB documents in Perl as objects.
78              
79             This class binds it all together:
80              
81             =over 4
82              
83             =item * L
84              
85             An object modelling a document.
86              
87             =item * L
88              
89             A collection of Mandel documents.
90              
91             =item * L
92              
93             A single MongoDB document with logic.
94              
95             =back
96              
97             =cut
98              
99 18     18   492704 use Mojo::Base 'Mojo::Base';
  18         12235  
  18         130  
100 18     18   16637 use Mojo::Loader qw( find_modules load_class );
  18         1167665  
  18         1315  
101 18     18   183 use Mojo::Util;
  18         33  
  18         608  
102 18     18   11445 use Mandel::Collection;
  18         66  
  18         183  
103 18     18   11955 use Mandel::Model;
  18         69  
  18         209  
104 18     18   14786 use Mango;
  18         1759402  
  18         210  
105 18     18   698 use Carp 'confess';
  18         40  
  18         20246  
106              
107             our $VERSION = '0.29';
108              
109             =head1 ATTRIBUTES
110              
111             L inherits all attributes from L and implements the
112             following new ones.
113              
114             =head2 namespaces
115              
116             The namespaces which will be searched when looking for Types. By default, the
117             (sub)class name of this module.
118              
119             =head2 model_class
120              
121             Returns L.
122              
123             =head2 storage
124              
125             An instance of L which acts as the database connection. If not
126             provided.
127              
128             =cut
129              
130             has model_class => sub { shift->_build_model_class };
131             has namespaces => sub { shift->_build_namespaces };
132             has storage => sub { shift->_build_storage };
133              
134 5     5   63 sub _build_model_class {'Mandel::Model'}
135 3     3   25 sub _build_namespaces { [ref $_[0]] }
136 0     0   0 sub _build_storage { Mango->new('mongodb://localhost/mandeltest') }
137              
138             =head1 METHODS
139              
140             L inherits all methods from L and implements the following
141             new ones.
142              
143             =head2 connect
144              
145             $self = $class->connect(@connect_args);
146             $clone = $self->connect(@connect_args);
147              
148             C<@connect_args> will be passed on to L, which again will be set
149             as L.
150              
151             Calling this on an object will return a clone, but with a fresh L
152             object.
153              
154             =cut
155              
156             sub connect {
157 2     2 1 467 my ($self, @args) = @_;
158 2         13 my $storage = Mango->new(@args);
159              
160 2 50       35 if (my $class = ref $self) {
161 2         11 $self = $class->new(%$self, storage => $storage);
162             }
163             else {
164 0         0 $self = $self->new(storage => $storage);
165             }
166              
167 2         17 $self;
168             }
169              
170             =head2 all_document_names
171              
172             @names = $self->all_document_names;
173              
174             Returns a list of all the documents in the L.
175              
176             =cut
177              
178             sub all_document_names {
179 3     3 1 7 my $self = shift;
180 3 50       6 my %names = map { $_, 1 } keys %{$self->{model} || {}};
  0         0  
  3         28  
181              
182 3         9 for my $ns (@{$self->namespaces}) {
  3         12  
183 3         28 for my $name (find_modules $ns) {
184 6         1608 my $e = load_class $name;
185 6 100       897 next unless $name->isa('Mandel::Document');
186 3         85 $name =~ s/^${ns}:://;
187 3         16 $names{Mojo::Util::decamelize($name)} = 1;
188             }
189             }
190              
191 3         23 keys %names;
192             }
193              
194             =head2 class_for
195              
196             $document_class = $self->class_for($name);
197              
198             Given a document name, find the related class name, ensure that it is loaded
199             (or else die) and return it.
200              
201             =cut
202              
203             sub class_for {
204 5     5 1 12 my ($self, $name) = @_;
205              
206 5 100       24 if (my $class = $self->{loaded}{$name}) {
207 2         6 return $class;
208             }
209              
210 3         5 for my $ns (@{$self->namespaces}) {
  3         12  
211 3         60 my $class = $ns . '::' . Mojo::Util::camelize($name);
212 3         57 my $e = load_class $class;
213 3 50       48 die $e if ref $e;
214 3 50       8 next if $e;
215 3         19 return $self->{loaded}{$name} = $class;
216             }
217              
218 0         0 confess "Could not find class for $name";
219             }
220              
221             =head2 collection
222              
223             $collection_obj = $self->collection($name);
224              
225             Returns a L object.
226              
227             =cut
228              
229             sub collection {
230 1     1 1 437 my ($self, $name) = @_;
231              
232 1         35 $self->model($name)->new_collection($self);
233             }
234              
235             =head2 model
236              
237             $model = $self->model($name);
238             $self = $self->model($name => \%model_args);
239             $self = $self->model($name => $model_obj);
240              
241             Define or returns a L object. Will die unless a model is
242             registered by that name or L returns a class which has the
243             C method defined.
244              
245             =cut
246              
247             sub model {
248 22     22 1 802 my ($self, $name, $model) = @_;
249              
250 22 100       103 if ($model) {
251 10 50       81 $model = $self->model_class->new($model) if ref $model eq 'HASH';
252 10         150 $model->name($name);
253 10         102 $self->{loaded}{$name} = $model->document_class;
254 10         30 $self->{model}{$name} = $model;
255 10         42 return $self;
256             }
257             else {
258 12   66     72 return $self->{model}{$name} ||= $self->class_for($name)->model;
259             }
260             }
261              
262             =head2 initialize
263              
264             $self->initialize(@names, \%args);
265             $self->initialize(\%args);
266              
267             Takes a list of document names. Calls the L method
268             on any document given as input. C<@names> default to L
269             unless specified.
270              
271             C<%args> defaults to empty hash ref, unless specified as input.
272              
273             The C method will be called like this:
274              
275             $document_class->initialize($self, \%args);
276              
277             =cut
278              
279             sub initialize {
280 3 100   3 1 4951 my $args = ref $_[-1] eq 'HASH' ? pop : {};
281 3         6 my $self = shift;
282 3 100       13 my @documents = @_ ? @_ : $self->all_document_names;
283              
284 3         7 for my $document (@documents) {
285 3         10 my $class = $self->class_for($document);
286 3         15 $class->initialize($self, $args);
287             }
288             }
289              
290             sub _storage_collection {
291 0     0     $_[0]->storage->db->collection($_[1]);
292             }
293              
294             =head1 SEE ALSO
295              
296             L, L
297              
298             Still got MongoDB 2.4 on Ubuntu? Check out
299             L
300             to upgrade.
301              
302             =head1 SOURCE REPOSITORY
303              
304             L
305              
306             =head1 AUTHORS
307              
308             Jan Henning Thorsen - C
309              
310             Joel Berger - C
311              
312             Holger Rupprecht - C
313              
314             Huo Linhe - C
315              
316             This project is a fork of L,
317             created by Joel Berger, C.
318              
319             =head1 COPYRIGHT AND LICENSE
320              
321             Copyright (C) 2013 by Jan Henning Thorsen
322              
323             This library is free software; you can redistribute it and/or modify
324             it under the same terms as Perl itself.
325              
326             =cut
327              
328             1;