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