sub _expand_expr {
my ($self, $expr, $logic, $default_scalar_to) = @_;
local our $Default_Scalar_To = $default_scalar_to if $default_scalar_to;
+ our $Expand_Depth ||= 0; local $Expand_Depth = $Expand_Depth + 1;
return undef unless defined($expr);
if (ref($expr) eq 'HASH') {
if (keys %$expr > 1) {
sort keys %$expr
] };
}
- return unless %$expr;
+ return { -literal => [ '' ] } unless keys %$expr;
return $self->_expand_expr_hashpair(%$expr, $logic);
}
if (ref($expr) eq 'ARRAY') {
my $logic = lc($logic || $self->{logic});
$logic eq 'and' or $logic eq 'or' or puke "unknown logic: $logic";
- my @expr = @$expr;
+ #my @expr = @$expr;
+ my @expr = grep {
+ (ref($_) eq 'ARRAY' and @$_)
+ or (ref($_) eq 'HASH' and %$_)
+ or 1
+ } @$expr;
my @res;
$op =~ s/^-// if length($op) > 1;
# top level special ops are illegal in general
- puke "Illegal use of top-level '-$op'"
- if List::Util::first { $op =~ $_->{regex} } @{$self->{special_ops}};
+ # note that, arguably, if it makes no sense at top level, it also
+ # makes no sense on the other side of an = sign or similar but DBIC
+ # gets disappointingly upset if I disallow it
+ if (
+ (our $Expand_Depth) == 1
+ and List::Util::first { $op =~ $_->{regex} } @{$self->{special_ops}}
+ ) {
+ puke "Illegal use of top-level '-$op'"
+ }
if (my $us = List::Util::first { $op =~ $_->{regex} } @{$self->{unary_ops}}) {
return { -op => [ $op, $v ] };
}
and (keys %$v)[0] =~ /^-/
) {
my ($func) = $k =~ /^-(.*)$/;
+ if (List::Util::first { $func =~ $_->{regex} } @{$self->{special_ops}}) {
+ return +{ -op => [ $func, $self->_expand_expr($v) ] };
+ }
return +{ -func => [ $func, $self->_expand_expr($v) ] };
}
if (!ref($v) or is_literal_value($v)) {
my ($sql, @bind) = @$literal;
if ($self->{bindtype} eq 'columns') {
for (@bind) {
- if (!defined $_ || ref($_) ne 'ARRAY' || @$_ != 2) {
- puke "bindtype 'columns' selected, you need to pass: [column_name => bind_value]"
- }
+ $self->_assert_bindval_matches_bindtype($_);
}
}
return +{ -literal => [ $self->_quote($k).' '.$sql, @bind ] };
my $where_exp = (ref($where)
? $self->_expand_expr($where, $logic)
: { -literal => [ $where ] });
+#::Dwarn([ EXPANDED => $where_exp ]);
#print STDERR Data::Dumper::Concise::Dumper([ EXP => $where_exp ]);
# my ($sql, @bind) = $self->$method($where_exp, $logic);
my ($sql, @bind) = defined($where_exp) ? $self->_render_expr($where_exp) : (undef);
-
# DBIx::Class used to call _recurse_where in scalar context
# something else might too...
if (wantarray) {
if (my $h = $special{$op}) {
return $self->$h(\@args);
}
- if (my $us = List::Util::first { $op =~ $_->{regex} } @{$self->{special_ops}}) {
+ my $us = List::Util::first { $op =~ $_->{regex} } @{$self->{special_ops}};
+ if ($us and @args > 1) {
puke "Special op '${op}' requires first value to be identifier"
unless my ($k) = map $_->{-ident}, grep ref($_) eq 'HASH', $args[0];
return $self->${\($us->{handler})}($k, $op, $args[1]);
? "${expr_sql} ${op_sql}"
: "${op_sql} ${expr_sql}"
);
- return (($op eq 'not' ? '('.$final_sql.')' : $final_sql), @bind);
+ return (($op eq 'not' || $us ? '('.$final_sql.')' : $final_sql), @bind);
+ #} elsif (@args == 0) {
+ # return '';
} else {
- my @parts = map [ $self->_render_expr($_) ], @args;
- my ($final_sql) = map +($op =~ /^(and|or)$/ ? "(${_})" : $_), join(
+ my @parts = grep length($_->[0]), map [ $self->_render_expr($_) ], @args;
+ return '' unless @parts;
+ my $is_andor = !!($op =~ /^(and|or)$/);
+ return @{$parts[0]} if $is_andor and @parts == 1;
+ my ($final_sql) = map +($is_andor ? "( ${_} )" : $_), join(
($final_op eq ',' ? '' : ' ').$self->_sqlcase($final_op).' ',
map $_->[0], @parts
);