File Coverage

blib/lib/DBIx/Class/CDBICompat/ColumnGroups.pm
Criterion Covered Total %
statement 52 109 47.7
branch 4 28 14.2
condition 1 7 14.2
subroutine 14 25 56.0
pod 0 5 0.0
total 71 174 40.8


line stmt bran cond sub pod time code
1             package # hide from PAUSE
2             DBIx::Class::CDBICompat::ColumnGroups;
3              
4 2     2   870 use strict;
  2         5  
  2         50  
5 2     2   9 use warnings;
  2         4  
  2         48  
6              
7 2     2   9 use base qw/DBIx::Class::Row/;
  2         4  
  2         187  
8              
9 2     2   15 use List::Util ();
  2         5  
  2         46  
10 2     2   14 use DBIx::Class::_Util 'set_subname';
  2         5  
  2         190  
11 2     2   17 use namespace::clean;
  2         6  
  2         26  
12              
13             __PACKAGE__->mk_classdata('_column_groups' => { });
14              
15             sub columns :DBIC_method_is_bypassable_resultsource_proxy {
16 0     0 0 0 my $proto = shift;
17 0   0     0 my $class = ref $proto || $proto;
18 0   0     0 my $group = shift || "All";
19 0         0 $class->_init_result_source_instance();
20              
21 0 0       0 $class->_add_column_group($group => @_) if @_;
22 0 0       0 return $class->all_columns if $group eq "All";
23 0 0       0 return $class->primary_column if $group eq "Primary";
24              
25 0         0 my $grp = $class->_column_groups->{$group};
26 0         0 my @grp_cols = sort { $grp->{$b} <=> $grp->{$a} } (keys %$grp);
  0         0  
27 0         0 return @grp_cols;
28 2     2   795 }
  2         6  
  2         14  
29              
30             sub _add_column_group {
31 0     0   0 my ($class, $group, @cols) = @_;
32 0         0 $class->mk_group_accessors(column => @cols);
33 0         0 $class->add_columns(@cols);
34 0         0 $class->_register_column_group($group => @cols);
35             }
36              
37             sub add_columns :DBIC_method_is_bypassable_resultsource_proxy {
38 0     0 0 0 my ($class, @cols) = @_;
39 0         0 $class->result_source->add_columns(@cols);
40 2     2   489 }
  2         5  
  2         8  
