use Data::Query::ExprHelpers;
use Moo::Role;
+with 'Data::Query::Renderer::SQL::Slice::SubqueryRemap';
+
sub _render_slice_limit {
my ($self, $dq) = @_;
return [
];
}
+sub slice_stability {
+ (offset => 'requires');
+}
+
sub _slice_type { 'FetchFirst' }
sub _render_slice {
die "Slice's Select not followed by Order but order_is_stable set"
unless is_Order $orig_select->{from};
- my $gensym_count;
- my $default_inside_alias;
-
- my @inside_select_list = map {
- if (is_Alias) {
- $_;
- } elsif (is_Identifier) {
- my @el = @{$_->{elements}};
- if (@el == 2 and $el[0] eq ($default_inside_alias ||= $el[0])) {
- $_;
- } else {
- Alias(join('__', @el), $_);
- }
- } else {
- Alias(sprintf("GENSYM__%03i",++$gensym_count), $_);
- }
- } @{$orig_select->{select}};
-
- my %alias_map = map {
- if (is_Alias and is_Identifier $_->{from}) {
- +(join('.',@{$_->{from}{elements}}) => Identifier($_->{to}))
- } elsif (is_Identifier) {
- +(join('.',@{$_->{elements}}) => $_)
- } else {
- +()
- }
- } @inside_select_list;
-
- my @outside_select_list = map {
- if (is_Alias) {
- Identifier($_->{to});
- } else {
- $_;
- }
- } @inside_select_list;
-
- my @order_nodes;
- my $inner_body = do {
- my $order = $orig_select->{from};
- while (is_Order $order) {
- push @order_nodes, $order;
- $order = $order->{from};
- }
- $order;
- };
-
- my $order_gensym_count;
- my @mapped_order = map {
- my $by = $_->{by};
- if (is_Identifier $by) {
- $default_inside_alias ||= $by->{elements}[0]
- if @{$by->{elements}} == 2;
- my $mapped_by
- = $alias_map{join('.', @{$by->{elements}})}
- ||= do {
- if (
- @{$by->{elements}} == 2
- and $by->{elements}[0] eq $default_inside_alias
- ) {
- $by;
- } else {
- my $name = sprintf("ORDER__BY__%03i",++$order_gensym_count);
- push @inside_select_list, Alias($name, $by);
- Identifier($name);
- }
- };
- Order($mapped_by, $_->{reverse});
- } else {
- die "XXX not implemented yet";
- }
- } @order_nodes;
+ my %remapped = $self->_subquery_remap($orig_select);
- $default_inside_alias ||= 'me';
+ my @inside_select_list = @{$remapped{inside_select_list}};
+ my @outside_select_list = @{$remapped{outside_select_list}};
+ my @inside_order = @{$remapped{inside_order}};
+ my @outside_order = @{$remapped{outside_order}};
+ my $default_inside_alias = $remapped{default_inside_alias};
+ my $inner_body = $remapped{inner_body};
my $limit_plus_offset = +{
%{$dq->{limit}}, value => $dq->{limit}{value} + $dq->{offset}{value}
? Select(
\@outside_select_list,
compose {
- Order($b->{by}, $b->{reverse}, $a)
+ Order($b->{by}, $b->{reverse}, $b->{nulls}, $a)
} (
- @mapped_order,
+ @outside_order,
Alias($default_inside_alias, $_)
)
)
@outside_select_list,
$dq->{preserve_order}
? (grep @{$_->{elements}} == 1,
- map $_->{by}, @mapped_order)
+ map $_->{by}, @outside_order)
: (),
],
compose {
- Order($b->{by}, !$b->{reverse}, $a)
+ Order($b->{by}, !$b->{reverse}, -($b->{nulls}||0), $a)
} (
- @mapped_order,
+ @outside_order,
Alias(
$default_inside_alias,
Slice(
Select(
\@inside_select_list,
compose {
- Order($b->{by}, $b->{reverse}, $a)
- } @order_nodes, $inner_body
+ Order($b->{by}, $b->{reverse}, $b->{nulls}, $a)
+ } @inside_order, $inner_body
)
)
)