File Coverage

blib/lib/DBIx/Class/CDBICompat/ColumnGroups.pm
Criterion Covered Total %
statement 52 109 47.7
branch 4 28 14.2
condition 1 8 12.5
subroutine 13 24 54.1
pod 0 5 0.0
total 70 174 40.2


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