File Coverage

blib/lib/DBIx/DataModel/Meta/Source/Table.pm
Criterion Covered Total %
statement 74 85 87.0
branch 18 26 69.2
condition 3 6 50.0
subroutine 19 22 86.3
pod 0 8 0.0
total 114 147 77.5


line stmt bran cond sub pod time code
1             package DBIx::DataModel::Meta::Source::Table;
2 16     16   9311 use strict;
  16         40  
  16         744  
3 16     16   105 use warnings;
  16         34  
  16         466  
4 16     16   97 use parent "DBIx::DataModel::Meta::Source";
  16         32  
  16         92  
5 16     16   1088 use DBIx::DataModel;
  16         41  
  16         116  
6 16     16   142 use DBIx::DataModel::Meta::Utils qw/define_method does/;
  16         42  
  16         997  
7 16     16   113 use Params::Validate qw/HASHREF ARRAYREF SCALAR/;
  16         36  
  16         986  
8 16     16   101 use List::MoreUtils qw/any/;
  16         49  
  16         140  
9 16     16   11363 use Carp::Clan qw[^(DBIx::DataModel::|SQL::Abstract)];
  16         35  
  16         103  
10              
11 16     16   1589 use namespace::clean;
  16         59  
  16         114  
12              
13              
14              
15             sub new {
16 50     50 0 106 my $class = shift;
17              
18             # the real work occurs in parent class
19 50         564 my $self = $class->_new_meta_source(
20              
21             # more spec for Params::Validate
22             { column_types => {type => HASHREF, default => {}},
23             column_handlers => {type => HASHREF, default => {}},
24             db_name => {type => SCALAR},
25             where => {type => HASHREF|ARRAYREF, optional => 1},
26              
27             auto_insert_columns => {type => HASHREF, default => {}},
28             auto_update_columns => {type => HASHREF, default => {}},
29             no_update_columns => {type => HASHREF, default => {}},
30              
31             },
32              
33             # method to call in schema for building @ISA
34             'table_parent',
35              
36             # original args
37             @_
38             );
39              
40 50         307 my $types = delete $self->{column_types};
41 50         224 while (my ($type_name, $columns_aref) = each %$types) {
42 0         0 $self->define_column_type($type_name, @$columns_aref);
43             }
44              
45 50         159 return $self;
46             }
47              
48              
49             sub db_from {
50 384     384 0 735 my $self = shift;
51 384         1068 return $self->{db_name};
52             }
53              
54              
55             sub where {
56 0     0 0 0 my $self = shift;
57              
58 0         0 return $self->{where};
59             }
60              
61             sub components {
62 38     38 0 79 my $self = shift;
63              
64 38 100       60 return @{$self->{components} || []};
  38         220  
65             }
66              
67              
68              
69             sub define_navigation_method {
70 62     62 0 173 my ($self, $method_name, @path) = @_;
71 62 50       217 @path or croak "define_navigation_method: not enough arguments";
72              
73             # last arg may be a hashref of parameters to be passed to select()
74 62         97 my $pre_args;
75 62 100       169 $pre_args = pop @path if ref $path[-1];
76              
77             # build the method body
78             my $method_body = sub {
79 24     24   56072 my ($self, @args) = @_;
80              
81             # if called without args, and just one role, and that role
82             # was previously expanded, then return the cached version
83 24 100 100     155 if (@path == 1 && !@args) {
84 8         34 my $cached = $self->{$path[0]};
85 8 100       39 return $cached if $cached;
86             }
87              
88             # otherwise, build a query
89 22 100       65 unshift @args, %$pre_args if $pre_args;
90 22         120 my $statement = $self->join(@path); # Source::join, not Schema::join
91              
92             # return either the resulting rows, or the query statement
93 20 100       57 return $self->_is_called_as_class_method
94             ? $statement->refine(@args) # when class method
95             : $statement->select(@args); # when instance method
96 62         264 };
97              
98             # install the method
99             define_method(
100             class => $self->{class},
101 62         247 name => $method_name,
102             body => $method_body,
103             );
104             }
105              
106              
107             sub define_column_type {
108 9     9 0 32 my ($self, $type_name, @columns) = @_;
109              
110 9 50       34 my $type = $self->{schema}->type($type_name)
111             or croak "unknown column type : $type_name";
112              
113 9         26 foreach my $column (@columns) {
114 14         25 $self->define_column_handlers($column, %{$type->{handlers}})
  14         46  
115             }
116              
117 9         22 return $self;
118             }
119              
120              
121             sub define_column_handlers {
122 17     17 0 51 my ($self, $column_name, %handlers) = @_;
123              
124 17         58 while (my ($handler_name, $body) = each %handlers) {
125 37         59 my $handler = $body;
126 37         77 my $previous = $self->{column_handlers}{$column_name}{$handler_name};
127 37 100       72 if ($previous) {
128             # compose new coderef with previous coderef
129             $handler
130 0     0   0 = $handler_name eq 'from_DB' ? sub {$body->(@_); $previous->(@_)}
  0         0  
131 1 50   1   9 : sub {$previous->(@_); $body->(@_)};
  1         4  
  1         20  
132             }
133 37         116 $self->{column_handlers}{$column_name}{$handler_name} = $handler;
134             }
135              
136 17         45 return $self;
137             }
138              
139              
140             sub define_auto_expand {
141 3     3 0 17 my ($self, @component_names) = @_;
142              
143             # check that we only auto_expand on components
144 3         14 my @components = $self->components;
145 3         9 foreach my $component_name (@component_names) {
146 3     3   18 any {$component_name eq $_} @components
147 3 50       20 or croak "cannot auto_expand on $component_name: not a composition";
148             }
149              
150             # closure to iterate on the components
151             my $body = sub {
152 0     0   0 my ($self, $want_recurse) = @_;
153 0         0 foreach my $component_name (@component_names) {
154 0         0 my $r = $self->expand($component_name); # result can be an object ref
155             # or an array ref
156 0 0 0     0 if ($r and $want_recurse) {
157 0 0       0 $r = [$r] unless does($r, 'ARRAY');
158 0         0 $_->auto_expand($want_recurse) foreach @$r;
159             }
160             }
161 3         22 };
162              
163             # install the method
164             define_method(
165             class => $self->{class},
166 3         18 name => 'auto_expand',
167             body => $body,
168             check_override => 0,
169             );
170              
171 3         13 return $self;
172             }
173              
174              
175             1;
176