move to default registration
[scpubgit/Q-Branch.git] / lib / SQL / Abstract / ExtraClauses.pm
1 package SQL::Abstract::ExtraClauses;
2
3 use strict;
4 use warnings;
5 use if $] < '5.010', 'MRO::Compat';
6 use mro 'c3';
7 use base qw(SQL::Abstract::Clauses);
8
9 BEGIN { *puke = \&SQL::Abstract::puke }
10
11 sub register_defaults {
12   my $self = shift;
13   $self->next::method(@_);
14   $self->clauses_of(
15     select => $self->clauses_of('select'), qw(group_by having)
16   );
17   $self->clause_expander('select.group_by', sub {
18     $_[0]->_expand_maybe_list_expr($_[1], -ident)
19   });
20   $self->clause_expander('select.having', sub {
21     $_[0]->expand_expr($_[1])
22   });
23   $self->{expand}{from_list} = '_expand_from_list';
24   $self->{render}{from_list} = '_render_from_list';
25   $self->{expand}{join} = '_expand_join';
26   $self->{render}{join} = '_render_join';
27   $self->{expand_op}{as} = '_expand_op_as';
28   $self->{expand}{as} = '_expand_op_as';
29   $self->{render}{as} = '_render_as';
30   splice(@{$self->{clauses_of}{update}}, 2, 0, 'from');
31   splice(@{$self->{clauses_of}{delete}}, 1, 0, 'using');
32   $self->{expand_clause}{'update.from'} = '_expand_select_clause_from';
33   $self->{expand_clause}{'delete.using'} = sub {
34     +(using => $_[0]->_expand_from_list(undef, $_[1]));
35   };
36   $self->{expand_clause}{'insert.rowvalues'} = sub {
37     (from => $_[0]->expand_expr({ -values => $_[1] }));
38   };
39   $self->{expand_clause}{'insert.select'} = sub {
40     (from => $_[0]->expand_expr({ -select => $_[1] }));
41   };
42   return $self;
43 }
44
45 sub _expand_select_clause_from {
46   my ($self, $from) = @_;
47   +(from => $self->_expand_from_list(undef, $from));
48 }
49
50 sub _expand_from_list {
51   my ($self, undef, $args) = @_;
52   if (ref($args) eq 'HASH') {
53     return { -from_list => [ $self->expand_expr($args) ] };
54   }
55   my @list;
56   my @args = ref($args) ? @$args : ($args);
57   while (my $entry = shift @args) {
58     if (!ref($entry) and $entry =~ /^-(.*)/) {
59       if ($1 eq 'as') {
60         $list[-1] = $self->expand_expr({ -as => [
61           $list[-1], map +(ref($_) eq 'ARRAY' ? @$_ : $_), shift(@args)
62         ]});
63         next;
64       }
65       $entry = { $entry => shift @args };
66     }
67     my $aqt = $self->expand_expr($entry, -ident);
68     if ($aqt->{-join} and not $aqt->{-join}{from}) {
69       $aqt->{-join}{from} = pop @list;
70     }
71     push @list, $aqt;
72   }
73   return { -from_list => \@list };
74 }
75
76 sub _expand_join {
77   my ($self, undef, $args) = @_;
78   my %proto = (
79     ref($args) eq 'HASH'
80       ? %$args
81       : (to => $args->[0], @{$args}[1..$#$args])
82   );
83   if (my $as = delete $proto{as}) {
84     $proto{to} = { -as => [ $proto{to}, ref($as) eq 'ARRAY' ? @$as : $as ] };
85   }
86   if (defined($proto{using}) and ref(my $using = $proto{using}) ne 'HASH') {
87     $proto{using} = { -row => [
88       map [ $self->expand_expr($_, -ident) ],
89         ref($using) eq 'ARRAY' ? @$using: $using
90     ] };
91   }
92   my %ret = map +($_ => $self->expand_expr($proto{$_}, -ident)),
93               sort keys %proto;
94   return +{ -join => \%ret };
95 }
96
97 sub _render_from_list {
98   my ($self, $list) = @_;
99   return $self->_join_parts(', ', map [ $self->render_aqt($_) ], @$list);
100 }
101
102 sub _render_join {
103   my ($self, $args) = @_;
104
105   my @parts = (
106     [ $self->render_aqt($args->{from}) ],
107     [ $self->_sqlcase(
108         ($args->{type}
109           ? join(' ', split '_', $args->{type}).' '
110           : ''
111         )
112         .'join'
113       )
114     ],
115     [ $self->render_aqt(
116         map +($_->{-ident} || $_->{-as} ? $_ : { -row => [ $_ ] }), $args->{to}
117     ) ],
118     ($args->{on} ? (
119       [ $self->_sqlcase('on') ],
120       [ $self->render_aqt($args->{on}) ],
121     ) : ()),
122     ($args->{using} ? (
123       [ $self->_sqlcase('using') ],
124       [ $self->render_aqt($args->{using}) ],
125     ) : ()),
126   );
127   return $self->_join_parts(' ', @parts);
128 }
129
130 sub _expand_op_as {
131   my ($self, undef, $vv, $k) = @_;
132   my @as = map $self->expand_expr($_, -ident),
133              (defined($k) ? ($k) : ()), ref($vv) eq 'ARRAY' ? @$vv : $vv;
134   return { -as => \@as };
135 }
136
137 sub _render_as {
138   my ($self, $args) = @_;
139   my ($thing, $as, @cols) = @$args;
140   return $self->_join_parts(
141     ' ',
142     [ $self->render_aqt($thing) ],
143     [ $self->_sqlcase('as') ],
144     (@cols
145       ? [ $self->_join_parts('',
146             [ $self->render_aqt($as) ],
147             [ '(' ],
148             [ $self->_join_parts(
149                 ', ',
150                 map [ $self->render_aqt($_) ], @cols
151             ) ],
152             [ ')' ],
153         ) ]
154       : [ $self->render_aqt($as) ]
155     ),
156   );
157 }
158
159 1;