}
}
- return unless $fin_idx;
-
- $fin = ( keys %$fin_idx == 1 ) ? (values %$fin_idx)[0] : {
- -or => [ map {
- # unroll single-element hashes
- ( ref $fin_idx->{$_} eq 'HASH' and keys %{$fin_idx->{$_}} == 1 )
- ? %{$fin_idx->{$_}}
- : $fin_idx->{$_}
- } sort keys %$fin_idx ]
- };
+ if (! $fin_idx) {
+ return;
+ }
+ elsif ( keys %$fin_idx == 1 ) {
+ $fin = (values %$fin_idx)[0];
+ }
+ else {
+ my @or;
+
+ # at this point everything is at most one level deep - unroll if needed
+ for (sort keys %$fin_idx) {
+ if ( ref $fin_idx->{$_} eq 'HASH' and keys %{$fin_idx->{$_}} == 1 ) {
+ my ($l, $r) = %{$fin_idx->{$_}};
+
+ if (
+ ref $r eq 'ARRAY'
+ and
+ (
+ ( @$r == 1 and $l =~ /^\-and$/i )
+ or
+ $l =~ /^\-or$/i
+ )
+ ) {
+ push @or, @$r
+ }
+
+ elsif (
+ ref $r eq 'HASH'
+ and
+ keys %$r == 1
+ and
+ $l =~ /^\-(?:and|or)$/i
+ ) {
+ push @or, %$r;
+ }
+
+ else {
+ push @or, $l, $r;
+ }
+ }
+ else {
+ push @or, $fin_idx->{$_};
+ }
+ }
+
+ $fin->{-or} = \@or;
+ }
}
else {
# not a hash not an array
- $fin = { '' => $where };
+ $fin = { -and => [ $where ] };
}
# unroll single-element -and's
%$fin, %{$and->[0]}
};
}
+ else {
+ $fin->{-and} = $and;
+ last;
+ }
}
# compress same-column conds found in $fin
},
{
where => { -and => [ \'foo=bar', [ { artistid => { '=', $num } } ], { name => 'Caterwauler McCrae'} ] },
- cc_result => { '' => \'foo=bar', name => 'Caterwauler McCrae', artistid => $num },
+ cc_result => { -and => [ \'foo=bar' ], name => 'Caterwauler McCrae', artistid => $num },
sql => 'WHERE foo=bar AND artistid = ? AND name = ?',
efcc_result => { name => 'Caterwauler McCrae', artistid => $num },
},
{
+ where => { -and => [ \'foo=bar', [ { artistid => { '=', $num } } ], { name => 'Caterwauler McCrae'}, \'buzz=bozz' ] },
+ cc_result => { -and => [ \'foo=bar', \'buzz=bozz' ], name => 'Caterwauler McCrae', artistid => $num },
+ sql => 'WHERE foo=bar AND artistid = ? AND name = ? AND buzz=bozz',
+ collapsed_sql => 'WHERE foo=bar AND buzz=bozz AND artistid = ? AND name = ?',
+ efcc_result => { name => 'Caterwauler McCrae', artistid => $num },
+ },
+ {
where => { artistid => [ $num ], rank => [ 13, 2, 3 ], charfield => [ undef ] },
cc_result => { artistid => $num, charfield => undef, rank => [13, 2, 3] },
sql => 'WHERE artistid = ? AND charfield IS NULL AND ( rank = ? OR rank = ? OR rank = ? )',
[ { 'me.title' => 'Spoonful of bees' } ],
]},
cc_result => {
- '' => \[
+ -and => [ \[
"LOWER(me.title) LIKE ?",
'%spoon%',
- ],
+ ]],
'me.title' => 'Spoonful of bees',
},
sql => 'WHERE LOWER(me.title) LIKE ? AND me.title = ?',
efcc_result => { 'me.title' => 'Spoonful of bees' },
- }
+ },
+
+ # crazy literals
+ {
+ where => {
+ -or => [
+ \'foo = bar',
+ ],
+ },
+ sql => 'WHERE foo = bar',
+ cc_result => {
+ -and => [
+ \'foo = bar',
+ ],
+ },
+ efcc_result => {},
+ },
+ {
+ where => {
+ -or => [
+ \'foo = bar',
+ \'baz = ber',
+ ],
+ },
+ sql => 'WHERE foo = bar OR baz = ber',
+ collapsed_sql => 'WHERE baz = ber OR foo = bar',
+ cc_result => {
+ -or => [
+ \'baz = ber',
+ \'foo = bar',
+ ],
+ },
+ efcc_result => {},
+ },
+ {
+ where => {
+ -and => [
+ \'foo = bar',
+ \'baz = ber',
+ ],
+ },
+ sql => 'WHERE foo = bar AND baz = ber',
+ cc_result => {
+ -and => [
+ \'foo = bar',
+ \'baz = ber',
+ ],
+ },
+ efcc_result => {},
+ },
+ {
+ where => {
+ -and => [
+ \'foo = bar',
+ \'baz = ber',
+ x => { -ident => 'y' },
+ ],
+ },
+ sql => 'WHERE foo = bar AND baz = ber AND x = y',
+ cc_result => {
+ -and => [
+ \'foo = bar',
+ \'baz = ber',
+ ],
+ x => { '=' => { -ident => 'y' } }
+ },
+ efcc_result => { x => { -ident => 'y' } },
+ },
) {
for my $w (
is_same_sql ( $generated_sql, $t->{sql}, "Expected SQL from $name" )
if exists $t->{sql};
- my $collapsed_cond = $schema->storage->_collapse_cond($w);
-
is_same_sql(
- ($sm->where($collapsed_cond))[0],
+ ($sm->where($t->{cc_result}))[0],
( $t->{collapsed_sql} || $t->{sql} || $generated_sql ),
"Collapse did not alter *the semantics* of the final SQL based on $name",
);
+ my $collapsed_cond = $schema->storage->_collapse_cond($w);
+
is_deeply(
$collapsed_cond,
$t->{cc_result},