use SQL::ReservedWords;
use Data::Query::Constants qw(
DQ_IDENTIFIER DQ_OPERATOR DQ_VALUE DQ_JOIN DQ_ALIAS DQ_ORDER DQ_LITERAL
+ DQ_GROUP
);
use Moo;
has always_quote => (is => 'ro', default => sub { 0 });
+has collapse_aliases => (is => 'ro', default => sub { 1 });
+
sub _default_simple_ops {
+{
(map +($_ => 'binop'), qw(= > < >= <= != LIKE), 'NOT LIKE' ),
$_ eq '*' # Yes, this means you can't have a column just called '*'.
? $_ # Yes, this is a feature. Go shoot the DBA if he disagrees.
: ( # reserved are stored uc, quote if non-word
- $always_quote || $res_check->{+uc} || /\W/
+ ($always_quote and $q1) || $res_check->{+uc} || /\W/
? $q1.$_.$q2
: $_
)
$op->{$self->_operator_type} = $self->_convert_op($dq);
}
my $op_name = $op->{$self->_operator_type};
- if (my $op_type = $self->{simple_ops}{$op_name}) {
+ if (my $op_type = $self->simple_ops->{$op_name}) {
return $self->${\"_handle_op_type_${op_type}"}($op_name, $dq);
} elsif (my $meth = $self->can("_handle_op_special_${op_name}")) {
return $self->$meth($dq);
my ($self, $dq, $as) = @_;
# FROM foo foo -> FROM foo
# FROM foo.bar bar -> FROM foo.bar
- if ($dq->{alias}{type} eq DQ_IDENTIFIER) {
- if ($dq->{alias}{elements}[-1] eq $dq->{as}) {
- return $self->_render($dq->{alias});
+ if ($self->collapse_aliases) {
+ if ($dq->{from}{type} eq DQ_IDENTIFIER) {
+ if ($dq->{from}{elements}[-1] eq $dq->{to}) {
+ return $self->_render($dq->{from});
+ }
}
}
return [
- $self->_render($dq->{alias}),
+ $self->_render($dq->{from}),
$as || ' ',
- $self->_render_identifier({ elements => [ $dq->{as} ] })
+ $self->_render_identifier({ elements => [ $dq->{to} ] })
];
}
sub _render_join {
my ($self, $dq) = @_;
- my ($left, $right) = @{$dq->{join}};
- die "No support for ON yet" if $dq->{on};
- die "No support for LEFT/RIGHT yet" if $dq->{outer};
- [ $self->_render($left), ',', $self->_render($right) ];
+ my ($left, $right) = @{$dq}{qw(left right)};
+ my $join = do {
+ if ($dq->{outer}) {
+ $self->_format_keyword(uc($dq->{outer}).' JOIN');
+ } elsif ($dq->{on}) {
+ $self->_format_keyword('JOIN');
+ } else {
+ ','
+ }
+ };
+ [
+ $self->_render($left), $join, $self->_render($right),
+ ($dq->{on}
+ ? ($self->_format_keyword('ON'), $self->_render($dq->{on}))
+ : ())
+ ];
}
sub _render_where {
my ($self, $dq) = @_;
my ($from, $where) = @{$dq}{qw(from where)};
+ my $keyword = ($from && $from->{type} eq DQ_GROUP) ? 'HAVING' : 'WHERE';
[
($from ? $self->_render($from) : ()),
- $self->_format_keyword('WHERE'),
+ $self->_format_keyword($keyword),
$self->_render($where)
]
}
\@ret;
}
+sub _render_group {
+ my ($self, $dq) = @_;
+ # this could also squash like order does. but I dunno whether that should
+ # move somewhere else just yet.
+ my @ret = (
+ ($dq->{from} ? $self->_render($dq->{from}) : ()),
+ $self->_format_keyword('GROUP BY'),
+ intersperse(',', map $self->_render($_), @{$dq->{by}})
+ );
+ \@ret;
+}
+
sub _render_delete {
my ($self, $dq) = @_;
my ($target, $where) = @{$dq}{qw(target where)};