File Coverage

blib/lib/SQL/OrderBy.pm
Criterion Covered Total %
statement 53 53 100.0
branch 39 44 88.6
condition 10 12 83.3
subroutine 7 7 100.0
pod 4 4 100.0
total 113 120 94.1


line stmt bran cond sub pod time code
1             package SQL::OrderBy;
2             our $AUTHORITY = 'cpan:GENE';
3              
4             # ABSTRACT: Transform an SQL "order by" clause
5              
6 1     1   723 use strict;
  1         2  
  1         29  
7 1     1   5 use warnings;
  1         2  
  1         877  
8              
9             our $VERSION = '0.1000';
10              
11             # Transform an order by clause.
12             sub toggle_resort {
13 12     12 1 4267 my %args = @_;
14              
15             # Set the column name list and the directions.
16 12         34 my ($columns, $direction, $asc_desc) = get_columns(
17             %args,
18             name_direction => 1,
19             numeric_direction => 1,
20             );
21              
22             # Handle a selected column.
23 12 50       29 if (my $name = $args{selected}) {
24 12         24 ($name, $direction, $asc_desc) = _name_direction(
25             $name, $direction, $asc_desc
26             );
27              
28             # Toggle if the selected column was already the first one.
29 12 100 66     62 if ($columns && @$columns && $name eq $columns->[0]) {
      100        
30 2 50       7 $direction->{$name} = $direction->{$name} + 0 ? 0 : 1;
31             }
32              
33             # Remove the selected column name from its old position.
34 12         24 @$columns = grep { $_ ne $name } @$columns;
  30         106  
35             # And add the selected column name to the beginning.
36 12         30 unshift @$columns, $name;
37             }
38              
39             # Convert from numeric, if asked to.
40             %$direction = to_asc_desc ($direction, %args)
41 12 50       38 unless $args{numeric_direction};
42              
43             # Fetch our "name direction" array.
44 12         29 @$columns = col_dir_list ($columns, $direction);
45              
46             # Return the column ordering as an arrayref or string.
47 12 100       74 return wantarray ? @$columns : join ', ', @$columns;
48             }
49              
50             # Return the column names and directions as either hash/array
51             # references, or a column array, or an "order by" clause.
52             sub get_columns {
53 20     20 1 5399 my %args = @_;
54              
55             # Set the order array from the order_by argument.
56 20         31 my @order;
57 20 100       46 if (ref $args{order_by} eq 'ARRAY') {
58 5         8 @order = @{ $args{order_by} };
  5         12  
59             # warn "Empty order list provided." unless @order;
60             }
61             else {
62 15 100       29 if ($args{order_by}) {
63             # Strip off any unneeded SQL clauses.
64 12         62 $args{order_by} =~ s/^.*?\border by\s+(.*)$/$1/i;
65             # Split the order clause.
66 12         69 @order = split /\s*,\s*/, $args{order_by};
67             }
68             else {
69 3         6 @order = ();
70             # warn "No statement or clause provided.\n" unless $args{order_by};
71             }
72             }
73              
74             # Hold column names and directions.
75 20         35 my ($columns, $direction, $asc_desc);
76              
77             # Set the column array and direction hashes.
78 20         35 for (@order) {
79 48         84 (my $name, $direction, $asc_desc) = _name_direction(
80             $_, $direction, $asc_desc
81             );
82              
83             # Add the column to our columns array.
84 48         111 push @$columns, $name;
85             }
86              
87             # Make alpha directions if asked to.
88             %$direction = to_asc_desc ($asc_desc, %args)
89 20 100       60 unless $args{numeric_direction};
90              
91             # NOTE: name_direction only makes sense in an array context.
92 20 100       36 if ($args{name_direction}) {
93 14         27 $columns = [ $columns, $direction, $asc_desc ];
94             }
95             else {
96 6         11 @$columns = col_dir_list ($columns, $direction);
97             }
98              
99 20 100       94 return wantarray ? @$columns : join ', ', @$columns;
100             }
101              
102             # Return an array of column names with their respective directions
103             # concatenated. This is conditional concatenation. ASC/DESC vs.
104             # 1/0 issues do not concern us here.
105             sub col_dir_list {
106 19     19 1 622 my ($columns, $direction) = @_;
107             return map {
108 19 100       34 $direction->{$_}
  49         141  
109             ? "$_ $direction->{$_}"
110             : $_
111             } @$columns;
112             }
113              
114             # Return alpha directions in place of numeric eqivalents.
115             sub to_asc_desc {
116 21     21 1 1124 my $dir = shift;
117 21         44 my %args = @_;
118              
119             # Set default direction strings.
120             my ($asc, $desc) = $args{uc_direction}
121 21 100       50 ? ('ASC', 'DESC') : ('asc', 'desc');
122              
123             # Replace directions with "proper" values.
124 21         61 for (keys %$dir) {
125             # From numeric
126 55 100 66     232 if (defined $dir->{$_} && $dir->{$_} =~ /^\d+$/) {
127             $dir->{$_} = $dir->{$_}
128 40 100       112 ? $args{show_ascending} ? $asc : ''
    100          
129             : $desc;
130             }
131             # Use existing if present, ascend otherwise.
132             else {
133             $dir->{$_} = $dir->{$_}
134             ? lc ($dir->{$_}) eq 'desc'
135             ? $dir->{$_}
136             : $args{show_ascending} ? $dir->{$_} : ''
137 15 50       44 : $args{show_ascending} ? $asc : ''
    100          
    100          
    100          
138             }
139             }
140              
141 21         89 return %$dir;
142             }
143              
144             sub _name_direction {
145 60     60   101 my ($col, $direction, $asc_desc) = @_;
146              
147 60 50       278 if ($col =~ /^(.*?)(?:\s+(asc|desc))?$/i) {
148             # Use the direction provided; Ascend by default.
149 60         154 ($col, my $dir) = ($1, $2);
150             # Set the numeric directions.
151 60 100 100     180 $direction->{$col} = $dir && lc ($dir) eq 'desc' ? 0 : 1;
152             # Set the case sensitive alpha directions.
153 60 100       127 $asc_desc->{$col} = $dir ? $dir : '';
154             }
155              
156 60         125 return $col, $direction, $asc_desc;
157             }
158              
159             1;
160              
161             __END__