{regex => qr/^ (?: not \s )? between $/ix, handler => sub { die "NOPE" }},
{regex => qr/^ is (?: \s+ not )? $/ix, handler => sub { die "NOPE" }},
{regex => qr/^ (?: not \s )? in $/ix, handler => sub { die "NOPE" }},
+ {regex => qr/^ ident $/ix, handler => sub { die "NOPE" }},
+ {regex => qr/^ value $/ix, handler => sub { die "NOPE" }},
);
#======================================================================
# special operators
$opt{special_ops} ||= [];
- # regexes are applied in order, thus push after user-defines
- push @{$opt{special_ops}}, @BUILTIN_SPECIAL_OPS;
-
if ($class->isa('DBIx::Class::SQLMaker')) {
- push @{$opt{special_ops}}, our $DBIC_Compat_Op ||= {
- regex => qr/^(?:ident|value|(?:not\s)?in)$/i, handler => sub { die "NOPE" }
- };
- $opt{is_dbic_sqlmaker} = 1;
+ $opt{warn_once_on_nest} = 1;
+ $opt{disable_old_special_ops} = 1;
}
# unary operators
-bind => sub { shift; +{ @_ } },
-in => '_expand_in',
-not_in => '_expand_in',
+ -row => sub {
+ my ($self, $node, $args) = @_;
+ +{ $node => [ map $self->expand_expr($_), @$args ] };
+ },
+ -between => '_expand_between',
+ -not_between => '_expand_between',
+ -op => sub {
+ my ($self, $node, $args) = @_;
+ my ($op, @opargs) = @$args;
+ +{ $node => [ $op, map $self->expand_expr($_), @opargs ] };
+ },
+ (map +($_ => '_expand_op_is'), ('-is', '-is_not')),
+ -ident => '_expand_ident',
+ -value => '_expand_value',
};
$opt{expand_op} = {
'nest' => '_expand_nest',
(map +($_ => '_expand_op_andor'), ('and', 'or')),
(map +($_ => '_expand_op_is'), ('is', 'is_not')),
+ 'ident' => '_expand_ident',
+ 'value' => '_expand_value',
};
- # placeholder for _expand_unop system
- {
- my %unops = (-ident => '_expand_ident', -value => '_expand_value');
- foreach my $name (keys %unops) {
- $opt{expand}{$name} = $unops{$name};
- my ($op) = $name =~ /^-(.*)$/;
- $opt{expand_op}{$op} = sub {
- my ($self, $op, $arg, $k) = @_;
- return $self->_expand_expr_hashpair_cmp(
- $k, { "-${op}" => $arg }
- );
- };
- }
- }
-
$opt{render} = {
- (map +("-$_", "_render_$_"), qw(op func bind ident literal list)),
+ (map +("-$_", "_render_$_"), qw(op func bind ident literal row)),
%{$opt{render}||{}}
};
),
(not => '_render_op_not'),
(map +($_ => '_render_op_andor'), qw(and or)),
+ ',' => '_render_op_multop',
};
return bless \%opt, $class;
my $f = $options->{returning};
my ($sql, @bind) = $self->render_aqt(
- $self->_expand_maybe_list_expr($f, undef, -ident)
+ $self->_expand_maybe_list_expr($f, -ident)
);
return wantarray
? $self->_sqlcase(' returning ') . $sql
my ($self, $fields) = @_;
return $fields unless ref($fields);
return $self->render_aqt(
- $self->_expand_maybe_list_expr($fields, undef, '-ident')
+ $self->_expand_maybe_list_expr($fields, '-ident')
);
}
if (
(our $Expand_Depth) == 1
- and List::Util::first { $op =~ $_->{regex} } @{$self->{special_ops}}
+ and (
+ List::Util::first { $op =~ $_->{regex} } @{$self->{special_ops}}
+ or (
+ $self->{disable_old_special_ops}
+ and List::Util::first { $op =~ $_->{regex} } @BUILTIN_SPECIAL_OPS
+ )
+ )
) {
puke "Illegal use of top-level '-$op'"
}
}
sub _expand_ident {
- my ($self, $op, $body) = @_;
+ my ($self, $op, $body, $k) = @_;
+ return $self->_expand_expr_hashpair_cmp(
+ $k, { -ident => $body }
+ ) if defined($k);
unless (defined($body) or (ref($body) and ref($body) eq 'ARRAY')) {
puke "$op requires a single plain scalar argument (a quotable identifier) or an arrayref of identifier parts";
}
}
sub _expand_value {
+ return $_[0]->_expand_expr_hashpair_cmp(
+ $_[3], { -value => $_[2] },
+ ) if defined($_[3]);
+{ -bind => [ our $Cur_Col_Meta, $_[2] ] };
}
sub _expand_op_is {
my ($self, $op, $vv, $k) = @_;
+ $op =~ s/^-//;
+ ($k, $vv) = @$vv unless defined $k;
puke "$op can only take undef as argument"
if defined($vv)
and not (
and exists($vv->{-value})
and !defined($vv->{-value})
);
- return +{ -op => [ $op.'_null', $self->_expand_ident(-ident => $k) ] };
+ return +{ -op => [ $op.'_null', $self->expand_expr($k, -ident) ] };
}
sub _expand_between {
my ($self, $op, $vv, $k) = @_;
- local our $Cur_Col_Meta = $k;
+ $op =~ s/^-//;
+ $k = shift @{$vv = [ @$vv ]} unless defined $k;
my @rhs = map $self->_expand_expr($_),
ref($vv) eq 'ARRAY' ? @$vv : $vv;
unless (
}
return +{ -op => [
$op,
- $self->_expand_ident(-ident => $k),
+ $self->expand_expr(ref($k) ? $k : { -ident => $k }),
@rhs
] }
}
sub _expand_in {
my ($self, $raw, $vv, $k) = @_;
$k = shift @{$vv = [ @$vv ]} unless defined $k;
- local our $Cur_Col_Meta = $k;
my $op = $self->_normalize_op($raw);
if (my $literal = is_literal_value($vv)) {
my ($sql, @bind) = @$literal;
my $opened_sql = $self->_open_outer_paren($sql);
return +{ -op => [
- $op, $self->_expand_ident(-ident => $k),
+ $op, $self->expand_expr($k, -ident),
[ { -literal => [ $opened_sql, @bind ] } ]
] };
}
;
puke("Argument passed to the '${\uc($op)}' operator can not be undefined")
if !defined($vv);
- my @rhs = map $self->_expand_expr($_),
- map { ref($_) ? $_ : { -bind => [ $k, $_ ] } }
+ my @rhs = map $self->expand_expr($_, -value),
map { defined($_) ? $_: puke($undef_err) }
(ref($vv) eq 'ARRAY' ? @$vv : $vv);
return $self->${\($op =~ /^not/ ? 'sqltrue' : 'sqlfalse')} unless @rhs;
return +{ -op => [
$op,
- $self->_expand_ident(-ident => $k),
+ $self->expand_expr($k, -ident),
\@rhs
] };
}
my ($self, $op, $v) = @_;
# DBIx::Class requires a nest warning to be emitted once but the private
# method it overrode to do so no longer exists
- if ($self->{is_dbic_sqlmaker}) {
+ if ($self->{warn_once_on_nest}) {
unless (our $Nest_Warned) {
belch(
"-nest in search conditions is deprecated, you most probably wanted:\n"
return $self->_convert($self->_quote($ident));
}
-sub _render_list {
- my ($self, $list) = @_;
- my @parts = grep length($_->[0]), map [ $self->render_aqt($_) ], @$list;
- return join(', ', map $_->[0], @parts), map @{$_}[1..$#$_], @parts;
+sub _render_row {
+ my ($self, $values) = @_;
+ my ($sql, @bind) = $self->_render_op([ ',', @$values ]);
+ return "($sql)", @bind;
}
sub _render_func {
return '' unless @parts;
return @{$parts[0]} if @parts == 1;
my ($final_sql) = join(
- ' '.$self->_sqlcase(join ' ', split '_', $op).' ',
+ ($op eq ',' ? '' : ' ').$self->_sqlcase(join ' ', split '_', $op).' ',
map $_->[0], @parts
);
return (
),
map $self->expand_expr($_, -ident),
map ref($_) eq 'ARRAY' ? @$_ : $_, @to_expand;
- return (@exp > 1 ? { -list => \@exp } : $exp[0]);
+ return undef unless @exp;
+ return undef if @exp == 1 and not defined($exp[0]);
+ return +{ -op => [ ',', @exp ] };
};
local @{$self->{expand}}{qw(-asc -desc)} = (($expander) x 2);
if $expanded->{-ident} or @{$expanded->{-literal}||[]} == 1;
for ($expanded) {
- if (ref() eq 'HASH' and my $l = $_->{-list}) {
- return map $self->_chunkify_order_by($_), @$l;
+ if (ref() eq 'HASH' and $_->{-op} and $_->{-op}[0] eq ',') {
+ my ($comma, @list) = @{$_->{-op}};
+ return map $self->_chunkify_order_by($_), @list;
}
return [ $self->render_aqt($_) ];
}
my $self = shift;
my $from = shift;
($self->render_aqt(
- $self->_expand_maybe_list_expr($from, undef, -ident)
+ $self->_expand_maybe_list_expr($from, -ident)
))[0];
}
#======================================================================
sub _expand_maybe_list_expr {
- my ($self, $expr, $logic, $default) = @_;
- my $e = do {
- if (ref($expr) eq 'ARRAY') {
- return { -list => [
- map $self->expand_expr($_, $default), @$expr
- ] } if @$expr > 1;
- $expr->[0]
- } else {
- $expr
- }
- };
- return $self->expand_expr($e, $default);
+ my ($self, $expr, $default) = @_;
+ return +{ -op => [ ',',
+ map $self->expand_expr($_, $default),
+ ref($expr) eq 'ARRAY' ? @$expr : $expr
+ ] };
}
# highly optimized, as it's called way too often