File Coverage

blib/lib/Mongoose.pm
Criterion Covered Total %
statement 37 73 50.6
branch 6 32 18.7
condition 2 13 15.3
subroutine 10 15 66.6
pod 6 6 100.0
total 61 139 43.8


line stmt bran cond sub pod time code
1             package Mongoose;
2             $Mongoose::VERSION = '1.02';
3 25     25   3045615 use MooseX::Singleton;
  25         5640877  
  25         86  
4 25     25   557176 use Class::MOP;
  25         41  
  25         507  
5 25     25   13985 use MongoDB;
  25         30553420  
  25         682  
6 25     25   173 use Carp;
  25         35  
  25         1025  
7 25     25   93 use version;
  25         34  
  25         84  
8              
9             with 'Mongoose::Role::Naming';
10              
11             has _db => (
12             is => 'rw',
13             isa => 'HashRef',
14             default => sub {{}},
15             );
16              
17             has _client => (
18             is => 'rw',
19             isa => "HashRef",
20             lazy => 1,
21             default => sub {{}},
22             clearer => 'disconnect'
23             );
24              
25             has _args => (
26             is => 'rw',
27             isa => 'HashRef',
28             default => sub{{}}
29             );
30              
31             has _alias => ( # keep track of aliased() document classes.
32             is => 'rw',
33             isa => 'HashRef',
34             default => sub{{}}
35             );
36              
37             has _config => ( # Store document classes configuration
38             is => 'rw',
39             isa => 'HashRef',
40             default => sub{{}}
41             );
42              
43             sub db {
44 24     24 1 471672 my $self = shift;
45 24 100       185 my %p = @_ == 1 ? (db_name=>shift) : @_;
46 24         59 my $now = delete $p{'-now'};
47 24         131 my $name = $self->_add_args( \%p );
48              
49 24 50 33     236 return $self->connect($name) if $now || defined wantarray;
50             }
51              
52             sub class_config {
53 2     2 1 4 my ( $self, $class_name, $config ) = @_;
54              
55             # Set
56 2 50       55 return $self->_config->{$class_name} = $config if $config;
57              
58             # Get
59 0   0     0 my $class = $self->aliased(ref $class_name || $class_name);
60             confess "Document class '$class' is not registered. Registered classes are: ".
61 0 0       0 join(', ', keys %{$self->_config}) unless exists $self->_config->{$class};
  0         0  
62 0         0 $self->_config->{$class};
63             }
64              
65             # setup db config and class to db mapping if class exists.
66             sub _add_args {
67 24     24   49 my ( $self, $args ) = @_;
68 24         79 my $name = 'default';
69 24 50       190 if ( my $class = delete $args->{class} ) {
70 0 0       0 $class = [$class] unless ref $class eq 'ARRAY';
71 0         0 $name = join "-", @$class;
72 0         0 $self->_args->{class}{$_} = $name for @$class;
73             }
74 24         993 $self->_args->{db}{$name} = $args;
75 24         54 $name;
76             }
77              
78             # Connection/db name for a given class
79             sub _name_for_class {
80 0     0   0 my ( $self, $class ) = @_;
81 0 0       0 return 'default' unless $class;
82 0 0       0 $self->_args->{class}{$class} || 'default';
83             }
84              
85             # Go thru class-db mapping and ensure to get a connected db.
86             sub _db_for_class {
87 0     0   0 my ( $self, $class ) = @_;
88 0         0 my $name = $self->_name_for_class($class);
89 0 0       0 $self->_db->{$name} || $self->connect($name);
90             }
91              
92             sub connect {
93 24     24 1 45 my ( $self, $name ) = @_;
94 24   50     79 $name ||= 'default';
95 24         36 my %p = %{ $self->_args->{db}{$name} };
  24         500  
96 24         524 my $data_db_name = $p{db_name};
97              
98             $self->_client->{$name} = MongoDB::MongoClient->new(%p)
99 24 50       542 unless ref $self->_client->{$name};
100              
101 24         897 $self->_db->{$name} = $self->_client->{$name}->get_database( $data_db_name );
102             }
103              
104             sub connection {
105 0     0 1   my ( $self, $name ) = @_;
106 0   0       $name ||= 'default';
107 0 0         $self->_client->{$name} and return $self->_client->{$name};
108 0 0         $self->connect($name) and return $self->_client->{$name};
109             }
110              
111             sub load_schema {
112 0     0 1   my ( $self, %args ) = @_;
113 0           my $shorten = delete $args{shorten};
114 0           my $search_path = delete $args{search_path};
115              
116 0           require Module::Pluggable;
117 0           Module::Pluggable->import( search_path => $search_path );
118 0           for my $module ( $self->plugins ) {
119 0           eval "require $module";
120 0 0         croak $@ if $@;
121 0 0 0       if ( $shorten && $module =~ m/$search_path\:\:(.*?)$/ ) {
122 0           my $short_name = $1;
123 25     25   15513 no strict 'refs';
  25         32  
  25         4387  
124 0           *{ $short_name . "::" } = \*{ $module . "::" };
  0            
  0            
125 0           Class::MOP::store_metaclass_by_name( $short_name, $module->meta );
126 0           Class::MOP::weaken_metaclass( $short_name );
127 0           $self->aliased($short_name => $module);
128             }
129             }
130             }
131              
132             sub aliased {
133 0     0 1   my ( $self, $alias, $class ) = @_;
134 0 0         $self->_alias->{$alias} = $class if $class;
135 0 0         exists $self->_alias->{$alias} ? $self->_alias->{$alias} : $alias;
136             }
137              
138             __PACKAGE__->meta->make_immutable();
139              
140             =head1 NAME
141              
142             Mongoose - MongoDB document to Moose object mapper
143              
144             =head1 SYNOPSIS
145              
146             package Person;
147             use Moose;
148             with 'Mongoose::Document';
149             has 'name' => ( is => 'rw', isa => 'Str' );
150              
151             package main;
152             use Mongoose;
153              
154             Mongoose->db('mydb');
155              
156             my $person = Person->new( name => 'Jack' );
157             $person->save;
158              
159             $person = Person->find_one({ name => 'Jack' });
160             say $person->name; # Jack
161              
162             Person->find({ name => qr/^J/' })->each(sub{
163             say "Found ", $person->name;
164             });
165              
166             $person->delete;
167              
168             =head1 DESCRIPTION
169              
170             This is a L<MongoDB> to L<Moose> object mapper. This module allows you to use the full
171             power of MongoDB within your Moose classes, without sacrificing MongoDB's
172             power, flexibility and speed.
173              
174             It's loosely inspired by Ruby's MongoMapper,
175             which is in turn loosely based on the ActiveRecord pattern.
176              
177             Start by reading the introduction L<Mongoose::Intro>.
178              
179             Or proceed directly to the L<Mongoose::Cookbook> for many day-to-day recipes.
180              
181             =head1 WARNING
182              
183             Since version 1.00 Mongoose only support the new L<MongoDB> driver v1.x.x which it's now required.
184              
185             Please let me know if you find anything strange using this new driver.
186              
187             =head1 METHODS
188              
189             =head2 db
190              
191             Sets the current MongoDB connection and/or db name.
192              
193             Mongoose->db( 'mydb' );
194              
195             The connection defaults to whatever MongoDB defaults are
196             (typically localhost:27017).
197              
198             For more control over the connection, C<db> takes the same parameters as
199             L<MongoDB::MongoClient>.
200              
201             my $db = Mongoose->db(
202             host => 'mongodb://somehost:27017',
203             read_pref_mode => 'secondaryPreferred',
204             db_name => 'mydb',
205             username => 'myuser',
206             password => 'mypass',
207             ssl => 1
208             );
209              
210             This will, in turn, instantiate a L<MongoDB::MongoClient> and return
211             a L<MongoDB::Database> object for C<mydb>.
212              
213             B<Important>: Mongoose will always defer connecting to Mongo
214             until the last possible moment. This is done to prevent
215             using the MongoDB driver in a forked environment (ie. with a
216             prefork appserver like Starman, Hypnotoad or Catalyst's
217             HTTP::Prefork).
218              
219             If you prefer to connect while setting the connection string,
220             use one of these options:
221              
222             Mongoose->db( db_name=>'mydb', -now=>1 ); # connect now
223              
224             # or by wating for a return value
225              
226             my $db = Mongoose->db( 'mydb' );
227              
228             # or explicitly:
229              
230             Mongoose->db( 'mydb' );
231             Mongoose->connect;
232              
233             You can separate your classes storage on multiple hosts/databases
234             by calling db() several times:
235              
236             # Default host/database (connect now!)
237             my $db = Mongoose->db( 'mydb' );
238              
239             # Other database for some class (defer connection)
240             Mongoose->db( db_name => 'my_other_db', class => 'Log' );
241              
242             # Other database on other host for several classes
243             Mongoose->db(
244             db_name => 'my_remote_db',
245             host => 'mongodb://192.168.1.23:27017',
246             class => [qw/ Author Post /]
247             );
248              
249             =head2 connect
250              
251             Connects to Mongo using the connection arguments passed to the C<db> method.
252              
253             =head2 load_schema
254              
255             Uses L<Module::Pluggable> to C<require> all modules under a given search path
256             or search dir.
257              
258             All arguments will be sent to Module::Pluggable's C<import>, except for
259             Mongoose specific ones.
260              
261             package main;
262             use Mongoose;
263              
264             # to load a schema from a namespace path:
265             Mongoose->load_schema( search_path=>'MyApp::Schema' );
266              
267              
268             This method can be used to shorten class names, aliasing them for
269             convenience if you wish:
270              
271             Mongoose->load_schema( search_path=>'MyApp::Schema', shorten=>1 );
272              
273             Will shorten the module name to it's last bit:
274              
275             MyApp::Schema::Author->new( ... );
276              
277             # becomes
278              
279             Author->new( ... );
280              
281             =head2 connection
282              
283             Sets/returns the current connection object, of class L<MongoDB::MongoClient>.
284              
285             Defaults to whatever MongoDB defaults.
286              
287             =head2 disconnect
288              
289             Unsets the Mongoose connection handler.
290              
291             =head2 class_config
292              
293             Keep track of document classes config solving aliasing indirection.
294              
295             =head2 aliased
296              
297             Keep track of aliasing classes. Useful to retrieve full document class from a shortened one.
298              
299             =head1 COLLECTION NAMING
300              
301             By default, Mongoose composes the Mongo collection name from your package name
302             by replacing double-colon C<::> with underscores C<_>, separating camel-case,
303             such as C<aB> with C<a_b> and uppercase with lowercase letters.
304              
305             This behaviour can be changed by choosing other named method or by setting
306             the collection naming routine with a C<closure> as exlained in L<Mongoose::Role::Naming>.
307              
308             =head1 REPOSITORY
309              
310             Fork me on github: L<http://github.com/rodrigolive/mongoose>
311              
312             =head1 BUGS
313              
314             This is a WIP, now *beta* quality software.
315              
316             Report bugs via Github Issue reporting L<https://github.com/rodrigolive/mongoose/issues>.
317             Test cases highly desired and appreciated.
318              
319             =head1 TODO
320              
321             * Better error control
322              
323             * Finish-up multiple database support
324              
325             * Allow query->fields to control which fields get expanded into the object.
326              
327             * Cleanup internals.
328              
329             * More tests and use cases.
330              
331             * Better documentation.
332              
333             =head1 SEE ALSO
334              
335             L<KiokuDB>
336              
337             =head1 AUTHOR
338              
339             Rodrigo de Oliveira (rodrigolive), C<rodrigolive@gmail.com>
340              
341             =head1 MAINTAINER
342              
343             Diego Kuperman (diegok)
344              
345             =head1 CONTRIBUTORS
346              
347             Arthur Wolf
348             Solli Moreira Honorio (shonorio)
349             Michael Gentili (gentili)
350             Kang-min Liu (gugod)
351             Allan Whiteford (allanwhiteford)
352             Kartik Thakore (kthakore)
353             David Golden (dagolden)
354              
355             =head1 LICENSE
356              
357             This library is free software. You can redistribute it and/or modify it under
358             the same terms as Perl itself.
359