1 package Data::Query::Renderer::SQL::Slice::FetchFirst;
3 use Data::Query::Constants qw(
4 DQ_SELECT DQ_ALIAS DQ_IDENTIFIER DQ_ORDER DQ_SLICE
10 unless ($dq->{offset}) {
12 ($dq->{from} ? $self->_render($dq->{from}) : ()),
13 $self->_format_keyword('FETCH FIRST'),
14 sprintf("%i", $dq->{limit}{value}),
15 $self->_format_keyword('ROWS ONLY')
18 unless ($dq->{order_is_stable}) {
19 die "FetchFirst limit style requires a stable order";
21 die "Slice's inner is not a Select"
22 unless (my $orig_select = $dq->{from})->{type} eq DQ_SELECT;
25 my (@inside_select_list, @outside_select_list);
26 my $default_inside_alias;
27 SELECT: foreach my $s (@{$orig_select->{select}}) {
29 if ($s->{type} eq DQ_ALIAS) {
34 if ($s->{type} eq DQ_IDENTIFIER) {
35 if (@{$s->{elements}} == 2) {
36 $default_inside_alias ||= $s->{elements}[0];
37 if ($s->{elements}[0] eq $default_inside_alias) {
38 $alias_map{join('.',@{$s->{elements}})} = $s;
39 push @inside_select_list, $s;
40 push @outside_select_list, $s;
44 $name ||= join('__', @{$s->{elements}});
45 $key = join('.', @{$s->{elements}});
47 die "XXX not implemented yet";
49 $name ||= sprintf("GENSYM__%03i",++$gensym_count);
50 push @inside_select_list, +{
55 push @outside_select_list, $alias_map{$key} = +{
56 type => DQ_IDENTIFIER,
60 my $order = $orig_select->{from};
61 my $order_gensym_count;
62 die "Slice's Select not followed by Order but order_is_stable set"
63 unless $order->{type} eq DQ_ORDER;
64 my (@order_nodes, %order_map);
65 while ($order->{type} eq DQ_ORDER) {
66 my $by = $order->{by};
67 if ($by->{type} eq DQ_IDENTIFIER) {
69 = $alias_map{join('.', @{$by->{elements}})}
71 my $name = sprintf("ORDER__BY__%03i",++$order_gensym_count);
72 push @inside_select_list, +{
78 type => DQ_IDENTIFIER,
79 elements => [ $name ],
83 die "XXX not implemented yet";
85 push @order_nodes, $order;
86 $order = $order->{from};
88 my $inside_order = $order;
92 reverse => $_->{reverse},
94 } for reverse @order_nodes;
95 my $inside_select = +{
97 select => \@inside_select_list,
98 from => $inside_order,
100 my $limit_plus_offset = +{
101 %{$dq->{limit}}, value => $dq->{limit}{value} + $dq->{offset}{value}
103 $default_inside_alias ||= 'me';
106 to => $default_inside_alias,
109 limit => $limit_plus_offset,
110 from => $inside_select,
113 my $outside_order = $bridge_from;
116 by => $order_map{$_->{by}},
117 reverse => !$_->{reverse},
118 from => $outside_order
119 } for reverse @order_nodes;
120 my $outside_select = +{
123 $dq->{preserve_order}
125 @outside_select_list,
126 grep @{$_->{elements}} == 1, @order_map{map $_->{by}, @order_nodes}
128 : \@outside_select_list,
130 from => $outside_order,
134 limit => $dq->{limit},
135 from => $outside_select
137 if ($dq->{preserve_order}) {
141 to => $default_inside_alias,
145 by => $order_map{$_->{by}},
146 reverse => $_->{reverse},
148 } for reverse @order_nodes;
151 select => \@outside_select_list,
155 return $self->_render($final);