Make sure order realiasing remains in proper sequence on sorting
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / CDBICompat / ColumnGroups.pm
CommitLineData
75d07914 1package # hide from PAUSE
c0e7b4e5 2 DBIx::Class::CDBICompat::ColumnGroups;
ea2e61bf 3
4use strict;
5use warnings;
ddc0a6c8 6use Sub::Name ();
96eab6f8 7use Storable 'dclone';
b818efd7 8use List::Util ();
96eab6f8 9
75a23b3e 10use base qw/DBIx::Class::Row/;
ea2e61bf 11
12__PACKAGE__->mk_classdata('_column_groups' => { });
13
ea2e61bf 14sub columns {
15 my $proto = shift;
16 my $class = ref $proto || $proto;
17 my $group = shift || "All";
e60dc79f 18 $class->_init_result_source_instance();
19
510ca912 20 $class->_add_column_group($group => @_) if @_;
ea2e61bf 21 return $class->all_columns if $group eq "All";
22 return $class->primary_column if $group eq "Primary";
b818efd7 23
24 my $grp = $class->_column_groups->{$group};
25 my @grp_cols = sort { $grp->{$b} <=> $grp->{$a} } (keys %$grp);
26 return @grp_cols;
ea2e61bf 27}
28
510ca912 29sub _add_column_group {
ea2e61bf 30 my ($class, $group, @cols) = @_;
c0eb27e8 31 $class->mk_group_accessors(column => @cols);
510ca912 32 $class->add_columns(@cols);
6a94f7f4 33 $class->_register_column_group($group => @cols);
ea2e61bf 34}
35
c0eb27e8 36sub add_columns {
37 my ($class, @cols) = @_;
38 $class->result_source_instance->add_columns(@cols);
39}
40
ea2e61bf 41sub _register_column_group {
42 my ($class, $group, @cols) = @_;
b8e1e21f 43
96eab6f8 44 # Must do a complete deep copy else column groups
45 # might accidentally be shared.
46 my $groups = dclone $class->_column_groups;
b8e1e21f 47
ea2e61bf 48 if ($group eq 'Primary') {
510ca912 49 $class->set_primary_key(@cols);
b818efd7 50 delete $groups->{'Essential'}{$_} for @cols;
51 my $first = List::Util::max(values %{$groups->{'Essential'}});
52 $groups->{'Essential'}{$_} = ++$first for reverse @cols;
ea2e61bf 53 }
54
ea2e61bf 55 if ($group eq 'All') {
510ca912 56 unless (exists $class->_column_groups->{'Primary'}) {
8eae3205 57 $groups->{'Primary'}{$cols[0]} = 1;
510ca912 58 $class->set_primary_key($cols[0]);
ea2e61bf 59 }
510ca912 60 unless (exists $class->_column_groups->{'Essential'}) {
8eae3205 61 $groups->{'Essential'}{$cols[0]} = 1;
ea2e61bf 62 }
63 }
64
b818efd7 65 delete $groups->{$group}{$_} for @cols;
66 my $first = List::Util::max(values %{$groups->{$group}});
67 $groups->{$group}{$_} = ++$first for reverse @cols;
b8e1e21f 68
ea2e61bf 69 $class->_column_groups($groups);
70}
71
8da46543 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 my($class, $name) = @_;
d4daee7b 84
8da46543 85 no strict 'refs';
86 my $existing_accessor = *{$class .'::'. $name}{CODE};
87 return $existing_accessor && !$our_accessors{$existing_accessor};
88 }
89
90 sub _deploy_accessor {
91 my($class, $name, $accessor) = @_;
92
93 return if $class->_has_custom_accessor($name);
94
95 {
96 no strict 'refs';
97 no warnings 'redefine';
ddc0a6c8 98 my $fullname = join '::', $class, $name;
99 *$fullname = Sub::Name::subname $fullname, $accessor;
8da46543 100 }
d4daee7b 101
8da46543 102 $our_accessors{$accessor}++;
103
104 return 1;
105 }
106}
107
108sub _mk_group_accessors {
109 my ($class, $type, $group, @fields) = @_;
110
111 # So we don't have to do lots of lookups inside the loop.
112 my $maker = $class->can($type) unless ref $type;
113
114 # warn "$class $type $group\n";
115 foreach my $field (@fields) {
116 if( $field eq 'DESTROY' ) {
117 carp("Having a data accessor named DESTROY in ".
118 "'$class' is unwise.");
119 }
120
121 my $name = $field;
122
123 ($name, $field) = @$field if ref $field;
124
125 my $accessor = $class->$maker($group, $field);
126 my $alias = "_${name}_accessor";
127
128 # warn " $field $alias\n";
129 {
130 no strict 'refs';
d4daee7b 131
8da46543 132 $class->_deploy_accessor($name, $accessor);
133 $class->_deploy_accessor($alias, $accessor);
134 }
135 }
136}
137
8c49f629 138sub all_columns { return shift->result_source_instance->columns; }
ea2e61bf 139
140sub primary_column {
141 my ($class) = @_;
103647d5 142 my @pri = $class->primary_columns;
ea2e61bf 143 return wantarray ? @pri : $pri[0];
144}
145
902133a3 146sub _essential {
147 return shift->columns("Essential");
148}
149
ea2e61bf 150sub find_column {
151 my ($class, $col) = @_;
103647d5 152 return $col if $class->has_column($col);
ea2e61bf 153}
154
155sub __grouper {
156 my ($class) = @_;
04786a4c 157 my $grouper = { class => $class };
158 return bless($grouper, 'DBIx::Class::CDBICompat::ColumnGroups::GrouperShim');
ea2e61bf 159}
160
161sub _find_columns {
162 my ($class, @col) = @_;
163 return map { $class->find_column($_) } @col;
164}
165
b24d86a1 166package # hide from PAUSE (should be harmless, no POD no Version)
167 DBIx::Class::CDBICompat::ColumnGroups::GrouperShim;
ea2e61bf 168
169sub groups_for {
170 my ($self, @cols) = @_;
171 my %groups;
172 foreach my $col (@cols) {
173 foreach my $group (keys %{$self->{class}->_column_groups}) {
174 $groups{$group} = 1 if $self->{class}->_column_groups->{$group}->{$col};
175 }
176 }
177 return keys %groups;
178}
ea2e61bf 179
1801;