DBIx-Class-Sims

 view release on metacpan or  search on metacpan

lib/DBIx/Class/Sims/Item.pm  view on Meta::CPAN

  return 1;
}

sub build_searcher_for_constraints {
  my $self = shift;
  my (@constraints) = @_;

  my $to_find = {};
  my $matched_all_columns = 1;
  foreach my $c ( map { @$_ } @constraints ) {
    unless ($self->is_real_value($c->name)) {
      $matched_all_columns = 0;
      last;
    }

    # Undefined values cannot be searched over because undefined values appear
    # different to the UK, but appear the same in a query. Therefore, this
    # searcher cannot work.
    $to_find->{$c->name} = $self->value($c->name) // return;
  }

  return $to_find if keys(%$to_find) && $matched_all_columns;
  return;
}

sub unique_id {
  my $self = shift;
  my ($row) = @_;

  my @cols = $row->result_source->columns;
  my %data = $row->get_columns;
  my @vals = @data{@cols};
  return ref($row) . join(',',@cols) . join(',',map {$_//''} @vals);
}

sub find_unique_match {
  my $self = shift;

  my @uniques = $self->source->uniques;

  my $rs = $self->source->resultset;

  if ( my $to_find = $self->build_searcher_for_constraints(@uniques) ) {
    my $row = $rs->search($to_find, { rows => 1 })->first;
    if ($row) {
      push @{$self->runner->{duplicates}{$self->source_name}}, {
        criteria => [$to_find],
        found    => { $row->get_columns },
      };
      $self->row($row);

      $self->{trace}{find} = $self->{runner}{ids}{find}++;
      $self->{trace}{row} = $self->make_jsonable( { $row->get_columns } );
      $self->{trace}{criteria} = [$to_find];
      $self->{trace}{unique} = 1;

      return;
    }
  }

  # Search through all the possible iterations of unique keys.
  #  * Don't populate $self->{create}
  #  * If found with all keys, great.
  #  * Otherwise, keep track of what we find for each combination (if at all)
  #    * If we have multiple finds, die.
  # TODO: Use List::Powerset->powerset_lazy() instead of powerset()
  my %rows_found;
  foreach my $bundle (@{powerset(@uniques)}) {
    # Skip the all (already handled) and the empty (unneeded).
    next if @$bundle == 0 || @$bundle == @uniques;

    my $finder = $self->build_searcher_for_constraints(@$bundle)
      or next;

    my $row = $rs->search($finder, { rows => 1 })->first;
    if ($row) {
      my $unique_id = $self->unique_id($row);
      $rows_found{$unique_id} //= {
        row => $row,
        finders => [],
      };
      push @{$rows_found{$unique_id}{finders}}, $finder;
    }
  }

  if (keys(%rows_found) > 1) {
    die "Rows found by multiple unique constraints";
  }

  if (keys(%rows_found) == 1) {
    my $x = (values %rows_found)[0];
    my ($finders, $row) = @{$x}{qw(finders row)};
    push @{$self->runner->{duplicates}{$self->source_name}}, {
      criteria => $finders,
      found    => { $row->get_columns },
    };
    $self->row($row);

    $self->{trace}{find} = $self->{runner}{ids}{find}++;
    $self->{trace}{row} = $self->make_jsonable( { $row->get_columns } );
    $self->{trace}{criteria} = $finders;
    $self->{trace}{unique} = 1;

    return;
  }

  return;
}

sub find_any_match {
  my $self = shift;

  my $rs = $self->source->resultset;

  # This is for handling the case where a FK is within a UK in the child. This
  # ensures we cannot select a parent whose PK is already in use in the child.
  # We don't check for this in find_unique_match() because the UK is all that
  # matters there.
  if ($self->meta->{restriction}) {
    my $c = $self->meta->{restriction};
    $rs = $rs->search( $c->{cond}, $c->{extra} );



( run in 0.558 second using v1.01-cache-2.11-cpan-71847e10f99 )