41              
42             sub _register_column_group {
43 0     0   0 my ($class, $group, @cols) = @_;
44              
45             # Must do a complete deep copy else column groups
46             # might accidentally be shared.
47 0         0 my $groups = DBIx::Class::_Util::deep_clone( $class->_column_groups );
48              
49 0 0       0 if ($group eq 'Primary') {
50 0         0 $class->set_primary_key(@cols);
51 0         0 delete $groups->{'Essential'}{$_} for @cols;
52 0         0 my $first = List::Util::max(values %{$groups->{'Essential'}});
  0         0  
53 0         0 $groups->{'Essential'}{$_} = ++$first for reverse @cols;
54             }
55              
56 0 0       0 if ($group eq 'All') {
57 0 0       0 unless (exists $class->_column_groups->{'Primary'}) {
58 0         0 $groups->{'Primary'}{$cols[0]} = 1;
59 0         0 $class->set_primary_key($cols[0]);
60             }
61 0 0       0 unless (exists $class->_column_groups->{'Essential'}) {
62 0         0 $groups->{'Essential'}{$cols[0]} = 1;
63             }
64             }
65              
66 0         0 delete $groups->{$group}{$_} for @cols;
67 0         0 my $first = List::Util::max(values %{$groups->{$group}});
  0         0  
68 0         0 $groups->{$group}{$_} = ++$first for reverse @cols;
69              
70 0         0 $class->_column_groups($groups);
71             }
72              
73             # CDBI will never overwrite an accessor, but it only uses one
74             # accessor for all column types. DBIC uses many different
75             # accessor types so, for example, if you declare a column()
76             # and then a has_a() for that same column it must overwrite.
77             #
78             # To make this work CDBICompat has decide if an accessor
79             # method was put there by itself and only then overwrite.
80             {
81             my %our_accessors;
82              
83             sub _has_custom_accessor {
84 4     4   7 my($class, $name) = @_;
85              
86 2     2   908 no strict 'refs';
  2         6  
  2         300  
87 4         6 my $existing_accessor = *{$class .'::'. $name}{CODE};
  4         27  
88              
89             return(
90             defined $existing_accessor
91             and
92             ! $our_accessors{$existing_accessor}
93             and
94             # under 5.8 mro the CODE slot may simply be a "cached method"
95             ! (
96             DBIx::Class::_ENV_::OLD_MRO
97             and
98             grep {
99             $_ ne $class
100             and
101             ( $Class::C3::MRO{$_} || {} )->{methods}{$name}
102 4   50     27 } @{mro::get_linear_isa($class)}
103             )
104             )
105             }
106              
107             sub _deploy_accessor {
108 4     4   1064 my($class, $name, $accessor) = @_;
109              
110 4 50       13 return if $class->_has_custom_accessor($name);
111              
112             {
113 2     2   13 no strict 'refs';
  2         3  
  2         56  
  4         10  
114 2     2   10 no warnings 'redefine';
  2         4  
  2         924  
115 4         14 my $fullname = join '::', $class, $name;
116 4         17 *$fullname = set_subname $fullname, $accessor;
117             }
118              
119 4         18 $our_accessors{$accessor}++;
120              
121 4         14 return 1;
122             }
123             }
124              
125             sub _mk_group_accessors {
126 2     2   54 my ($class, $type, $group, @fields) = @_;
127              
128             # So we don't have to do lots of lookups inside the loop.
129 2 50       27 my $maker = $class->can($type) unless ref $type;
130              
131             # warn "$class $type $group\n";
132 2         5 foreach my $field (@fields) {
133 2 50       7 if( $field eq 'DESTROY' ) {
134 0         0 carp("Having a data accessor named DESTROY in ".
135             "'$class' is unwise.");
136             }
137              
138 2         4 my $name = $field;
139              
140 2 50       7 ($name, $field) = @$field if ref $field;
141              
142 2         5 for( $name, "_${name}_accessor" ) {
143 4         13 $class->_deploy_accessor(
144             $_,
145             $class->$maker($group, $field, $_)
146             );
147             }
148             }
149             }
150              
151 0     0 0   sub all_columns { return shift->result_source->columns; }
152              
153             sub primary_column {
154 0     0 0   my ($class) = @_;
155 0           my @pri = $class->primary_columns;
156 0 0         return wantarray ? @pri : $pri[0];
157             }
158              
159             sub _essential {
160 0     0     return shift->columns("Essential");
161             }
162              
163             sub find_column {
164 0     0 0   my ($class, $col) = @_;
165 0 0         return $col if $class->has_column($col);
166             }
167              
168             sub __grouper {
169 0     0     my ($class) = @_;
170 0           my $grouper = { class => $class };
171 0           return bless($grouper, 'DBIx::Class::CDBICompat::ColumnGroups::GrouperShim');
172             }
173              
174             sub _find_columns {
175 0     0     my ($class, @col) = @_;
176 0           return map { $class->find_column($_) } @col;
  0            
177             }
178              
179             package # hide from PAUSE (should be harmless, no POD no Version)
180             DBIx::Class::CDBICompat::ColumnGroups::GrouperShim;
181              
182             sub groups_for {
183 0     0     my ($self, @cols) = @_;
184 0           my %groups;
185 0           foreach my $col (@cols) {
186 0           foreach my $group (keys %{$self->{class}->_column_groups}) {
  0            
187 0 0         $groups{$group} = 1 if $self->{class}->_column_groups->{$group}->{$col};
188             }
189             }
190 0           return keys %groups;
191             }
192              
193             1;