Skip to content

Commit

Permalink
Add support for { -op => $foo } in UPDATE arguments
Browse files Browse the repository at this point in the history
Refactor unary op handlers to allow overrides at any level
Makes for very very hairy internals, but immensely useful for upstream
  • Loading branch information
ribasushi committed Oct 21, 2010
1 parent efc991a commit 0ec3aec
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 32 deletions.
1 change: 1 addition & 0 deletions Changes
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Revision history for SQL::Abstract
- Make sure unparse() does not destroy a passed in \@bindargs
- Support ops with _'s in them (valid in Oracle)
- Properly parse both types of default value inserts
- Allow { -func => $val } as arguments to UPDATE

revision 1.68 2010-09-16
----------------------------
Expand Down
75 changes: 47 additions & 28 deletions lib/SQL/Abstract.pm
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,19 @@ sub update {
},
SCALARREF => sub { # literal SQL without bind
push @set, "$label = $$v";
},
},
HASHREF => sub {
my ($op, $arg, @rest) = %$v;

puke 'Operator calls in update must be in the form { -op => $arg }'
if (@rest or not $op =~ /^\-(.+)/);

local $self->{_nested_func_lhs} = $k;
my ($sql, @bind) = $self->_where_unary_op ($1, $arg);

push @set, "$label = $sql";
push @all_bind, @bind;
},
SCALAR_or_UNDEF => sub {
push @set, "$label = ?";
push @all_bind, $self->_bindtype($k, $v);
Expand Down Expand Up @@ -471,29 +483,16 @@ sub _where_HASHREF {
$op =~ s/^not_/NOT /i;

$self->_debug("Unary OP(-$op) within hashref, recursing...");

my $op_entry = List::Util::first {$op =~ $_->{regex}} @{$self->{unary_ops}};
if (my $handler = $op_entry->{handler}) {
if (not ref $handler) {
if ($op =~ s/ [_\s]? \d+ $//x ) {
belch 'Use of [and|or|nest]_N modifiers is deprecated and will be removed in SQLA v2.0. '
. "You probably wanted ...-and => [ -$op => COND1, -$op => COND2 ... ]";
}
$self->$handler ($op, $v);
}
elsif (ref $handler eq 'CODE') {
$handler->($self, $op, $v);
}
else {
puke "Illegal handler for operator $k - expecting a method name or a coderef";
}
}
else {
$self->debug("Generic unary OP: $k - recursing as function");
my ($s, @b) = $self->_where_func_generic ($op, $v);
$s = "($s)" unless (defined($self->{_nested_func_lhs}) && ($self->{_nested_func_lhs} eq $k)); # top level vs nested
($s, @b);
}
my ($s, @b) = $self->_where_unary_op ($op, $v);

# top level vs nested
# we assume that handled unary ops will take care of their ()s
$s = "($s)" unless (
List::Util::first {$op =~ $_->{regex}} @{$self->{unary_ops}}
or
defined($self->{_nested_func_lhs}) && ($self->{_nested_func_lhs} eq $k)
);
($s, @b);
}
else {
my $method = $self->_METHOD_FOR_refkind("_where_hashpair", $v);
Expand All @@ -508,9 +507,29 @@ sub _where_HASHREF {
return $self->_join_sql_clauses('and', \@sql_clauses, \@all_bind);
}

sub _where_func_generic {
sub _where_unary_op {
my ($self, $op, $rhs) = @_;

if (my $op_entry = List::Util::first {$op =~ $_->{regex}} @{$self->{unary_ops}}) {
my $handler = $op_entry->{handler};

if (not ref $handler) {
if ($op =~ s/ [_\s]? \d+ $//x ) {
belch 'Use of [and|or|nest]_N modifiers is deprecated and will be removed in SQLA v2.0. '
. "You probably wanted ...-and => [ -$op => COND1, -$op => COND2 ... ]";
}
return $self->$handler ($op, $rhs);
}
elsif (ref $handler eq 'CODE') {
return $handler->($self, $op, $rhs);
}
else {
puke "Illegal handler for operator $op - expecting a method name or a coderef";
}
}

$self->debug("Generic unary OP: $op - recursing as function");

my ($sql, @bind) = $self->_SWITCH_refkind ($rhs, {
SCALAR => sub {
puke "Illegal use of top-level '$op'"
Expand Down Expand Up @@ -714,7 +733,7 @@ sub _where_hashpair_HASHREF {
# retain for proper column type bind
$self->{_nested_func_lhs} ||= $k;

($sql, @bind) = $self->_where_func_generic ($op, $val);
($sql, @bind) = $self->_where_unary_op ($op, $val);

$sql = join (' ',
$self->_convert($self->_quote($k)),
Expand Down Expand Up @@ -886,7 +905,7 @@ sub _where_field_BETWEEN {
puke ("Only simple { -func => arg } functions accepted as sub-arguments to BETWEEN")
if (@rest or $func !~ /^ \- (.+)/x);
local $self->{_nested_func_lhs} = $k;
$self->_where_func_generic ($1 => $arg);
$self->_where_unary_op ($1 => $arg);
}
});
push @all_sql, $sql;
Expand Down Expand Up @@ -941,7 +960,7 @@ sub _where_field_IN {
puke ("Only simple { -func => arg } functions accepted as sub-arguments to IN")
if (@rest or $func !~ /^ \- (.+)/x);
local $self->{_nested_func_lhs} = $k;
$self->_where_func_generic ($1 => $arg);
$self->_where_unary_op ($1 => $arg);
}
});
push @all_sql, $sql;
Expand Down
8 changes: 4 additions & 4 deletions t/01generate.t
Original file line number Diff line number Diff line change
Expand Up @@ -441,10 +441,10 @@ my @tests = (
{
func => 'update',
new => {bindtype => 'columns'},
args => ['test', {a => 1, b => \["to_date(?, 'MM/DD/YY')", [{dummy => 1} => '02/02/02']]}, {a => {'between', [1,2]}}],
stmt => 'UPDATE test SET a = ?, b = to_date(?, \'MM/DD/YY\') WHERE ( a BETWEEN ? AND ? )',
stmt_q => 'UPDATE `test` SET `a` = ?, `b` = to_date(?, \'MM/DD/YY\') WHERE ( `a` BETWEEN ? AND ? )',
bind => [[a => '1'], [{dummy => 1} => '02/02/02'], [a => '1'], [a => '2']],
args => ['test', {a => 1, b => \["to_date(?, 'MM/DD/YY')", [{dummy => 1} => '02/02/02']], c => { -lower => 'foo' }}, {a => {'between', [1,2]}}],
stmt => "UPDATE test SET a = ?, b = to_date(?, 'MM/DD/YY'), c = LOWER( ? ) WHERE ( a BETWEEN ? AND ? )",
stmt_q => "UPDATE `test` SET `a` = ?, `b` = to_date(?, 'MM/DD/YY'), `c` = LOWER ( ? ) WHERE ( `a` BETWEEN ? AND ? )",
bind => [[a => '1'], [{dummy => 1} => '02/02/02'], [c => 'foo'], [a => '1'], [a => '2']],
},
{
func => 'select',
Expand Down

0 comments on commit 0ec3aec

Please sign in to comment.