use Data::Query::ExprHelpers;
use Moo::Role;
+with 'Data::Query::Renderer::SQL::Slice::SubqueryRemap';
+
sub _render_slice_limit {
my ($self, $dq) = @_;
return [
];
}
+sub slice_subquery {
+ (offset => 1);
+}
+
+sub slice_stability {
+ (offset => 'requires');
+}
+
sub _slice_type { 'FetchFirst' }
sub _render_slice {
}
die "Slice's inner is not a Select"
unless is_Select my $orig_select = $dq->{from};
- my %alias_map;
- my $gensym_count;
- my (@inside_select_list, @outside_select_list);
- my $default_inside_alias;
- SELECT: foreach my $s (@{$orig_select->{select}}) {
- my $name;
- if (is_Alias $s) {
- $name = $s->{to};
- $s = $s->{from};
- }
- my $key;
- if (is_Identifier $s) {
- if (!$name and @{$s->{elements}} == 2) {
- $default_inside_alias ||= $s->{elements}[0];
- if ($s->{elements}[0] eq $default_inside_alias) {
- $alias_map{join('.',@{$s->{elements}})} = $s;
- push @inside_select_list, $s;
- push @outside_select_list, $s;
- next SELECT;
- }
- }
- $name ||= join('__', @{$s->{elements}});
- $key = join('.', @{$s->{elements}});
- } else {
- die "XXX not implemented yet" unless $name;
- $key = "$s";
- }
- $name ||= sprintf("GENSYM__%03i",++$gensym_count);
- push @inside_select_list, Alias($name, $s);
- push @outside_select_list, $alias_map{$key} = Identifier($name);
- }
- my $order = $orig_select->{from};
- my $order_gensym_count;
die "Slice's Select not followed by Order but order_is_stable set"
- unless is_Order $order;
- my (@order_nodes, %order_map);
- while (is_Order $order) {
- my $by = $order->{by};
- if (is_Identifier $by) {
- $default_inside_alias ||= $by->{elements}[0]
- if @{$by->{elements}} == 2;
- $order_map{$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);
- }
- };
- } else {
- die "XXX not implemented yet";
- }
- push @order_nodes, $order;
- $order = $order->{from};
- }
- my $inside_order = $order;
- $inside_order = Order($_->{by}, $_->{reverse}, $inside_order)
- for reverse @order_nodes;
- my $inside_select = Select(\@inside_select_list, $inside_order);
+ unless is_Order $orig_select->{from};
+
+ my %remapped = $self->_subquery_remap($orig_select);
+
+ 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}
};
- $default_inside_alias ||= 'me';
- my $bridge_from = Alias(
- $default_inside_alias,
- Slice(undef, $limit_plus_offset, $inside_select)
- );
- my $outside_order = $bridge_from;
- $outside_order = Order($order_map{$_->{by}}, !$_->{reverse}, $outside_order)
- for reverse @order_nodes;
- my $outside_select = Select(
- (
+
+ return $self->_render(
+ map {
$dq->{preserve_order}
- ? [
+ ? Select(
+ \@outside_select_list,
+ compose {
+ Order($b->{by}, $b->{reverse}, $b->{nulls}, $a)
+ } (
+ @outside_order,
+ Alias($default_inside_alias, $_)
+ )
+ )
+ : $_
+ } (
+ Slice(
+ undef, $dq->{limit},
+ Select(
+ [
@outside_select_list,
- grep @{$_->{elements}} == 1, @order_map{map $_->{by}, @order_nodes}
- ]
- : \@outside_select_list,
- ),
- $outside_order,
+ $dq->{preserve_order}
+ ? (grep @{$_->{elements}} == 1,
+ map $_->{by}, @outside_order)
+ : (),
+ ],
+ compose {
+ Order($b->{by}, !$b->{reverse}, -($b->{nulls}||0), $a)
+ } (
+ @outside_order,
+ Alias(
+ $default_inside_alias,
+ Slice(
+ undef, $limit_plus_offset,
+ Select(
+ \@inside_select_list,
+ compose {
+ Order($b->{by}, $b->{reverse}, $b->{nulls}, $a)
+ } @inside_order, $inner_body
+ )
+ )
+ )
+ )
+ )
+ )
+ )
);
- my $final = Slice(undef, $dq->{limit}, $outside_select);
- if ($dq->{preserve_order}) {
- $final = Alias($default_inside_alias, $final);
- $final = Order($order_map{$_->{by}}, $_->{reverse}, $final)
- for reverse @order_nodes;
- $final = Select(\@outside_select_list, $final);
- }
- return $self->_render($final);
}
1;