From: Dagfinn Ilmari Mannsåker Date: Sat, 26 Jan 2013 19:55:38 +0000 (+0000) Subject: Add support for NULLS FIRST/LAST in ORDER BY X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=dbsrgits%2FSQL-Abstract.git;a=commitdiff_plain;h=36e3ea6ca294fa0c1a32cefa39ec23146498faf0 Add support for NULLS FIRST/LAST in ORDER BY --- diff --git a/Changes b/Changes index 674d881..59487f2 100644 --- a/Changes +++ b/Changes @@ -7,6 +7,7 @@ Revision history for SQL::Abstract - Fix incorrect reporting of mismatch-members in SQLA::Test - Migrate the -ident operator from DBIC into SQLA - Migrate the -value operator from DBIC into SQLA + - Add support for NULLS FIRST/LAST in ORDER BY revision 1.72 2010-12-21 ---------------------------- diff --git a/lib/SQL/Abstract/Converter.pm b/lib/SQL/Abstract/Converter.pm index 8779cce..1f5414b 100644 --- a/lib/SQL/Abstract/Converter.pm +++ b/lib/SQL/Abstract/Converter.pm @@ -200,7 +200,7 @@ sub _select_to_dq { my $ordered_dq = do { if ($order) { - $self->_order_by_to_dq($order, undef, $source_dq); + $self->_order_by_to_dq($order, undef, undef, $source_dq); } else { $source_dq } @@ -517,13 +517,14 @@ sub _where_hashpair_to_dq { } sub _order_by_to_dq { - my ($self, $arg, $dir, $from) = @_; + my ($self, $arg, $dir, $nulls, $from) = @_; return unless $arg; my $dq = Order( undef, (defined($dir) ? (!!($dir =~ /desc/i)) : undef), + (defined($nulls) ? ($nulls =~ /first/i ? 1 : -1) : undef), ($from ? ($from) : undef), ); @@ -536,7 +537,7 @@ sub _order_by_to_dq { my ($outer, $inner); foreach my $member (@$arg) { local $Order_Inner; - my $next = $self->_order_by_to_dq($member, $dir, $from); + my $next = $self->_order_by_to_dq($member, $dir, $nulls, $from); $outer ||= $next; $inner->{from} = $next if $inner; $inner = $Order_Inner || $next; @@ -564,15 +565,27 @@ sub _order_by_to_dq { $dq->{by} = $self->_literal_to_dq($$arg); } } elsif (ref($arg) eq 'HASH') { - my ($key, $val, @rest) = %$arg; + return () unless %$arg; + + my ($direction, $val); + foreach my $key (keys %$arg) { + if ( $key =~ /^-(desc|asc)/i ) { + die "hash passed to _order_by_to_dq must have exactly one of -desc or -asc" + if defined $direction; + $direction = $1; + $val = $arg->{$key}; + } elsif ($key =~ /^-nulls$/i) { + $nulls = $arg->{$key}; + die "invalid value for -nulls" unless $nulls =~ /^(?:first|last)$/; + } else { + die "invalid key in hash passed to _order_by_to_dq"; + } + } - return unless $key; + die "hash passed to _order_by_to_dq must have exactly one of -desc or -asc" + unless defined $direction; - if (@rest or not $key =~ /^-(desc|asc)/i) { - die "hash passed to _order_by must have exactly one key (-desc or -asc)"; - } - my $dir = uc $1; - return $self->_order_by_to_dq($val, $dir, $from); + return $self->_order_by_to_dq($val, $direction, $nulls, $from); } else { die "Can't handle $arg in _order_by_to_dq"; } diff --git a/t/06order_by.t b/t/06order_by.t index 25a4f32..2b3b13f 100644 --- a/t/06order_by.t +++ b/t/06order_by.t @@ -104,10 +104,25 @@ my @cases = expects_quoted => ' ORDER BY colA, colB LIKE ? DESC, colC LIKE ?', bind => [qw/test tost/], }, + { + given => [ { -asc => 'colA', -nulls => 'first' }, { -desc => 'colB', -nulls => 'last' } ], + expects => ' ORDER BY colA NULLS FIRST, colB DESC NULLS LAST', + expects_quoted => ' ORDER BY `colA` NULLS FIRST, `colB` DESC NULLS LAST', + }, + { + given => [ { -asc => 'colA', -nulls => 'first' }, { -desc => 'colB', -nulls => 'last' } ], + expects => ' ORDER BY colA NULLS FIRST, colB DESC NULLS LAST', + expects_quoted => ' ORDER BY `colA` NULLS FIRST, `colB` DESC NULLS LAST', + }, + { + given => { -asc => [qw/colA colB/], -nulls => 'first' } , + expects => ' ORDER BY colA NULLS FIRST, colB NULLS FIRST', + expects_quoted => ' ORDER BY `colA` NULLS FIRST, `colB` NULLS FIRST', + }, ); -plan tests => (scalar(@cases) * 2) + 2; +plan tests => (scalar(@cases) * 2) + 4; my $sql = SQL::Abstract->new; my $sqlq = SQL::Abstract->new({quote_char => '`'}); @@ -134,12 +149,24 @@ for my $case( @cases) { throws_ok ( sub { $sql->_order_by({-desc => 'colA', -asc => 'colB' }) }, - qr/hash passed .+ must have exactly one key/, + qr/hash passed .+ must have exactly one of/, 'Undeterministic order exception', ); throws_ok ( sub { $sql->_order_by({-desc => [ qw/colA colB/ ], -asc => [ qw/colC colD/ ] }) }, - qr/hash passed .+ must have exactly one key/, + qr/hash passed .+ must have exactly one of/, 'Undeterministic order exception', ); + +throws_ok( + sub { $sql->_order_by({-wibble => "fleem" }) }, + qr/invalid key in hash/, + 'Invalid order exception', +); + +throws_ok( + sub { $sql->_order_by({-nulls => "fleem" }) }, + qr/invalid value for -nulls/, + 'Invalid nulls exception', +);