import sqlmaker work from the dq branch
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / SQLMaker / Renderer / OracleJoins.pm
CommitLineData
10cef607 1package DBIx::Class::SQLMaker::Renderer::OracleJoins;
2
3sub map_descending (&;@) {
4 my ($block, $in) = @_;
5 local $_ = $in;
6 $_ = $block->($_) if ref($_) eq 'HASH';
7#::Dwarn([mapped => $_]);
8 if (ref($_) eq 'REF' and ref($$_) eq 'HASH') {
9 $$_;
10 } elsif (ref($_) eq 'HASH') {
11#::Dwarn([unmapped => $_]);
12#::Dwarn([mapped => $mapped]);
13 my $mapped = $_;
14 local $_;
15 +{ map +($_ => &map_descending($block, $mapped->{$_})), keys %$mapped };
16 } elsif (ref($_) eq 'ARRAY') {
17 [ map &map_descending($block, $_), @$_ ]
18 } else {
19 $_
20 }
21}
22
23use Data::Query::ExprHelpers;
24use Moo;
25use namespace::clean;
26
27extends 'Data::Query::Renderer::SQL::Naive';
28
29around render => sub {
30 my ($orig, $self) = (shift, shift);
31 $self->$orig($self->_oracle_joins_unroll(@_));
32};
33
34sub _oracle_joins_unroll {
35 my ($self, $dq) = @_;
36 map_descending {
37#warn "here";
38#::Dwarn([unroll => $_]);
39 return $_ unless is_Join;
40 return \$self->_oracle_joins_mangle_join($_);
41 } $dq;
42}
43
44sub _oracle_joins_mangle_join {
45 my ($self, $dq) = @_;
46 my ($mangled, $where) = $self->_oracle_joins_recurse_join($dq);
47 Where(
48 (@$where > 1
49 ? Operator({ 'SQL.Naive' => 'and' }, $where)
50 : $where->[0]),
51 $mangled
52 );
53}
54
55sub _oracle_joins_recurse_join {
56 my ($self, $dq) = @_;
57 die "Can't handle cross join" unless $dq->{on};
58 my $mangled = { %$dq };
59 delete $mangled->{on};
60 my @where;
61 my %idents;
62 foreach my $side (qw(left right)) {
63 if (is_Join $dq->{$side}) {
64 ($mangled->{$side}, my ($side_where, $side_idents))
65 = $self->_oracle_joins_recurse_join($dq->{$side});
66 push @where, $side_where;
67 $idents{$side} = $side_idents;
68 } else {
69 if (is_Identifier($dq->{$side})) {
70 $idents{$side} = { join($;, @{$dq->{$side}{elements}}) => 1 };
71 } elsif (is_Alias($dq->{$side})) {
72 $idents{$side} = { $dq->{$side}{to} => 1 };
73 }
74 $mangled->{$side} = $self->_oracle_joins_unroll($dq->{$side});
75 }
76 }
77 my %other = (left => 'right', right => 'left');
78 unshift @where, (
79 $dq->{outer}
80 ? map_descending {
81 return $_
82 if is_Operator and ($_->{operator}{'SQL.Naive'}||'') eq '(+)';
83 return $_ unless is_Identifier;
84 die "Can't unroll single part identifiers in on"
85 unless @{$_->{elements}} > 1;
86 my $check = join($;, @{$_->{elements}}[0..($#{$_->{elements}}-1)]);
87 if ($idents{$other{$dq->{outer}}}{$check}) {
88 return \Operator({ 'SQL.Naive' => '(+)' }, [ $_ ]);
89 }
90 return $_;
91 } $dq->{on}
92 : $dq->{on}
93 );
94 return ($mangled, \@where, { map %{$_||{}}, @idents{qw(left right)} });
95}
96
97around _default_simple_ops => sub {
98 my ($orig, $self) = (shift, shift);
99 +{
100 %{$self->$orig(@_)},
101 '(+)' => 'unop_reverse',
102 };
103};
104
1051;