Commit | Line | Data |
01d7143b |
1 | package Data::Query::Renderer::SQL::Slice::GenericSubquery; |
2 | |
3 | use Data::Query::ExprHelpers; |
4 | use Moo::Role; |
5 | |
6 | with 'Data::Query::Renderer::SQL::Slice::SubqueryRemap'; |
7 | |
fbf38b8e |
8 | sub slice_subquery { |
9 | (limit => 1, offset => 1); |
10 | } |
11 | |
8b2c306b |
12 | sub slice_stability { |
13 | (limit => 'requires', offset => 'requires'); |
14 | } |
15 | |
01d7143b |
16 | sub _render_slice { |
17 | my ($self, $dq) = @_; |
18 | die "Slice's inner is not a Select" |
19 | unless is_Select my $orig_select = $dq->{from}; |
20 | my %remapped = $self->_subquery_remap($orig_select); |
21 | my $first_from = $remapped{inner_body}; |
5a058623 |
22 | # Should we simply strip until we reach a join/alias/etc. here? |
9c778d0f |
23 | STRIP: while ($first_from) { |
24 | if (is_Group($first_from)) { |
25 | $first_from = $first_from->{from}; |
26 | next STRIP; |
27 | } elsif (is_Where($first_from)) { |
28 | $first_from = $first_from->{from}; |
29 | next STRIP; |
30 | } elsif (is_Join($first_from)) { |
31 | $first_from = $first_from->{left}; |
32 | next STRIP; |
33 | } |
34 | last STRIP; |
01d7143b |
35 | } |
9c778d0f |
36 | die "WHAT" unless $first_from; |
01d7143b |
37 | $first_from = $first_from->{from} if is_Alias($first_from); |
9c778d0f |
38 | my @main_order; |
39 | foreach my $i (0..$#{$remapped{inside_order}}) { |
40 | my $order = $remapped{inside_order}[$i]; |
41 | my $outside = $remapped{outside_order}[$i]; |
42 | if (is_Identifier($order->{by}) |
43 | and ( |
44 | (@{$order->{by}{elements}} == 2 |
45 | and $order->{by}{elements}[0] eq $remapped{default_inside_alias}) |
46 | or (@{$order->{by}{elements}} == 1)) |
47 | ) { |
48 | push @main_order, [ |
1cc80bbd |
49 | $outside->{by}, $order->{by}{elements}[-1], $order->{reverse}, |
50 | $order->{nulls} |
9c778d0f |
51 | ]; |
52 | } else { |
53 | last; |
54 | } |
55 | } |
56 | |
01d7143b |
57 | my $count_alias = 'rownum__emulation'; |
9c778d0f |
58 | my ($op_and, $op_or) = map +{ 'SQL.Naive' => $_ }, qw(AND OR); |
59 | my $count_cond = compose { |
60 | my $lhs = $b->[0]; |
61 | my $rhs = Identifier($count_alias, $b->[1]); |
62 | ($lhs, $rhs) = ($rhs, $lhs) if $b->[2]; |
1cc80bbd |
63 | my $no_nulls = ($b->[3]||'') eq 'none'; |
64 | my ($this) = map { |
65 | $no_nulls |
66 | ? $_ |
67 | : Operator($op_or, [ |
68 | Operator($op_and, [ |
69 | Operator({ 'SQL.Naive' => 'IS NOT NULL' }, [ $lhs ]), |
70 | Operator({ 'SQL.Naive' => 'IS NULL' }, [ $rhs ]), |
9c778d0f |
71 | ]), |
1cc80bbd |
72 | $_ |
9c778d0f |
73 | ]) |
1cc80bbd |
74 | } Operator({ 'SQL.Naive' => '>' }, [ $lhs, $rhs ]); |
75 | my $final = ( |
76 | $a |
77 | ? Operator($op_or, [ |
78 | $this, |
79 | Operator($op_and, [ |
80 | (map { |
81 | $no_nulls |
82 | ? $_ |
83 | : Operator($op_or, [ |
84 | Operator($op_and, [ |
85 | map Operator({ 'SQL.Naive' => 'IS NULL' }, [ $_ ]), |
86 | $lhs, $rhs |
87 | ]), |
88 | $_, |
89 | ]) |
90 | } Operator({ 'SQL.Naive' => '=' }, [ $lhs, $rhs ])), |
91 | $a |
92 | ]) |
93 | ]) |
94 | : $this |
95 | ); |
96 | $final; |
9c778d0f |
97 | } @main_order, undef; |
01d7143b |
98 | my $count_sel = Select( |
99 | [ Operator({ 'SQL.Naive' => 'apply' }, [ Identifier('COUNT'), Identifier('*') ]) ], |
100 | Where( |
9c778d0f |
101 | $count_cond, |
01d7143b |
102 | Alias($count_alias, $first_from) |
103 | ) |
104 | ); |
105 | my $count_where = Operator( |
106 | { 'SQL.Naive' => ($dq->{offset} ? 'BETWEEN' : '<') }, |
107 | [ $count_sel, ( |
108 | $dq->{offset} |
109 | ? ( |
110 | $dq->{offset}, |
111 | { |
112 | %{$dq->{limit}}, |
113 | value => $dq->{limit}{value}+$dq->{offset}{value}-1 |
114 | } |
115 | ) |
116 | : ($dq->{limit}) |
117 | ) |
118 | ] |
119 | ); |
120 | return $self->render( |
121 | Select( |
122 | $remapped{outside_select_list}, |
e3335558 |
123 | (compose { no warnings 'once'; Order($b->{by}, $b->{reverse}, $b->{nulls}, $a) } |
01d7143b |
124 | @{$remapped{outside_order}}, |
125 | Where( |
126 | $count_where, |
127 | Alias( |
128 | $remapped{default_inside_alias}, |
129 | Select( |
130 | $remapped{inside_select_list}, |
131 | $remapped{inner_body}, |
132 | ) |
133 | ) |
134 | ) |
135 | ) |
136 | ) |
137 | ); |
138 | } |
139 | |
140 | 1; |