File Coverage

blib/lib/Mandel/Model.pm
Criterion Covered Total %
statement 101 109 92.6
branch 36 44 81.8
condition 6 6 100.0
subroutine 22 22 100.0
pod 4 5 80.0
total 169 186 90.8


line stmt bran cond sub pod time code
1             package Mandel::Model;
2 27     27   233 use Mojo::Base -base;
  27         56  
  27         335  
3 27     27   7833 use Mojo::Loader 'load_class';
  27         281756  
  27         1576  
4 27     27   192 use Mojo::Util;
  27         65  
  27         1176  
5 26     26   11053 use Mandel::Model::Field;
  26         83  
  26         252  
6 26     26   914 use Carp 'confess';
  26         222  
  26         15645  
7              
8             my $ANON = 1;
9              
10             has collection_name => sub {
11             my $self = shift;
12             my $name = $self->name;
13              
14             return $name =~ /s$/ ? $name : $name . 's' if $name;
15             confess "collection_name or name required in constructor";
16             };
17              
18             has collection_class => 'Mandel::Collection';
19              
20             has document_class => sub {
21             my $self = shift;
22             my $name = ucfirst $self->name || 'AnonDoc';
23             my $class = "Mandel::Document::__ANON_${ANON}__::$name"; # this might change
24              
25 5     5   41 eval <<" PACKAGE" or confess $@;
  5     5   11  
  5     3   27  
  5     2   37  
  5         19  
  5         22  
  3         63  
  2         61  
26             package $class;
27             use Mojo::Base "Mandel::Document";
28             sub model { \$self }
29             \$INC{"Mandel/Document/__ANON__$ANON.pm"} = "GENERATED";
30             PACKAGE
31              
32             $ANON++;
33             $class;
34             };
35              
36             has name => '';
37              
38             sub field {
39 17     17 1 51 my ($self, $name, $meta) = @_;
40              
41 17 100       52 if ($meta) {
42 12         43 return $self->_add_field($name => $meta); # $name might be an array-ref
43             }
44              
45 5 50       7 for (@{$self->{fields} || []}) {
  5         18  
46 15 100       29 return $_ if $name eq $_->name;
47             }
48              
49 0         0 return;
50             }
51              
52             sub _add_field {
53 12     12   28 my ($self, $fields, $meta) = @_;
54 12         53 my $class = $self->document_class;
55              
56             # Compile fieldibutes
57 12 100       114 for my $name (@{ref $fields eq 'ARRAY' ? $fields : [$fields]}) {
  12         59  
58 13         39 local $meta->{name} = $name;
59 13         110 my $field = Mandel::Model::Field->new($meta);
60 13         214 my $builder = $field->builder;
61 13         27 my $code = "";
62              
63 13         50 $code .= "package $class;\nsub $name {\n my \$raw = \$_[0]->data;\n";
64              
65 13 100       32 if ($builder) {
66 2         9 $code
67             .= "return exists \$raw->{'$name'} ? (\$raw->{'$name'}) : (\$raw->{'$name'} = \$_[0]->\$builder) if \@_ == 1;\n";
68             }
69             else {
70 11         70 $code .= "return \$raw->{'$name'} if \@_ == 1;\n";
71             }
72              
73 13         51 $code .= "local \$_ = \$_[1];\n";
74 13 100       93 $code .= $self->_field_type($meta->{isa}) if $meta->{isa};
75 13         38 $code .= "\$_[0]->{dirty}{$name} = 1;";
76 13         32 $code .= "\$raw->{'$name'} = \$_;\n";
77 13         23 $code .= "return \$_[0];\n}";
78              
79             # We compile custom attribute code for speed
80 26     26   244 no strict 'refs';
  26         86  
  26         6801  
81 13 50       45 warn "-- Attribute $name in $class\n$code\n\n" if $ENV{MOJO_BASE_DEBUG};
82 13 50   7 0 2279 Carp::croak "Mandel::Document error: $@ ($code)" unless eval "$code;1";
  9 100   2   86  
  9 100   1   90  
  8 100   1   4579  
  4 100   1   53  
  4 50       11  
  4 50       10  
  5 50       34  
  3 50       49  
  2         6  
  2         6  
  2         5  
  2         958  
  2         56  
  2         10  
  1         2  
  1         2  
  1         5  
  1         9  
  2         8  
  2         27  
  1         5  
  0         0  
  0         0  
  0         0  
  1         657  
  1         26  
  0            
  0            
  0            
  0            
83              
84 13         50 push @{$self->{fields}}, $field;
  13         68  
85             }
86              
87 12         53 $self;
88             }
89              
90             sub fields {
91 4 100   4 1 72 @{$_[0]->{fields} || []};
  4         54  
92             }
93              
94             sub _field_type {
95 7     8   49 my ($self, $type) = @_;
96 7         12 my $code = "";
97              
98 26     26   15491 use Types::Standard 'Num';
  26         1948686  
  26         286  
99              
100 7 100 100     28 if ($type->has_coercion and $type->coercion->can_be_inlined) {
101 2         126 $code .= '$_ = ' . $type->coercion->inline_coercion('$_') . ";\n";
102             }
103 6 100       438 if ($type->can_be_inlined) {
104 6         138 $code .= $type->inline_assert('$_') . "\n";
105             }
106 8 100       508 if ($type->is_a_type_of(Num)) {
107 5         390 $code .= "\$_ += 0;\n";
108             }
109              
110 8         4600 return $code;
111             }
112              
113             sub relationship {
114 7     4 1 3006 my $self = shift;
115              
116 8 50       58 if (@_ == 1) {
117 2         11 return $self->{relationship}{$_[0]};
118             }
119              
120 6         36 my ($type, $field, $other, %args) = @_;
121 6         61 my $class = 'Mandel::Relationship::' . Mojo::Util::camelize($type);
122 6         129 my $e = load_class $class;
123              
124 5 100       77 confess $e if ref $e;
125              
126 5         22 $self->{relationship}{$field}
127             = $class->new(accessor => $field, document_class => $self->document_class, related_class => $other, %args);
128             }
129              
130             sub new_collection {
131 4     5 1 21 my ($self, $connection, %args) = @_;
132              
133 4   100     15 $self->collection_class->new(
134             {connection => $connection || confess('$model->new_collection($connection)'), model => $self, %args});
135             }
136              
137             1;
138              
139             =encoding utf8
140              
141             =head1 NAME
142              
143             Mandel::Model - An object modelling a document
144              
145             =head1 DESCRIPTION
146              
147             This class is used to descrieb the structure of L
148             in mongodb.
149              
150             =head1 ATTRIBUTES
151              
152             =head2 collection_name
153              
154             The name of the collection in the database. Default is the plural form of L.
155              
156             =head2 collection_class
157              
158             The class name of the collection class. This default to L.
159              
160             =head2 document_class
161              
162             The class name of the document this description is attached to. Default to
163             an autogenerated class name.
164              
165             =head2 name
166              
167             The name of this model. Same as given to L and
168             L.
169              
170             =head1 METHODS
171              
172             =head2 field
173              
174             $field_obj = $self->field('name');
175             $self = $self->field(name => \%meta);
176             $self = $self->field(['name1', 'name2'], \%meta);
177              
178             Used to define new field(s) or retrieve a defined L
179             object.
180              
181             =head2 fields
182              
183             @fields = $self->fields;
184              
185             Get list of L objects in the order they were added to
186             thie model.
187              
188             =head2 relationship
189              
190             $rel_obj = $self->relationship($type => $accessor => 'Other::Document::Class', %args);
191             $rel_obj = $self->relationship($accessor);
192              
193             This method is used to describe a relationship between two documents.
194              
195             See L, L or
196             L.
197              
198             C<$accessor> will be used as l,
199             "Other::Document::Class" will be used as L
200             and C will be used as
201             L.
202              
203             C<%args> is passed on the the L constructor.
204              
205             =head2 new_collection
206              
207             $self->new_collection($connection);
208              
209             Returns a new instance of L.
210              
211             =head1 SEE ALSO
212              
213             L, L, L
214              
215             =head1 AUTHOR
216              
217             Jan Henning Thorsen - C
218              
219             =cut