use Scalar::Util qw/blessed weaken reftype/;
use DBIx::Class::_Util 'fail_on_internal_wantarray';
use Try::Tiny;
-use Data::Compare (); # no imports!!! guard against insane architecture
+use Data::Dumper::Concise ();
use Data::Query::Constants;
use Data::Query::ExprHelpers;
# not importing first() as it will clash with our own method
sub _stack_cond {
my ($self, $left, $right) = @_;
- # collapse single element top-level conditions
- # (single pass only, unlikely to need recursion)
- for ($left, $right) {
- if (ref $_ eq 'ARRAY') {
- if (@$_ == 0) {
- $_ = undef;
- }
- elsif (@$_ == 1) {
- $_ = $_->[0];
- }
- }
- elsif (ref $_ eq 'HASH') {
- my ($first, $more) = keys %$_;
-
- # empty hash
- if (! defined $first) {
- $_ = undef;
- }
- # one element hash
- elsif (! defined $more) {
- if ($first eq '-and' and ref $_->{'-and'} eq 'HASH') {
- $_ = $_->{'-and'};
- }
- elsif ($first eq '-or' and ref $_->{'-or'} eq 'ARRAY') {
- $_ = $_->{'-or'};
- }
- }
- }
- }
+ my $source = $self->result_source;
- # merge hashes with weeding out of duplicates (simple cases only)
- if (ref $left eq 'HASH' and ref $right eq 'HASH') {
+ my $converter = $source->schema->storage->sql_maker->converter;
- # shallow copy to destroy
- $right = { %$right };
- for (grep { exists $right->{$_} } keys %$left) {
- # the use of eq_deeply here is justified - the rhs of an
- # expression can contain a lot of twisted weird stuff
- delete $right->{$_} if Data::Compare::Compare( $left->{$_}, $right->{$_} );
- }
+ my @top = map $source->_extract_top_level_conditions(
+ $converter->_expr_to_dq($_)
+ ), grep defined, $left, $right;
- $right = undef unless keys %$right;
- }
+ return undef unless @top;
+ my %top = map +(Data::Dumper::Concise::Dumper($_) => $_), @top;
- if (defined $left xor defined $right) {
- return defined $left ? $left : $right;
- }
- elsif (! defined $left) {
- return undef;
- }
- else {
- return { -and => [ $left, $right ] };
- }
+ return \Operator({ 'SQL.Naive' => 'AND' }, [ values %top ]);
}
=head2 search_literal
sub _extract_fixed_conditions_for {
my ($self, $dq, $alias) = @_;
my (@q, %found) = ($dq);
- while (my $n = shift @q) {
- if (is_Operator($n)) {
- if (($n->{operator}{Perl}||'') =~ /^(?:==|eq)$/) {
- my ($l, $r) = @{$n->{args}};
- if (
- is_Identifier($r) and @{$r->{elements}} == 2
- and (!$alias or $r->{elements}[0] eq $alias)
- ) {
- ($l, $r) = ($r, $l);
- }
- if (
- is_Identifier($l) and @{$l->{elements}} == 2
- and (!$alias or $l->{elements}[0] eq $alias)
- ) {
- $found{$l->{elements}[1]} = $r;
- } elsif (($n->{operator}{Perl}||'') eq 'and') {
- push @q, @{$n->{args}};
- }
+ foreach my $n ($self->_extract_top_level_conditions($dq)) {
+ if (
+ is_Operator($n)
+ and (
+ ($n->{operator}{Perl}||'') =~ /^(?:==|eq)$/
+ or ($n->{operator}{'SQL.Naive'}||'') eq '='
+ )
+ ) {
+ my ($l, $r) = @{$n->{args}};
+ if (
+ is_Identifier($r) and @{$r->{elements}} == 2
+ and (!$alias or $r->{elements}[0] eq $alias)
+ ) {
+ ($l, $r) = ($r, $l);
+ }
+ if (
+ is_Identifier($l) and @{$l->{elements}} == 2
+ and (!$alias or $l->{elements}[0] eq $alias)
+ ) {
+ $found{$l->{elements}[1]} = $r;
}
}
}
return \%found;
}
+sub _extract_top_level_conditions {
+ my ($self, $dq) = @_;
+ my (@q, @found) = ($dq);
+ while (my $n = shift @q) {
+ if (
+ is_Operator($n)
+ and ($n->{operator}{Perl}||$n->{operator}{'SQL.Naive'}||'') =~ /^and$/i
+ ) {
+ push @q, @{$n->{args}};
+ } else {
+ push @found, $n;
+ }
+ }
+ return @found;
+}
+
sub compare_relationship_keys {
carp 'compare_relationship_keys is a private method, stop calling it';
my $self = shift;