116bbb267087da6cae9df396b467357684d97b78
[dbsrgits/Data-Query.git] / lib / Data / Query / Renderer / SQL / MySQL.pm
1 package Data::Query::Renderer::SQL::MySQL;
2
3 sub map_descending (&;@) {
4   my ($block, $in) = @_;
5   local $_ = $in;
6   $_ = $block->($_) if ref($_) eq 'HASH';
7   if (ref($_) eq 'REF' and ref($$_) eq 'HASH') {
8     $$_;
9   } elsif (ref($_) eq 'HASH') {
10     my $mapped = $_;
11     local $_;
12     +{ map +($_ => &map_descending($block, $mapped->{$_})), keys %$mapped };
13   } elsif (ref($_) eq 'ARRAY') {
14     [ map &map_descending($block, $_), @$_ ]
15   } else {
16     $_
17   }
18 }
19
20 use Data::Query::Constants;
21 use Data::Query::ExprHelpers;
22 use Moo;
23
24 extends 'Data::Query::Renderer::SQL::Naive';
25
26 with 'Data::Query::Renderer::SQL::Slice::LimitXY';
27
28 sub _insert_default_values {
29   my ($self) = @_;
30   $self->_format_keyword('VALUES'), qw( ( ) );
31 }
32
33 foreach my $type (qw(update delete)) {
34   around "_render_${type}" => sub {
35     my ($orig, $self) = (shift, shift);
36     $self->$orig($self->_maybe_double_subquery(@_));
37   };
38 }
39
40 sub _maybe_double_subquery {
41   my ($self, $dq) = @_;
42   my $target = $dq->{target};
43   my $new = { %$dq };
44   foreach my $key (qw(set where)) {
45     next unless $dq->{$key};
46     $new->{$key} = map_descending {
47       if (is_Select) {
48         my $found;
49         scan_dq_nodes(do {
50           if (is_Identifier($target)) {
51             my $ident = $target->{elements}[0];
52             +{ DQ_IDENTIFIER ,=> sub {
53                  my @el = @{$_[0]->{elements}};
54                  $found = 1 if @el == 1 and $el[0] eq $ident;
55                }
56             };
57           } elsif (is_Literal($target)) {
58             my $ident = $target->{literal} or die "Can't handle complex literal";
59             +{ DQ_LITERAL ,=> sub {
60                  my $lit = $_[0]->{literal};
61                  $found = 1 if $lit and $lit eq $ident;
62                }
63             };
64           } else {
65             die "Can't handle target type ".$target->{type};
66           }
67         }, $_);
68         if ($found) {
69           \Select([ Identifier('*') ], Alias('_forced_double_subquery', $_));
70         } else {
71           $_
72         }
73       } else {
74         $_
75       }
76     } $dq->{$key};
77   }
78   $new;
79 }
80
81 1;