File Coverage

blib/lib/SQL/Abstract/Plugin/ExtraClausesFixed.pm
Criterion Covered Total %
statement 37 38 97.3
branch 11 16 68.7
condition 3 6 50.0
subroutine 6 6 100.0
pod n/a
total 57 66 86.3


line stmt bran cond sub pod time code
1             package SQL::Abstract::Plugin::ExtraClausesFixed;
2 5     5   2790 use Moo;
  5         14  
  5         60  
3 5     5   4045 use experimental qw/signatures postderef/;
  5         14789  
  5         34  
4             # TODO - get this upstreamed - `using` is borken RN b/c
5              
6             our $VERSION = '0.01_4';
7             extends 'SQL::Abstract::Plugin::ExtraClauses';
8              
9 1         3 has no_setop_parens => (
10             is => 'lazy',
11 1     1   11 builder => sub ($self) {
  1         2  
12 1         6 my $details = $self->sqla->_connection_info;
13 1         8 return $details->{SQL_DBMS_NAME} eq 'SQLite';
14             }
15             );
16              
17             # NOTE - upstream impl fails to put `group_by` and `having` before the setops; that's
18             # fixed here
19             sub _expand_select {
20 42     42   15930 my ($self, $orig, $before_setop, @args) = @_;
21 42         215 my $exp = $self->sqla->$orig(@args);
22 42 100       27309 return $exp unless my $setop = (my $sel = $exp->{-select})->{setop};
23 1 50       9 if (my @keys = grep $sel->{$_}, @$before_setop, qw/group_by having/) {
24 1         3 my %inner;
25 1         2 @inner{@keys} = delete @{$sel}{@keys};
  1         5  
26 1         2 unshift @{ (values(%$setop))[0]{queries} }, { -select => \%inner };
  1         6  
27             }
28 1         10 return $exp;
29             }
30              
31             sub _render_setop {
32 1     1   116 my ($self, $setop, $args) = @_;
33 1 50       21 if ($self->no_setop_parens) {
34 1         2 for my $q (@{ $args->{queries} }) {
  1         3  
35 2 100       8 if ($q->{-literal}) {
36 1         32 $q->{-literal}[0] =~ s/^\(|\)$//g;
37             }
38             }
39             }
40             $self->join_query_parts(
41             { -keyword => ' ' . join('_', $setop, ($args->{type} || ())) . ' ' },
42             map $self->render_aqt($_, $self->no_setop_parens),
43 1   33     12 @{ $args->{queries} }
  1         24  
44             );
45             }
46              
47             # NOTE - upstream accidentally double expands `using`, so we need to replace that here
48             sub _expand_join {
49 4     4   1325 my ($self, undef, $args) = @_;
50 4 50       29 my %proto = (
51             ref($args) eq 'HASH'
52             ? %$args
53             : (to => @$args)
54             );
55 4 50       21 if (my $as = delete $proto{as}) {
56 0         0 $proto{to} = $self->expand_expr({ -as => [ { -from_list => $proto{to} }, $as ] });
57             }
58 4 100 66     23 if (defined($proto{using}) and ref(my $using = $proto{using}) ne 'HASH') {
59 2 50       13 $proto{using} = { -list => [ ref($using) eq 'ARRAY' ? @$using : $using ] };
60             }
61             my %ret = (
62             type => delete $proto{type},
63 4         91 to => $self->expand_expr({ -from_list => delete $proto{to} }, -ident),
64             );
65 4         1255 %ret = (%ret, map +($_ => $self->expand_expr($proto{$_}, -ident)), sort keys %proto);
66 4         1465 return +{ -join => \%ret };
67             }
68              
69             9092;
70              
71             =encoding utf8
72              
73             =head1 NAME
74              
75             SQL::Abstract::Plugin::ExtraClausesFixed - Fixes for ExtraClauses
76              
77             =head1 DESCRIPTION
78              
79             This is a subclass of SQL::Abstract::Plugin::ExtraClauses that fixes a few annoying bugs . Details below !
80              
81             B
82              
83             =head2 Using with DBIx::Class
84              
85             In order to use this with DBIx::Class, you simply need to apply the DBIC-SQLA2 plugin,
86             and then your SQLMaker will support these fixes!
87              
88             =head2 Bugs fixed
89              
90             =head3 using in -join
91              
92             The ExtraClauses plugin has a bug that it double expands the using option for joins, making them unusable unless you explicitly pass in a hashref. This fixes, that allowing you to do natural joins using multiple columns.
93              
94             =head3 setop inner select marshalling
95              
96             ExtraClauses has a bug where it puts the group_by and having clauses after setops (like UNION and friends). This is incorrect, the inner subquery is meant to have those clauses. This is fixed here.
97              
98             In order to use this feature, you must pass group_by or having with the bang override syntax ('!group_by' => ['things', 'and', 'stuff']). I may get an idea one day and figure out how to support it even with a bare group_by.
99              
100             =head3 SQLite setop parens
101              
102             Syntax across different DBMSs is annoying. DBIC likes assuming that you can arbitrarily
103             wrap subqueries in as many parens as you'd like. SQLite considers it a syntax error if the
104             queries that you join with a UNION are parenthesized. This class handles the selective
105             parenthesizing. It will also strip parens if necessary from the output of a $rs->as_query,
106             allowing you to use the setops in the most natural way.
107              
108             =cut