1 package # hide from PAUSE
2 DBIx::Class::CDBICompat::ColumnGroups;
7 use base qw/DBIx::Class::Row/;
10 use DBIx::Class::_Util 'set_subname';
13 __PACKAGE__->mk_classdata('_column_groups' => { });
17 my $class = ref $proto || $proto;
18 my $group = shift || "All";
19 $class->_init_result_source_instance();
21 $class->_add_column_group($group => @_) if @_;
22 return $class->all_columns if $group eq "All";
23 return $class->primary_column if $group eq "Primary";
25 my $grp = $class->_column_groups->{$group};
26 my @grp_cols = sort { $grp->{$b} <=> $grp->{$a} } (keys %$grp);
30 sub _add_column_group {
31 my ($class, $group, @cols) = @_;
32 $class->mk_group_accessors(column => @cols);
33 $class->add_columns(@cols);
34 $class->_register_column_group($group => @cols);
38 my ($class, @cols) = @_;
39 $class->result_source_instance->add_columns(@cols);
42 sub _register_column_group {
43 my ($class, $group, @cols) = @_;
45 # Must do a complete deep copy else column groups
46 # might accidentally be shared.
47 my $groups = DBIx::Class::_Util::deep_clone( $class->_column_groups );
49 if ($group eq 'Primary') {
50 $class->set_primary_key(@cols);
51 delete $groups->{'Essential'}{$_} for @cols;
52 my $first = List::Util::max(values %{$groups->{'Essential'}});
53 $groups->{'Essential'}{$_} = ++$first for reverse @cols;
56 if ($group eq 'All') {
57 unless (exists $class->_column_groups->{'Primary'}) {
58 $groups->{'Primary'}{$cols[0]} = 1;
59 $class->set_primary_key($cols[0]);
61 unless (exists $class->_column_groups->{'Essential'}) {
62 $groups->{'Essential'}{$cols[0]} = 1;
66 delete $groups->{$group}{$_} for @cols;
67 my $first = List::Util::max(values %{$groups->{$group}});
68 $groups->{$group}{$_} = ++$first for reverse @cols;
70 $class->_column_groups($groups);
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.
78 # To make this work CDBICompat has decide if an accessor
79 # method was put there by itself and only then overwrite.
83 sub _has_custom_accessor {
84 my($class, $name) = @_;
87 my $existing_accessor = *{$class .'::'. $name}{CODE};
90 defined $existing_accessor
92 ! $our_accessors{$existing_accessor}
94 # under 5.8 mro the CODE slot may simply be a "cached method"
96 DBIx::Class::_ENV_::OLD_MRO
101 ($_->can($name)||0) == $existing_accessor
102 } @{mro::get_linear_isa($class)}
107 sub _deploy_accessor {
108 my($class, $name, $accessor) = @_;
110 return if $class->_has_custom_accessor($name);
114 no warnings 'redefine';
115 my $fullname = join '::', $class, $name;
116 *$fullname = set_subname $fullname, $accessor;
119 $our_accessors{$accessor}++;
125 sub _mk_group_accessors {
126 my ($class, $type, $group, @fields) = @_;
128 # So we don't have to do lots of lookups inside the loop.
129 my $maker = $class->can($type) unless ref $type;
131 # warn "$class $type $group\n";
132 foreach my $field (@fields) {
133 if( $field eq 'DESTROY' ) {
134 carp("Having a data accessor named DESTROY in ".
135 "'$class' is unwise.");
140 ($name, $field) = @$field if ref $field;
142 for( $name, "_${name}_accessor" ) {
143 $class->_deploy_accessor(
145 $class->$maker($group, $field, $_)
151 sub all_columns { return shift->result_source_instance->columns; }
155 my @pri = $class->primary_columns;
156 return wantarray ? @pri : $pri[0];
160 return shift->columns("Essential");
164 my ($class, $col) = @_;
165 return $col if $class->has_column($col);
170 my $grouper = { class => $class };
171 return bless($grouper, 'DBIx::Class::CDBICompat::ColumnGroups::GrouperShim');
175 my ($class, @col) = @_;
176 return map { $class->find_column($_) } @col;
179 package # hide from PAUSE (should be harmless, no POD no Version)
180 DBIx::Class::CDBICompat::ColumnGroups::GrouperShim;
183 my ($self, @cols) = @_;
185 foreach my $col (@cols) {
186 foreach my $group (keys %{$self->{class}->_column_groups}) {
187 $groups{$group} = 1 if $self->{class}->_column_groups->{$group}->{$col};