File Coverage

blib/lib/Mandel/Relationship/HasMany.pm
Criterion Covered Total %
statement 25 61 40.9
branch 0 22 0.0
condition 0 8 0.0
subroutine 7 16 43.7
pod 1 1 100.0
total 33 108 30.5


line stmt bran cond sub pod time code
1             package Mandel::Relationship::HasMany;
2 1     1   621 use Mojo::Base 'Mandel::Relationship';
  1         3  
  1         7  
3 1     1   71 use Mojo::Util;
  1         2  
  1         43  
4 1     1   6 use Mango::BSON 'bson_dbref';
  1         2  
  1         1014  
5              
6             has add_method_name => sub { sprintf 'add_%s', shift->accessor };
7             has search_method_name => sub { sprintf 'search_%s', shift->accessor };
8              
9             sub monkey_patch {
10 1     1 1 29 shift->_monkey_patch_all_method->_monkey_patch_add_method->_monkey_patch_search_method;
11             }
12              
13             sub _monkey_patch_all_method {
14 1     1   2 my $self = shift;
15 1         3 my $search = $self->search_method_name;
16 1         12 my $accessor = $self->accessor;
17              
18             Mojo::Util::monkey_patch(
19             $self->document_class,
20             $accessor,
21             sub {
22 0     0   0 my ($doc, $cb) = @_;
        0      
23 0 0       0 my $cached = delete $doc->{fresh} ? undef : $doc->_cache($accessor);
24              
25             # Blocking
26 0 0       0 unless ($cb) {
27 0 0       0 return $cached if $cached;
28 0         0 return $doc->_cache($accessor => $doc->$search->all);
29             }
30              
31 0 0       0 if ($cached) {
32 0         0 $doc->$cb('', $cached);
33             }
34             else {
35             $doc->$search->all(
36             sub {
37 0     0   0 my ($collection, $err, $objs) = @_;
38 0 0       0 $doc->_cache($accessor => $objs) unless $err;
39 0         0 $doc->$cb($err, $objs);
40             }
41 0         0 );
42             }
43              
44 0         0 return $doc;
45             }
46 1         8 );
47              
48 1         25 return $self;
49             }
50              
51             sub _monkey_patch_add_method {
52 1     1   2 my $self = shift;
53 1         5 my $foreign_field = $self->foreign_field;
54 1         12 my $accessor = $self->accessor;
55              
56             Mojo::Util::monkey_patch(
57             $self->document_class,
58             $self->add_method_name,
59             sub {
60 0     0   0 my ($doc, $obj, $cb) = @_;
        0      
61 0         0 my $cached = $doc->_cache($accessor);
62              
63 0 0       0 if (ref $obj eq 'HASH') {
64 0         0 $obj = $self->_related_model->new_collection($doc->connection)->create($obj);
65             }
66              
67 0         0 $obj->data->{$foreign_field} = bson_dbref $doc->model->collection_name, $doc->id;
68 0 0       0 $obj->dirty->{$foreign_field} = 1 if $obj->dirty;
69              
70             # Blocking
71 0 0       0 unless ($cb) {
72 0 0       0 push @$cached, $obj if $cached;
73 0         0 $obj->save;
74 0         0 $doc->save;
75 0         0 return $obj;
76             }
77              
78             # Non-blocking
79             Mojo::IOLoop->delay(
80             sub {
81 0     0   0 my ($delay) = @_;
82 0         0 $obj->save($delay->begin);
83 0         0 $doc->save($delay->begin);
84             },
85             sub {
86 0     0   0 my ($delay, $o_err, $d_err) = @_;
87 0   0     0 my $err = $o_err || $d_err;
88 0 0 0     0 push @$cached, $obj if !$err and $cached;
89 0         0 $doc->$cb($err, $obj);
90             },
91 0         0 );
92              
93 0         0 return $doc;
94             }
95 1         8 );
96              
97 1         27 return $self;
98             }
99              
100             sub _monkey_patch_search_method {
101 1     1   1 my $self = shift;
102 1         4 my $foreign_field = $self->foreign_field;
103 1         9 my $related_class = $self->related_class;
104              
105             Mojo::Util::monkey_patch(
106             $self->document_class,
107             $self->search_method_name,
108             sub {
109 0     0   0 my ($doc, $query, $extra) = @_;
        0      
110 0         0 my $related_model = $self->_related_model;
111              
112             return $related_model->new_collection(
113             $doc->connection,
114             extra => $extra || {},
115 0 0 0     0 query => {%{$query || {}}, sprintf('%s.$id', $foreign_field) => $doc->id},
  0         0  
116             );
117             }
118 1         5 );
119              
120 1         31 return $self;
121             }
122              
123             1;
124              
125             =encoding utf8
126              
127             =head1 NAME
128              
129             Mandel::Relationship::HasMany - A field relates to many other mongodb document
130              
131             =head1 DESCRIPTION
132              
133             L is a class used to describe the relationship
134             between one document that has a relationship to many other documents.
135             The connection between the documents is described in the database using
136             L.
137              
138             =head1 DATABASE STRUCTURE
139              
140             A "person" that I "cats" will look like this in the database:
141              
142             mongodb# db.persons.find();
143             { "_id" : ObjectId("53529f28c5483e4977020000") }
144              
145             mongodb# db.cats.find({ "person.$id": ObjectId("53529f28c5483e4977020000") })
146             {
147             "_id" : ObjectId("53529f28c5483e5077040000"),
148             "person" : DBRef("persons", ObjectId("53529f28c5483e4977020000"))
149             }
150             {
151             "_id" : ObjectId("6432574384483e4978010000"),
152             "person" : DBRef("persons", ObjectId("53529f28c5483e4977020000"))
153             }
154              
155             A "has many" on one side is L on the other
156             side.
157              
158             =head1 SYNOPSIS
159              
160             =head2 Using DSL
161              
162             package MyModel::Person;
163             use Mandel::Document;
164             has_many cats => 'MyModel::Cat';
165              
166             =head2 Using object oriented interface
167              
168             MyModel::Person->model->relationship(
169             "has_many",
170             "cats",
171             "MyModel::Cat",
172             );
173              
174             See also L.
175              
176             =head2 Methods generated
177              
178             # non-blocking
179             $person = MyModel::Person->new->add_cats(\%constructor_args, sub {
180             my($person, $err, $cat_obj) = @_;
181             # ...
182             });
183              
184             $person = MyModel::Person->new->add_cats($cat_obj, sub {
185             my($person, $err, $cat_obj) = @_;
186             # ...
187             });
188              
189             $person = MyModel::Cat->new->cats(sub {
190             my($self, $err, $array_of_cats) = @_;
191             # ...
192             });
193              
194             # blocking
195             $cat_obj = MyModel::Person->new->add_cats(\%args);
196             $cat_obj = MyModel::Person->new->add_cats($cat_obj);
197             $array_of_cats = MyModel::Person->new->cats;
198              
199             $cat_collection = MyModel::Person->new->search_cats;
200              
201             =head1 ATTRIBUTES
202              
203             L inherits all attributes from
204             L and implements the following new ones.
205              
206             =head2 add_method_name
207              
208             The name of the method used to add another document to the relationship.
209              
210             =head2 search_method_name
211              
212             The name of the method used to search related documents.
213              
214             =head1 METHODS
215              
216             L inherits all methods from
217             L and implements the following new ones.
218              
219             =head2 monkey_patch
220              
221             Add methods to L.
222              
223             =head1 SEE ALSO
224              
225             L, L, L
226              
227             =head1 AUTHOR
228              
229             Jan Henning Thorsen - C
230              
231             =cut