From: Peter Rabbitson Date: Tue, 2 Sep 2014 02:20:26 +0000 (+0200) Subject: Make sure empty cond collapser works on all positions X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=22485a7ea98d355acc7dc5432550d10dba0dee5e;p=dbsrgits%2FDBIx-Class-Historic.git Make sure empty cond collapser works on all positions Adds another round of sql stabilization (akin to 5268b1da6) --- diff --git a/lib/DBIx/Class/Storage/DBIHacks.pm b/lib/DBIx/Class/Storage/DBIHacks.pm index 90bade8..e172299 100644 --- a/lib/DBIx/Class/Storage/DBIHacks.pm +++ b/lib/DBIx/Class/Storage/DBIHacks.pm @@ -1076,36 +1076,41 @@ sub _collapse_cond { return $fin; } elsif (ref $where eq 'ARRAY') { - my @w = @$where; - while ( @w and ( - (ref $w[0] eq 'ARRAY' and ! @{$w[0]} ) - or - (ref $w[0] eq 'HASH' and ! keys %{$w[0]}) - )) { shift @w }; + # we are always at top-level here, it is safe to dump empty *standalone* pieces + my $fin_idx; - return unless @w; + for (my $i = 0; $i <= $#$where; $i++ ) { - if ( @w == 1 ) { - return ( length ref $w[0] ) - ? $self->_collapse_cond($w[0]) - : { $w[0] => undef } - ; - } - elsif ( @w == 2 and ! length ref $w[0]) { - if ( ( $w[0]||'' ) =~ /^\-and$/i ) { - return (ref $w[1] eq 'HASH' or ref $w[1] eq 'ARRAY') - ? $self->_collapse_cond($w[1], (ref $w[1] eq 'ARRAY') ) - : $self->throw_exception("Unsupported top-level op/arg pair: [ $w[0] => $w[1] ]") - ; + my $logic_mod = lc ( ($where->[$i] =~ /^(\-(?:and|or))$/i)[0] || '' ); + + if ($logic_mod) { + $i++; + $self->throw_exception("Unsupported top-level op/arg pair: [ $logic_mod => $where->[$i] ]") + unless ref $where->[$i] eq 'HASH' or ref $where->[$i] eq 'ARRAY'; + + my $sub_elt = $self->_collapse_cond({ $logic_mod => $where->[$i] }) + or next; + + $fin_idx->{ serialize $sub_elt } = $sub_elt; + } + elsif (! length ref $where->[$i] ) { + $fin_idx->{"$where->[$i]_$i"} = $self->_collapse_cond({ @{$where}[$i, $i+1] }) || next; + $i++; } else { - return $self->_collapse_cond({ @w }); + $fin_idx->{ serialize $where->[$i] } = $self->_collapse_cond( $where->[$i] ) || next; } } - else { - return { -or => \@w }; - } + + return unless $fin_idx; + + return ( keys %$fin_idx == 1 ) ? (values %$fin_idx)[0] : { + -or => [ map + { ref $fin_idx->{$_} eq 'HASH' ? %{$fin_idx->{$_}} : $fin_idx->{$_} } + sort keys %$fin_idx + ] + }; } else { # not a hash not an array diff --git a/t/sqlmaker/dbihacks_internals.t b/t/sqlmaker/dbihacks_internals.t index 1214638..1ad550a 100644 --- a/t/sqlmaker/dbihacks_internals.t +++ b/t/sqlmaker/dbihacks_internals.t @@ -179,6 +179,25 @@ for my $t ( efcc_result => {}, sql => '', }, + { + where => { -or => [ foo => 1, $_ ] }, + cc_result => { foo => 1 }, + efcc_result => { foo => 1 }, + sql => 'WHERE foo = ?', + }, + { + where => { -or => [ $_, foo => 1 ] }, + cc_result => { foo => 1 }, + efcc_result => { foo => 1 }, + sql => 'WHERE foo = ?', + }, + { + where => { -and => [ fuu => 2, $_, foo => 1 ] }, + sql => 'WHERE fuu = ? AND foo = ?', + collapsed_sql => 'WHERE foo = ? AND fuu = ?', + cc_result => { foo => 1, fuu => 2 }, + efcc_result => { foo => 1, fuu => 2 }, + }, } ( # bare [], {},