Commit | Line | Data |
0446ca9c |
1 | package Data::Query::Renderer::SQL::Slice::FetchFirst; |
2 | |
6b45ffe4 |
3 | use Data::Query::ExprHelpers; |
0446ca9c |
4 | use Moo::Role; |
5 | |
3482f7c8 |
6 | sub _render_slice_limit { |
7 | my ($self, $dq) = @_; |
8 | return [ |
9 | ($dq->{from} ? $self->_render($dq->{from}) : ()), |
10 | $self->_format_keyword('FETCH FIRST'), |
11 | sprintf("%i", $dq->{limit}{value}), |
12 | $self->_format_keyword('ROWS ONLY') |
13 | ]; |
14 | } |
15 | |
16 | sub _slice_type { 'FetchFirst' } |
17 | |
0446ca9c |
18 | sub _render_slice { |
19 | my ($self, $dq) = @_; |
20 | unless ($dq->{offset}) { |
3482f7c8 |
21 | return $self->_render_slice_limit($dq); |
0446ca9c |
22 | } |
23 | unless ($dq->{order_is_stable}) { |
3482f7c8 |
24 | die $self->_slice_type." limit style requires a stable order"; |
0446ca9c |
25 | } |
26 | die "Slice's inner is not a Select" |
6b45ffe4 |
27 | unless is_Select my $orig_select = $dq->{from}; |
22f934ee |
28 | die "Slice's Select not followed by Order but order_is_stable set" |
29 | unless is_Order $orig_select->{from}; |
30 | |
0446ca9c |
31 | my $gensym_count; |
0446ca9c |
32 | my $default_inside_alias; |
22f934ee |
33 | |
34 | my @inside_select_list = map { |
35 | if (is_Alias) { |
36 | $_; |
37 | } elsif (is_Identifier) { |
38 | my @el = @{$_->{elements}}; |
39 | if (@el == 2 and $el[0] eq ($default_inside_alias ||= $el[0])) { |
40 | $_; |
41 | } else { |
42 | Alias(join('__', @el), $_); |
0446ca9c |
43 | } |
0446ca9c |
44 | } else { |
22f934ee |
45 | Alias(sprintf("GENSYM__%03i",++$gensym_count), $_); |
0446ca9c |
46 | } |
22f934ee |
47 | } @{$orig_select->{select}}; |
48 | |
49 | my %alias_map = map { |
50 | if (is_Alias and is_Identifier $_->{from}) { |
51 | +(join('.',@{$_->{from}{elements}}) => Identifier($_->{to})) |
52 | } elsif (is_Identifier) { |
53 | +(join('.',@{$_->{elements}}) => $_) |
54 | } else { |
55 | +() |
56 | } |
57 | } @inside_select_list; |
58 | |
59 | my @outside_select_list = map { |
60 | if (is_Alias) { |
61 | Identifier($_->{to}); |
62 | } else { |
63 | $_; |
64 | } |
65 | } @inside_select_list; |
66 | |
67 | my @order_nodes; |
68 | my $inner_body = do { |
69 | my $order = $orig_select->{from}; |
70 | while (is_Order $order) { |
71 | push @order_nodes, $order; |
72 | $order = $order->{from}; |
73 | } |
74 | $order; |
75 | }; |
76 | |
0446ca9c |
77 | my $order_gensym_count; |
e82795ba |
78 | my @mapped_order = map { |
79 | my $by = $_->{by}; |
6b45ffe4 |
80 | if (is_Identifier $by) { |
3482f7c8 |
81 | $default_inside_alias ||= $by->{elements}[0] |
82 | if @{$by->{elements}} == 2; |
e82795ba |
83 | my $mapped_by |
0446ca9c |
84 | = $alias_map{join('.', @{$by->{elements}})} |
85 | ||= do { |
3482f7c8 |
86 | if ( |
87 | @{$by->{elements}} == 2 |
88 | and $by->{elements}[0] eq $default_inside_alias |
89 | ) { |
90 | $by; |
91 | } else { |
92 | my $name = sprintf("ORDER__BY__%03i",++$order_gensym_count); |
6b45ffe4 |
93 | push @inside_select_list, Alias($name, $by); |
94 | Identifier($name); |
3482f7c8 |
95 | } |
0446ca9c |
96 | }; |
e82795ba |
97 | Order($mapped_by, $_->{reverse}); |
0446ca9c |
98 | } else { |
99 | die "XXX not implemented yet"; |
100 | } |
e82795ba |
101 | } @order_nodes; |
22f934ee |
102 | |
9fcc2256 |
103 | $default_inside_alias ||= 'me'; |
22f934ee |
104 | |
0446ca9c |
105 | my $limit_plus_offset = +{ |
106 | %{$dq->{limit}}, value => $dq->{limit}{value} + $dq->{offset}{value} |
107 | }; |
22f934ee |
108 | |
9fcc2256 |
109 | return $self->_render( |
110 | map { |
0446ca9c |
111 | $dq->{preserve_order} |
9fcc2256 |
112 | ? Select( |
113 | \@outside_select_list, |
114 | compose { |
e82795ba |
115 | Order($b->{by}, $b->{reverse}, $a) |
60cbee33 |
116 | } ( |
e82795ba |
117 | @mapped_order, |
60cbee33 |
118 | Alias($default_inside_alias, $_) |
119 | ) |
9fcc2256 |
120 | ) |
121 | : $_ |
60cbee33 |
122 | } ( |
123 | Slice( |
9fcc2256 |
124 | undef, $dq->{limit}, |
125 | Select( |
126 | [ |
1bfa648a |
127 | @outside_select_list, |
9fcc2256 |
128 | $dq->{preserve_order} |
129 | ? (grep @{$_->{elements}} == 1, |
e82795ba |
130 | map $_->{by}, @mapped_order) |
9fcc2256 |
131 | : (), |
132 | ], |
133 | compose { |
e82795ba |
134 | Order($b->{by}, !$b->{reverse}, $a) |
9fcc2256 |
135 | } ( |
e82795ba |
136 | @mapped_order, |
9fcc2256 |
137 | Alias( |
138 | $default_inside_alias, |
139 | Slice( |
140 | undef, $limit_plus_offset, |
141 | Select( |
142 | \@inside_select_list, |
143 | compose { |
144 | Order($b->{by}, $b->{reverse}, $a) |
145 | } @order_nodes, $inner_body |
146 | ) |
147 | ) |
148 | ) |
149 | ) |
150 | ) |
151 | ) |
60cbee33 |
152 | ) |
6b45ffe4 |
153 | ); |
0446ca9c |
154 | } |
155 | |
156 | 1; |