File Coverage

blib/lib/Mandel/Relationship/BelongsTo.pm
Criterion Covered Total %
statement 23 49 46.9
branch 3 22 13.6
condition 0 6 0.0
subroutine 6 9 66.6
pod 1 1 100.0
total 33 87 37.9


line stmt bran cond sub pod time code
1             package Mandel::Relationship::BelongsTo;
2              
3             =head1 NAME
4              
5             Mandel::Relationship::BelongsTo - A document is owned by another mongodb document
6              
7             =head1 DESCRIPTION
8              
9             L is a class used to describe the relationship
10             between one document that belongs to another document. The connection
11             between the documents is described in the database using
12             L.
13              
14             =head1 DATABASE STRUCTURE
15              
16             A "cat" that I a "person" will look like this in the database:
17              
18             mongodb# db.persons.find();
19             { "_id" : ObjectId("5352abb0c5483e591a010000") }
20              
21             mongodb# db.cats.find({ "person.$id": ObjectId("5352abb0c5483e591a010000") })
22             {
23             "_id" : ObjectId("5352abb0c5483e591a020000"),
24             "person" : DBRef("persons", ObjectId("5352abb0c5483e591a010000"))
25             }
26              
27             =head1 SYNOPSIS
28              
29             =head2 Using DSL
30              
31             package MyModel::Cat;
32             use Mandel::Document;
33             belongs_to owner => 'MyModel::Person';
34              
35             =head2 Using object oriented interface
36              
37             MyModel::Cat
38             ->model
39             ->relationship(belongs_to => owner => 'MyModel::Person');
40              
41             See also L.
42              
43             =head2 Methods generated
44              
45             # non-blocking set
46             $cat = MyModel::Cat->new->owner(\%args, sub {
47             my($cat, $err, $person_obj) = @_;
48             # ...
49             });
50              
51             $cat = MyModel::Cat->new->owner($person_obj, sub {
52             my($cat, $err, $person_obj) = @_;
53             # ...
54             });
55              
56             # non-blocking get
57             $cat = MyModel::Cat->new->owner(sub {
58             my($cat, $err, $person_obj) = @_;
59             # ...
60             });
61              
62              
63             # blocking set
64             $person_obj = MyModel::Cat->new->owner(\%args);
65             $person_obj = MyModel::Cat->new->owner($person_obj);
66             $person_obj = MyModel::Cat->new->owner($bson_oid);
67              
68             # blocking get
69             $person = MyModel::Cat->new->owner;
70              
71             =cut
72              
73 1     1   703 use Mojo::Base 'Mandel::Relationship';
  1         1  
  1         6  
74 1     1   124 use Mojo::Util;
  1         2  
  1         35  
75 1     1   4 use Mango::BSON 'bson_dbref';
  1         2  
  1         743  
76              
77             =head1 ATTRIBUTES
78              
79             L inherits all attributes from
80             L and implements the following new ones.
81              
82             =head2 foreign_field
83              
84             The name of the field in this class which hold the "_id" to the related doc.
85              
86             =cut
87              
88             has foreign_field => sub { shift->accessor };
89              
90             =head1 METHODS
91              
92             L inherits all methods from
93             L and implements the following new ones.
94              
95             =head2 monkey_patch
96              
97             Add methods to L.
98              
99             =cut
100              
101             sub monkey_patch {
102 1     1 1 28 my $self = shift;
103 1         5 my $foreign_field = $self->foreign_field;
104 1         10 my $accessor = $self->accessor;
105              
106             Mojo::Util::monkey_patch(
107             $self->document_class,
108             $accessor,
109             sub {
110 1 50   1   32 my $cb = ref $_[-1] eq 'CODE' ? pop : undef;
        1      
111 1         2 my $doc = shift;
112 1         2 my $obj = shift;
113 1         6 my $related_model = $self->_related_model;
114 1         7 my $related_collection = $related_model->new_collection($doc->connection);
115              
116 1 50 0     103 if ($obj) { # set
    0          
117 1 50       13 if (UNIVERSAL::isa($obj, 'Mango::BSON::ObjectID')) {
118 1         6 $doc->data->{$foreign_field} = bson_dbref $related_model->collection_name, $obj;
119 1         10 return $obj;
120             }
121 0 0       0 if (ref $obj eq 'HASH') {
122 0         0 $obj = $related_collection->create($obj);
123             }
124              
125 0         0 $doc->data->{$foreign_field} = bson_dbref $related_model->collection_name, $obj->id;
126 0 0       0 $doc->dirty->{$foreign_field} = 1 if $doc->dirty;
127              
128             # Blocking
129 0 0       0 unless ($cb) {
130 0         0 $obj->save;
131 0         0 $doc->save;
132 0         0 $doc->_cache($accessor => $obj);
133 0         0 return $obj;
134             }
135              
136             # Non-blocking
137             Mojo::IOLoop->delay(
138             sub {
139 0     0   0 my ($delay) = @_;
140 0         0 $obj->save($delay->begin);
141 0         0 $doc->save($delay->begin);
142             },
143             sub {
144 0     0   0 my ($delay, $o_err, $d_err) = @_;
145 0   0     0 my $err = $o_err || $d_err;
146 0 0       0 $doc->_cache($accessor => $obj) unless $err;
147 0         0 $doc->$cb($err, $obj);
148             },
149 0         0 );
150             }
151             elsif (!delete $doc->{fresh} and my $cached = $doc->_cache($accessor)) { # get cached
152 0 0       0 return $cached unless $cb;
153 0         0 $self->$cb('', $cached);
154             }
155             else { # get
156 0         0 my $cursor = $related_collection->search({_id => $doc->data->{$foreign_field}{'$id'}});
157 0 0       0 return $doc->_cache($accessor => $cursor->single) unless $cb;
158             $cursor->single(
159             sub {
160 0     0   0 my ($cursor, $err, $obj) = @_;
161 0 0       0 $doc->_cache($accessor => $obj) unless $err;
162 0         0 $doc->$cb($err, $obj);
163             }
164 0         0 );
165             }
166              
167 0         0 $doc;
168             }
169 1         10 );
170              
171 1         34 return $self;
172             }
173              
174             =head1 SEE ALSO
175              
176             L, L, L
177              
178             =head1 AUTHOR
179              
180             Jan Henning Thorsen - C
181              
182             =cut
183              
184             1;