DQ_IDENTIFIER => 'Identifier',
DQ_OPERATOR => 'Operator',
DQ_VALUE => 'Value',
+ DQ_SELECT => 'Select',
))
};
package Data::Query::ExprHelpers;
use strictures 1;
-use Data::Query::Constants qw(DQ_VALUE DQ_OPERATOR);
+use Data::Query::Constants qw(DQ_VALUE DQ_OPERATOR DQ_IDENTIFIER);
use base qw(Exporter);
-our @EXPORT_OK = qw(perl_scalar_value perl_operator);
+our @EXPORT_OK = qw(perl_scalar_value perl_operator identifier);
sub perl_scalar_value {
+{
- type => DQ_VALUE,
- subtype => { Perl => 'Scalar' },
- value => $_[0]
+ type => DQ_VALUE,
+ subtype => { Perl => 'Scalar' },
+ value => $_[0]
}
}
}
}
+sub identifier {
+ +{
+ type => DQ_IDENTIFIER,
+ elements => [ @_ ]
+ }
+}
+
1;
} @$struct), @bind ];
}
+# I present this to permit strange people to easily supply a patch to lc()
+# their keywords, as I have heard many desire to do, lest they infect me
+# with whatever malady caused this desire by their continued proximity for
+# want of such a feature.
+
+sub _format_keyword { $_[1] }
+
sub _render {
$_[0]->${\"_render_${\lc($_[1]->{type})}"}($_[1]);
}
}
die "Can't convert non-perl op yet";
}
-
+
+sub _render_select {
+ my ($self, $dq) = @_;
+ die "Empty select list" unless @{$dq->{select}};
+
+ # it is, in fact, completely valid for there to be nothing for us
+ # to project from since many databases handle 'SELECT 1;' fine
+
+ my @select = map {
+ # we should perhaps validate that what we've been handed
+ # is an expression and possibly an identifier - at least a
+ # debugging mode that does such is almost certainly worthwhile;
+ # but for present I'm focusing on making this work.
+ my $e = $self->_render($_->{expr});
+ $_->{name} ? [ $e, 'AS', $self->_render($_->{name}), ',' ] : [ $e, ',' ]
+ } @{$dq->{select}};
+
+ # we put the commas inside the [] for each entry as a hint to the pretty
+ # printer downstreamso now we need to eliminate the comma from the last
+ # entry - we know there always is one due to the die guard at the top
+
+ pop @{$select[-1]};
+
+ return [
+ $self->_format_keyword('SELECT'),
+ \@select,
+ # if present this may be a bare FROM, a FROM+WHERE, or a FROM+WHERE+GROUP
+ # since we're the SELECT and therefore always come first, we don't care.
+ $dq->{from} ? @{$self->_render($dq->{from})} : ()
+ ];
+}
+
1;
+use strictures 1;
use Data::Query::ExprBuilder::Identifier;
-use Data::Query::Constants qw(DQ_IDENTIFIER DQ_OPERATOR DQ_VALUE);
+use Data::Query::Constants qw(DQ_SELECT);
+use Data::Query::ExprHelpers qw(perl_scalar_value identifier);
sub expr (&) {
_mk_expr($_[0]);
sub _mk_expr {
local $_ = Data::Query::ExprBuilder::Identifier->new({
- expr => {
- type => DQ_IDENTIFIER,
- elements => [],
- },
+ expr => identifier()
});
$_[0]->()->{expr};
}
+sub AS {
+ my $as = shift;
+ (bless(\$as, 'LIES::AS'), @_);
+}
+
+sub SELECT (&;@) {
+ my @select = map +(
+ ref()
+ ? $_
+ : { expr => perl_scalar_value($_) }
+ ), do {
+ local $_ = Data::Query::ExprBuilder::Identifier->new({
+ expr => identifier()
+ });
+ $_[0]->();
+ };
+ my @final;
+ while (@select) {
+ my $e = shift @select;
+ my $res = push @final, +{ expr => $e->{expr} };
+ if (ref($select[0]) eq 'LIES::AS') {
+ $res->{name} = identifier(shift @select);
+ }
+ }
+
+ return +{
+ expr => {
+ type => DQ_SELECT,
+ select => \@final
+ },
+ };
+}
+
1;
use Devel::Dwarn;
use Data::Query::Renderer::SQL::Naive;
+use Data::Query::ExprHelpers qw(perl_scalar_value);
BEGIN { require 't/expr.include' }
expr_sql_is { !$_->foo }
[ "NOT foo" ],
"Unary expression ok";
+
+expr_sql_is { SELECT { $_->foo } }
+ [ "SELECT foo" ],
+ "Simple identifier";
+
+expr_sql_is { SELECT { $_->foo, 1 } }
+ # the extra space here is a little icky but Naive's _flatten_structure
+ # will need rewriting to fix it - commit bits available if you do it first
+ [ "SELECT foo , ?", perl_scalar_value(1) ],
+ "Identifier and literal";