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 )