nested where nodes
[dbsrgits/Data-Query.git] / lib / Data / Query / Renderer / SQL / Slice / GenericSubquery.pm
CommitLineData
01d7143b 1package Data::Query::Renderer::SQL::Slice::GenericSubquery;
2
3use Data::Query::ExprHelpers;
4use Moo::Role;
5
6with 'Data::Query::Renderer::SQL::Slice::SubqueryRemap';
7
8b2c306b 8sub slice_stability {
9 (limit => 'requires', offset => 'requires');
10}
11
01d7143b 12sub _render_slice {
13 my ($self, $dq) = @_;
14 die "Slice's inner is not a Select"
15 unless is_Select my $orig_select = $dq->{from};
16 my %remapped = $self->_subquery_remap($orig_select);
17 my $first_from = $remapped{inner_body};
5a058623 18 # Should we simply strip until we reach a join/alias/etc. here?
19 $first_from = $first_from->{from}{from} if is_Having($first_from);
01d7143b 20 $first_from = $first_from->{from} if is_Where($first_from);
21 while (is_Join $first_from) {
22 $first_from = $first_from->{left};
23 }
24 $first_from = $first_from->{from} if is_Alias($first_from);
25 my $first_order = $remapped{inside_order}[0]{by};
26 my $count_col = $first_order->{elements}[-1];
27 my $count_alias = 'rownum__emulation';
28 my $count_sel = Select(
29 [ Operator({ 'SQL.Naive' => 'apply' }, [ Identifier('COUNT'), Identifier('*') ]) ],
30 Where(
31 Operator(
e31249d4 32 { 'SQL.Naive' => ($remapped{inside_order}[0]{reverse} ? '>' : '<') },
33 [
34 Identifier($count_alias, $count_col),
35 $remapped{outside_order}[0]{by}
36 ]
01d7143b 37 ),
38 Alias($count_alias, $first_from)
39 )
40 );
41 my $count_where = Operator(
42 { 'SQL.Naive' => ($dq->{offset} ? 'BETWEEN' : '<') },
43 [ $count_sel, (
44 $dq->{offset}
45 ? (
46 $dq->{offset},
47 {
48 %{$dq->{limit}},
49 value => $dq->{limit}{value}+$dq->{offset}{value}-1
50 }
51 )
52 : ($dq->{limit})
53 )
54 ]
55 );
56 return $self->render(
57 Select(
58 $remapped{outside_select_list},
59 (compose { no warnings 'once'; Order($b->{by}, $b->{reverse}, $a) }
60 @{$remapped{outside_order}},
61 Where(
62 $count_where,
63 Alias(
64 $remapped{default_inside_alias},
65 Select(
66 $remapped{inside_select_list},
67 $remapped{inner_body},
68 )
69 )
70 )
71 )
72 )
73 );
74}
75
761;