File Coverage

blib/lib/SQL/Abstract/Plugin/TableAlias.pm
Criterion Covered Total %
statement 167 173 96.5
branch 51 66 77.2
condition 36 60 60.0
subroutine 16 16 100.0
pod 0 1 0.0
total 270 316 85.4


line stmt bran cond sub pod time code
1             package SQL::Abstract::Plugin::TableAlias;
2 3     3   725821 use strict; use warnings; our $VERSION = '0.05';
  3     3   12  
  3         168  
  3         20  
  3         7  
  3         318  
3 3     3   2125 use Moo;
  3         34573  
  3         18  
4              
5             with 'SQL::Abstract::Role::Plugin';
6              
7             sub register_extensions {
8 2     2 0 2764 my ($self, $sqla) = @_;
9 2         29 $sqla->plugin('+ExtraClauses');
10             $sqla->wrap_expander(select => sub {
11 2     2   140 $self->cb('_alias_select', $_[0]);
12 2         31567 });
13             }
14              
15             sub _alias_select {
16 31     31   288274 my ($self, $orig, $select, $args) = @_;
17 31 50 33     324 $args = $self->_alias_from_array($args) if (ref $args eq 'HASH' && ref $args->{from} eq 'ARRAY');
18 31         209 return $self->sqla->$orig($select, $args);
19             }
20              
21             sub _alias_from_array {
22 31     31   85 my ($self, $args) = @_;
23              
24 31   100     184 $args->{talias} ||= [];
25              
26 31         100 my ($i, @map, %columns) = 0;
27 31         69 for my $from (@{ $args->{from} }) {
  31         96  
28 96   100     424 my $ref = ref $from || "";
29 96 100 66     625 if ( $ref eq 'HASH' ) {
    100          
    100          
30 26 50       96 if ($from->{to}) {
31 26 100 33     107 $from->{as} ||= scalar @{$args->{talias}} ? shift(@{$args->{talias}}) : ref $from->{to} ? $from->{to}->{-ident}->[0] : $from->{to};
  26 100       174  
  13         82  
32 26         69 push @map, $from->{as};
33 26 50       105 if ($from->{on}) {
34 26 100       76 if ($from->{on}->{-op}) {
35 2 50       5 if (scalar @{$from->{on}->{-op}->[1]->{-ident}} == 1) {
  2         9  
36 2         5 unshift @{$from->{on}{-op}[1]{-ident}}, $map[-2];
  2         11  
37             }
38 2 50       6 if (scalar @{$from->{on}->{-op}->[2]->{-ident}} == 1) {
  2         8  
39 2         4 unshift @{$from->{on}{-op}[2]{-ident}}, $map[-1];
  2         9  
40             }
41             } else {
42 24         47 for my $on (keys %{$from->{on}}) {
  24         96  
43 24 50       100 if (ref $from->{on}->{$on}) {
44 24         43 for my $oo (keys %{$from->{on}->{$on}}) {
  24         118  
45 24         117 $from->{on}->{$on}->{$oo} = sprintf("%s.%s", $map[-1], $from->{on}->{$on}->{$oo});
46             }
47             }
48 24         133 $from->{on}->{sprintf("%s.%s", $map[-2], $on)} = delete $from->{on}->{$on};
49             }
50             }
51             }
52             } else {
53             push @map, $from->{$_}->{-as} ||= shift(@{$args->{talias}}) || $_
54 0   0     0 for ( sort keys %{ $from } );
  0   0     0  
55             }
56             } elsif ($ref eq 'ARRAY') {
57 3 50       14 if ($from->[1] eq 'as') {
58 0         0 push @map, $from->[2];
59             } else {
60 3   66     8 push @map, shift @{$args->{talias}} || $from->[0];
61 3         7 splice @{$from}, 1, 0, 'as', $map[-1];
  3         19  
62             }
63 3         8 for my $key ( keys %{ $from->[-1] } ) {
  3         12  
64 3         18 $from->[-1]->{_valid_column($key, $map[-2], {})} = _valid_column(delete $from->[-1]->{$key}, $map[-1], {});
65             }
66             } elsif (!$ref && $from !~ m/^-/) {
67 38   66     83 push @map, shift @{$args->{talias}} || $from;
68 38         71 splice @{$args->{from}}, $i, 1, { $from => { 'as' => $map[-1] } };
  38         225  
69             }
70 96         235 $i++;
71             }
72              
73             ($args, %columns) = $self->_alias_select_array($args, \@map)
74 31 50 50     218 if ((ref($args->{select}) || "") eq 'ARRAY');
75            
76 31         107 my $where = ref $args->{where};
77 31 100 66     153 $where eq 'HASH'
78             ? $self->_alias_where_hash($args, $map[0], \%columns)
79             : $where eq 'ARRAY' && $self->_alias_where_array($args, $map[0], \%columns);
80              
81 31         107 my $order_by = ref $args->{order_by};
82             $order_by eq 'HASH'
83             ? $self->_alias_order_by_hash($args, $map[0], \%columns)
84             : $order_by eq 'ARRAY'
85             ? $self->_alias_order_by_array($args, $map[0], \%columns)
86 31 100 66     257 : defined $args->{order_by} && ! ref $order_by && $self->_alias_order_by_string($args, $map[0], \%columns);
    100          
87              
88 31         75 my $group_by = ref $args->{group_by};
89 31 100 66     146 $group_by eq 'ARRAY'
90             ? $self->_alias_group_by_array($args, $map[0], \%columns)
91             : $group_by eq 'HASH' && $self->_alias_group_by_hash($args, $map[0], \%columns);
92              
93 31         128 return $args;
94             }
95              
96             sub _alias_select_array {
97 31     31   85 my ($self, $args, $map) = @_;
98 31         132 my ($i, $last_array, @select, %columns) = -1;
99 31         58 for my $sel ( @{ $args->{select} } ) {
  31         85  
100 122         248 my $ref = ref $sel;
101 122 100       401 if ( $ref eq 'ARRAY' ) {
    100          
    50          
102 33         61 $i++;
103 33         79 for (my $l = 0; $l < scalar @{$sel}; $l++) {
  77         206  
104 44 100 100     186 if (ref($sel->[$l]) || "" eq "HASH") {
105 1         3 for my $key ( keys %{ $sel->[$l] } ) {
  1         4  
106 1         33 $sel->[$l]{_valid_column($key, $map->[$i], {})} = delete $sel->[$l]{$key};
107 1         5 $columns{$key} = $map->[$i];
108             }
109 1         4 push @select, $sel->[$l];
110             } else {
111 43         166 $columns{$sel->[$l]} = $map->[$i];
112 43         159 push @select, sprintf("%s.%s", $map->[$i], $sel->[$l]);
113             }
114             }
115 33         102 $last_array = 1;
116             } elsif ( $ref eq 'HASH' ) {
117 2 50 33     11 $i++ if $i < 0 || $last_array && do { $last_array = 0; 1; };
  0   66     0  
  0         0  
118 2         5 for my $key ( keys %{ $sel } ) {
  2         7  
119 2         8 $sel->{_valid_column($key, $map->[$i], {})} = delete $sel->{$key};
120 2         8 $columns{$key} = $map->[$i];
121             }
122 2         6 push @select, $sel;
123             } elsif (! $ref) {
124 87 50 66     299 $i++ if $i < 0 || $last_array && do { $last_array = 0; 1; };
  4   100     9  
  4         28  
125 87         255 $columns{$sel} = $map->[$i];
126 87         328 push @select, sprintf("%s.%s", $map->[$i], $sel);
127             }
128             }
129 31         117 $args->{select} = \@select;
130 31         233 return ($args, %columns);
131             }
132              
133             sub _alias_where_hash {
134 17     17   47 my ($self, $args, $default, $columns) = @_;
135 17         30 my %where;
136 17         29 for my $w (keys %{ $args->{where} }) {
  17         59  
137 39 50 33     161 if (ref $args->{$w} eq 'HASH' && $args->{$w}->{-alias}) {
138 0         0 $where{sprintf("%s.%s", delete $args->{where}->{$w}->{-alias}, $w)} = $args->{where}->{$w};
139             } else {
140 39         132 $where{_valid_column($w, $default, $columns)} = $args->{where}->{$w};
141             }
142             }
143 17         49 $args->{where} = \%where;
144 17         58 return $args;
145             }
146              
147             sub _alias_where_array {
148 6     6   20 my ($self, $args, $default, $columns) = @_;
149 6 100       15 my $list = grep { $_ % 2 > 0 && $args->{where}->[$_] =~ m/-(and|or)/ } 0 .. scalar @{ $args->{where} };
  22         107  
  6         21  
150 6 50       24 return $self->_alias_where_list($args, $default, $columns) if $list;
151 6         17 for my $where (@{ $args->{where} }) {
  6         20  
152 16   100     59 my $ref = ref $where || "";
153 16 100       42 if ( $ref eq 'HASH' ) {
154 12         48 my $update = $self->_alias_where_hash({ where => $where }, $default, $columns);
155 12         25 %{$where} = %{$update->{where}};
  12         68  
  12         31  
156             }
157             }
158 6         16 return $args;
159             }
160              
161             sub _alias_order_by_hash {
162 9     9   25 my ($self, $args, $default, $columns) = @_;
163 9         14 my %order_by;
164 9         16 for my $w (keys %{ $args->{order_by} }) {
  9         27  
165 9         26 my $ref = ref $args->{order_by}->{$w};
166 9 100       41 if ($ref eq 'ARRAY') {
    50          
167 5         8 my @order;
168 5         9 for my $o ( @{ $args->{order_by}->{$w} } ) {
  5         17  
169 10         24 push @order, _valid_column($o, $default, $columns);
170             }
171 5         17 $order_by{$w} = \@order;
172             } elsif ( ! $ref ) {
173 4         15 $order_by{$w} = _valid_column($args->{order_by}{$w}, $default, $columns);
174             }
175             }
176 9         23 $args->{order_by} = \%order_by;
177 9         20 return $args;
178             }
179              
180             sub _alias_order_by_array {
181 6     6   20 my ($self, $args, $default, $columns) = @_;
182 6         18 my $i = 0;
183 6         14 for my $w ( @{ $args->{order_by} }) {
  6         19  
184 16   100     55 my $ref = ref $w || "";
185 16 100       36 if ($ref eq 'HASH') {
186 8         35 my $new = $self->_alias_order_by_hash({ order_by => $w }, $default, $columns);
187 8         14 %{$w} = %{$new->{order_by}};
  8         31  
  8         34  
188             } else {
189 8         23 $args->{order_by}->[$i] = _valid_column($w, $default, $columns);
190             }
191 16         41 $i++;
192             }
193 6         17 return $args;
194             }
195              
196             sub _alias_order_by_string {
197 12     12   32 my ($self, $args, $default, $columns) = @_;
198 12         58 $args->{order_by} = _valid_column($args->{order_by}, $default, $columns);
199             }
200              
201             sub _alias_group_by_array {
202 5     5   15 my ($self, $args, $default, $columns) = @_;
203 5         22 my @group_by;
204 5         25 for my $group (@{ $args->{group_by} }) {
  5         14  
205 7         23 push @group_by, _valid_column($group, $default, $columns);
206             }
207 5         14 $args->{group_by} = \@group_by;
208 5         12 return $args;
209             }
210              
211             sub _alias_group_by_hash {
212 2     2   8 my ($self, $args, $default, $columns) = @_;
213 2         6 my @group_by = shift @{ $args->{group_by}->{-op} };
  2         10  
214 2         6 for my $group (@{ $args->{group_by}->{-op} }) {
  2         7  
215             $group->{-ident} = ref $group->{-ident} ? [map {
216 4         12 _valid_column($_, $default, $columns);
217 4 50       15 } @{$group->{-ident}}] : _valid_column($group->{-ident}, $default, $columns);
  4         11  
218 4         12 push @group_by, $group;
219             }
220 2         21 $args->{group_by}->{-op} = \@group_by;
221 2         6 return $args;
222             }
223              
224             sub _valid_column {
225 93     93   215 my ($column, $default, $columns) = @_;
226 93 100       351 return $column if ($column =~ m/[^.]+\W+/);
227 92   66     619 return sprintf( "%s.%s", ($columns->{$column} || $default), $column);
228             }
229              
230             1;
231              
232             __END__