From: Justin Hunter Date: Tue, 21 Apr 2009 00:03:47 +0000 (+0000) Subject: patch for -between to handle [\"", \""] and \["", @bind] with accompanying tests X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=cf02fc473c670690d4c70f240dfe5d8cba10a94d;p=scpubgit%2FQ-Branch.git patch for -between to handle [\"", \""] and \["", @bind] with accompanying tests --- diff --git a/lib/SQL/Abstract.pm b/lib/SQL/Abstract.pm index e0f1cad..457f305 100644 --- a/lib/SQL/Abstract.pm +++ b/lib/SQL/Abstract.pm @@ -699,16 +699,39 @@ sub _where_UNDEF { sub _where_field_BETWEEN { my ($self, $k, $op, $vals) = @_; - ref $vals eq 'ARRAY' && @$vals == 2 - or puke "special op 'between' requires an arrayref of two values"; - - my ($label) = $self->_convert($self->_quote($k)); - my ($placeholder) = $self->_convert('?'); - my $and = $self->_sqlcase('and'); + (ref $vals eq 'ARRAY' && @$vals == 2) or + (ref $vals eq 'REF' && (@$$vals == 1 || @$$vals == 2 || @$$vals == 3)) + or puke "special op 'between' requires an arrayref of two values (or a scalarref or arrayrefref for literal SQL)"; + + my ($clause, @bind, $label, $and, $placeholder); + $label = $self->_convert($self->_quote($k)); + $and = ' ' . $self->_sqlcase('and') . ' '; + $placeholder = $self->_convert('?'); $op = $self->_sqlcase($op); - my $sql = "( $label $op $placeholder $and $placeholder )"; - my @bind = $self->_bindtype($k, @$vals); + if (ref $vals eq 'REF') { + ($clause, @bind) = @$$vals; + } + else { + my (@all_sql, @all_bind); + + foreach my $val (@$vals) { + my ($sql, @bind) = $self->_SWITCH_refkind($val, { + SCALAR => sub { + return ($placeholder, ($val)); + }, + SCALARREF => sub { + return ($self->_convert($$val), ()); + }, + }); + push @all_sql, $sql; + push @all_bind, @bind; + } + + $clause = (join $and, @all_sql); + @bind = $self->_bindtype($k, @all_bind); + } + my $sql = "( $label $op $clause )"; return ($sql, @bind) } diff --git a/t/05between.t b/t/05between.t new file mode 100644 index 0000000..00b7361 --- /dev/null +++ b/t/05between.t @@ -0,0 +1,101 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Test::More; +use Test::Exception; +use SQL::Abstract::Test import => ['is_same_sql_bind']; + +use Data::Dumper; +use SQL::Abstract; + +=begin +Test -between and -in + * between + * [scalar, scalar] + * [scalarref, scalar] + * [scalar, scalarref] + * [scalarref, scalarref] + * \[] + * \["? AND ?", scalar, scalar] + * \["1 AND ?", scalar] + * \["? AND 2", scalar] + * \["1 AND 2"] +=cut + +my @in_between_tests = ( + { + where => { x => { -between => [1, 2] } }, + stmt => 'WHERE (x BETWEEN ? AND ?)', + bind => [qw/1 2/], + test => '-between with two placeholders', + }, + { + where => { x => { -between => [\"1", 2] } }, + stmt => 'WHERE (x BETWEEN 1 AND ?)', + bind => [qw/2/], + test => '-between with one literal sql arg and one placeholder', + }, + { + where => { x => { -between => [1, \"2"] } }, + stmt => 'WHERE (x BETWEEN ? AND 2)', + bind => [qw/1/], + test => '-between with one placeholder and one literal sql arg', + }, + { + where => { x => { -between => [\'current_date - 1', \'current_date - 0'] } }, + stmt => 'WHERE (x BETWEEN current_date - 1 AND current_date - 0)', + bind => [], + test => '-between with two literal sql arguments', + }, + { + where => { x => { -between => \['? AND ?', 1, 2] } }, + stmt => 'WHERE (x BETWEEN ? AND ?)', + bind => [1,2], + test => '-between with literal sql with placeholders (\["? AND ?", scalar, scalar])', + }, + { + where => { x => { -between => \["'something' AND ?", 2] } }, + stmt => "WHERE (x BETWEEN 'something' AND ?)", + bind => [2], + test => '-between with literal sql with one literal arg and one placeholder (\["\'something\' AND ?", scalar])', + }, + { + where => { x => { -between => \["? AND 'something'", 1] } }, + stmt => "WHERE (x BETWEEN ? AND 'something')", + bind => [1], + test => '-between with literal sql with one placeholder and one literal arg (\["? AND \'something\'", scalar])', + }, + { + where => { x => { -between => \["'this' AND 'that'"] } }, + stmt => "WHERE (x BETWEEN 'this' AND 'that')", + bind => [], + test => '-between with literal sql with two literal args (\["\'this\' AND \'that\'"])', + }, +); + +plan tests => @in_between_tests*3; + +for my $case (@in_between_tests) { + TODO: { + local $TODO = $case->{todo} if $case->{todo}; + + local $Data::Dumper::Terse = 1; + + my @w; + local $SIG{__WARN__} = sub { push @w, @_ }; + my $sql = SQL::Abstract->new ($case->{args} || {}); + lives_ok (sub { + my ($stmt, @bind) = $sql->where($case->{where}); + is_same_sql_bind( + $stmt, + \@bind, + $case->{stmt}, + $case->{bind}, + ) + || diag "Search term:\n" . Dumper $case->{where}; + }); + is (@w, 0, $case->{test} || 'No warnings within in-between tests') + || diag join "\n", 'Emitted warnings:', @w; + } +}