(map +($_ => '_render_unop_postfix'),
'is_null', 'is_not_null', 'asc', 'desc',
),
- (not => '_render_op_not'),
+ (not => '_render_unop_paren'),
(map +($_ => '_render_op_andor'), qw(and or)),
',' => '_render_op_multop',
};
my $data = shift || return;
my $options = shift;
- my $method = $self->_METHOD_FOR_refkind("_insert", $data);
- my ($sql, @bind) = $self->$method($data);
- $sql = join " ", $self->_sqlcase('insert into'), $table, $sql;
+ my ($sql, @bind) = do {
+ if (is_literal_value($data)) {
+ $self->render_expr($data);
+ } else {
+ my ($fields, $values) = (
+ ref($data) eq 'HASH' ?
+ ([ sort keys %$data ], [ @{$data}{sort keys %$data} ])
+ : (undef, $data)
+ );
+
+ # no names (arrayref) means can't generate bindtype
+ !($fields) && $self->{bindtype} eq 'columns'
+ && belch "can't do 'columns' bindtype when called with arrayref";
+
+ my $fields_sql = ($fields
+ ? ' '.($self->render_expr({ -row => $fields }, '-ident'))[0]
+ : ''
+ );
+ my ($values_sql, @bind) = $self->render_aqt(
+ { -row => [
+ map {
+ local our $Cur_Col_Meta = $fields->[$_];
+ $self->_expand_insert_value($values->[$_])
+ } 0..$#$values
+ ] }
+ );
+ ($fields_sql.' '.$self->_sqlcase('values').' '.$values_sql, @bind);
+ }
+ };
+
+ $sql = (join " ", $self->_sqlcase('insert into'), $table).$sql;
if ($options->{returning}) {
my ($s, @b) = $self->_insert_returning($options);
: ($self->_sqlcase(' returning ').$sql, @bind);
}
-sub _insert_HASHREF { # explicit list of fields and then values
- my ($self, $data) = @_;
-
- my @fields = sort keys %$data;
-
- my ($sql, @bind) = $self->_insert_values($data);
-
- # assemble SQL
- $_ = $self->_quote($_) foreach @fields;
- $sql = "( ".join(", ", @fields).") ".$sql;
-
- return ($sql, @bind);
-}
-
-sub _insert_ARRAYREF { # just generate values(?,?) part (no list of fields)
- my ($self, $data) = @_;
-
- # no names (arrayref) so can't generate bindtype
- $self->{bindtype} ne 'columns'
- or belch "can't do 'columns' bindtype when called with arrayref";
-
- my (@values, @all_bind);
- foreach my $value (@$data) {
- my ($values, @bind) = $self->_insert_value(undef, $value);
- push @values, $values;
- push @all_bind, @bind;
- }
- my $sql = $self->_sqlcase('values')." ( ".join(", ", @values)." )";
- return ($sql, @all_bind);
-}
-
-sub _insert_ARRAYREFREF { # literal SQL with bind
- my ($self, $data) = @_;
-
- my ($sql, @bind) = @${$data};
- $self->_assert_bindval_matches_bindtype(@bind);
-
- return ($sql, @bind);
-}
-
-
-sub _insert_SCALARREF { # literal SQL without bind
- my ($self, $data) = @_;
-
- return ($$data);
-}
-
-sub _insert_values {
- my ($self, $data) = @_;
-
- my (@values, @all_bind);
- foreach my $column (sort keys %$data) {
- my ($values, @bind) = $self->_insert_value($column, $data->{$column});
- push @values, $values;
- push @all_bind, @bind;
- }
- my $sql = $self->_sqlcase('values')." ( ".join(", ", @values)." )";
- return ($sql, @all_bind);
-}
-
-sub _insert_value {
- my ($self, $column, $v) = @_;
-
- return $self->render_aqt(
- $self->_expand_insert_value($column, $v)
- );
-}
-
sub _expand_insert_value {
- my ($self, $column, $v) = @_;
+ my ($self, $v) = @_;
+
+ my $k = our $Cur_Col_Meta;
if (ref($v) eq 'ARRAY') {
if ($self->{array_datatypes}) {
- return +{ -bind => [ $column, $v ] };
+ return +{ -bind => [ $k, $v ] };
}
my ($sql, @bind) = @$v;
$self->_assert_bindval_matches_bindtype(@bind);
if (ref($v) eq 'HASH') {
if (grep !/^-/, keys %$v) {
belch "HASH ref as bind value in insert is not supported";
- return +{ -bind => [ $column, $v ] };
+ return +{ -bind => [ $k, $v ] };
}
}
if (!defined($v)) {
- return +{ -bind => [ $column, undef ] };
+ return +{ -bind => [ $k, undef ] };
}
- local our $Cur_Col_Meta = $column;
return $self->expand_expr($v);
}
my ($self, $aqt) = @_;
my ($k, $v, @rest) = %$aqt;
die "No" if @rest;
- die "Also no" unless $k =~ s/^-//;
+ die "Not a node type: $k" unless $k =~ s/^-//;
if (my $meth = $self->{render}{$k}) {
return $self->$meth($v);
}
}
sub render_expr {
- my ($self, $expr) = @_;
- $self->render_aqt($self->expand_expr($expr));
+ my ($self, $expr, $default_scalar_to) = @_;
+ $self->render_aqt($self->expand_expr($expr, $default_scalar_to));
}
sub _normalize_op {
if (ref($expr) eq 'HASH') {
return undef unless my $kc = keys %$expr;
if ($kc > 1) {
- return $self->_expand_op_andor(-and => $expr);
+ return $self->_expand_op_andor(and => $expr);
}
my ($key, $value) = %$expr;
if ($key =~ /^-/ and $key =~ s/ [_\s]? \d+ $//x ) {
return $self->_expand_hashpair($key, $value);
}
if (ref($expr) eq 'ARRAY') {
- my $logic = '-'.lc($self->{logic});
- return $self->_expand_op_andor($logic, $expr);
+ return $self->_expand_op_andor(lc($self->{logic}), $expr);
}
if (my $literal = is_literal_value($expr)) {
return +{ -literal => $literal };
# hash with multiple or no elements is andor
if (ref($v) eq 'HASH' and keys %$v != 1) {
- return $self->_expand_op_andor(-and => $v, $k);
+ return $self->_expand_op_andor(and => $v, $k);
}
# undef needs to be re-sent with cmp to achieve IS/IS NOT NULL
$self->_debug("ARRAY($k) means distribute over elements");
my $logic = lc(
$v->[0] =~ /^-(and|or)$/i
- ? shift(@{$v = [ @$v ]})
- : '-'.lc($self->{logic} || 'OR')
+ ? (shift(@{$v = [ @$v ]}), $1)
+ : lc($self->{logic} || 'OR')
);
return $self->_expand_op_andor(
$logic => $v, $k
my $op = $self->_normalize_op($k);
if (my $exp = $self->{expand}{$op}) {
- return $self->$exp($k, $v);
+ return $self->$exp($op, $v);
}
# Ops prefixed with -not_ get converted
if (ref($vv) eq 'ARRAY') {
my @raw = @$vv;
my $logic = (defined($raw[0]) and $raw[0] =~ /^-(and|or)$/i)
- ? shift @raw : '-or';
+ ? (shift(@raw), $1) : 'or';
my @values = map +{ $vk => $_ }, @raw;
if (
$op =~ $self->{inequality_op}
or $op =~ $self->{not_like_op}
) {
- if (lc($logic) eq '-or' and @values > 1) {
+ if (lc($logic) eq 'or' and @values > 1) {
belch "A multi-element arrayref as an argument to the inequality op '${\uc(join ' ', split '_', $op)}' "
. 'is technically equivalent to an always-true 1=1 (you probably wanted '
. "to say ...{ \$inequality_op => [ -and => \@values ] }... instead)"
}
sub _expand_ident {
- my ($self, $op, $body, $k) = @_;
+ my ($self, undef, $body, $k) = @_;
return $self->_expand_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";
+ puke "-ident requires a single plain scalar argument (a quotable identifier) or an arrayref of identifier parts";
}
my @parts = map split(/\Q${\($self->{name_sep}||'.')}\E/, $_),
ref($body) ? @$body : $body;
}
sub _expand_row {
- my ($self, $node, $args) = @_;
- +{ $node => [ map $self->expand_expr($_), @$args ] };
+ my ($self, undef, $args) = @_;
+ +{ -row => [ map $self->expand_expr($_), @$args ] };
}
sub _expand_op {
- my ($self, $node, $args) = @_;
+ my ($self, undef, $args) = @_;
my ($op, @opargs) = @$args;
- +{ $node => [ $op, map $self->expand_expr($_), @opargs ] };
+ if (my $exp = $self->{expand_op}{$op}) {
+ return $self->$exp($op, \@opargs);
+ }
+ +{ -op => [ $op, map $self->expand_expr($_), @opargs ] };
}
sub _expand_bool {
}
sub _expand_op_andor {
- my ($self, $logic, $v, $k) = @_;
+ my ($self, $logop, $v, $k) = @_;
if (defined $k) {
$v = [ map +{ $k, $_ },
(ref($v) eq 'HASH')
: @$v,
];
}
- my ($logop) = $logic =~ /^-?(.*)$/;
if (ref($v) eq 'HASH') {
return undef unless keys %$v;
return +{ -op => [
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)
sub _expand_between {
my ($self, $op, $vv, $k) = @_;
- $op =~ s/^-//;
$k = shift @{$vv = [ @$vv ]} unless defined $k;
my @rhs = map $self->_expand_expr($_),
ref($vv) eq 'ARRAY' ? @$vv : $vv;
}
sub _expand_in {
- my ($self, $raw, $vv, $k) = @_;
+ my ($self, $op, $vv, $k) = @_;
$k = shift @{$vv = [ @$vv ]} unless defined $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_expr($k, -ident),
- [ { -literal => [ $opened_sql, @bind ] } ]
+ { -literal => [ $opened_sql, @bind ] }
] };
}
my $undef_err =
return +{ -op => [
$op,
$self->expand_expr($k, -ident),
- \@rhs
+ @rhs
] };
}
sub _expand_nest {
- my ($self, $op, $v) = @_;
+ my ($self, undef, $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->{warn_once_on_nest}) {
}
sub _expand_bind {
- my ($self, $op, $bind) = @_;
- return { $op => $bind };
+ my ($self, undef, $bind) = @_;
+ return { -bind => $bind };
}
sub _recurse_where {
my $op = join(' ', split '_', $op);
- my $us = List::Util::first { $op =~ $_->{regex} } @{$self->{special_ops}};
- if ($us and @args > 1) {
+ my $ss = List::Util::first { $op =~ $_->{regex} } @{$self->{special_ops}};
+ if ($ss and @args > 1) {
puke "Special op '${op}' requires first value to be identifier"
unless my ($ident) = map $_->{-ident}, grep ref($_) eq 'HASH', $args[0];
my $k = join(($self->{name_sep}||'.'), @$ident);
local our $Expand_Depth = 1;
- return $self->${\($us->{handler})}($k, $op, $args[1]);
+ return $self->${\($ss->{handler})}($k, $op, $args[1]);
}
if (my $us = List::Util::first { $op =~ $_->{regex} } @{$self->{unary_ops}}) {
return $self->${\($us->{handler})}($op, $args[0]);
}
-
+ if ($ss) {
+ return $self->_render_unop_paren($op, \@args);
+ }
}
if (@args == 1) {
return $self->_render_unop_prefix($op, \@args);
sub _render_op_in {
my ($self, $op, $args) = @_;
- my ($lhs, $rhs) = @$args;
+ my ($lhs, @rhs) = @$args;
my @in_bind;
my @in_sql = map {
my ($sql, @bind) = $self->render_aqt($_);
push @in_bind, @bind;
$sql;
- } @$rhs;
+ } @rhs;
my ($lhsql, @lbind) = $self->render_aqt($lhs);
return (
$lhsql.' '.$self->_sqlcase(join ' ', split '_', $op).' ( '
my @parts = grep length($_->[0]), map [ $self->render_aqt($_) ], @$args;
return '' unless @parts;
return @{$parts[0]} if @parts == 1;
- my ($sql, @bind) = $self->_render_op_multop($op, $args);
+ my ($sql, @bind) = $self->_join_parts(' '.$self->_sqlcase($op).' ', @parts);
return '( '.$sql.' )', @bind;
}
my @parts = grep length($_->[0]), map [ $self->render_aqt($_) ], @$args;
return '' unless @parts;
return @{$parts[0]} if @parts == 1;
- my ($final_sql) = join(
- ($op eq ',' ? '' : ' ').$self->_sqlcase(join ' ', split '_', $op).' ',
- map $_->[0], @parts
- );
+ my $join = ($op eq ','
+ ? ', '
+ : ' '.$self->_sqlcase(join ' ', split '_', $op).' '
+ );
+ return $self->_join_parts($join, @parts);
+}
+
+sub _join_parts {
+ my ($self, $join, @parts) = @_;
return (
- $final_sql,
+ join($join, map $_->[0], @parts),
map @{$_}[1..$#$_], @parts
);
}
-sub _render_op_not {
+
+sub _render_unop_paren {
my ($self, $op, $v) = @_;
my ($sql, @bind) = $self->_render_unop_prefix($op, $v);
return "(${sql})", @bind;