diff --git a/Changes b/Changes index 3b2f82934..c10c333a5 100644 --- a/Changes +++ b/Changes @@ -1,5 +1,7 @@ LIST OF CHANGES FOR NPG-QC PACKAGE + - autoqc results loader to check for potential composition digest clashes + release 66.0 - GUI for utility QC (inactive) - add new bcfstats qc check + viewer change diff --git a/lib/npg_qc/Schema/ResultSet.pm b/lib/npg_qc/Schema/ResultSet.pm index 68c2656bd..f016d54a3 100644 --- a/lib/npg_qc/Schema/ResultSet.pm +++ b/lib/npg_qc/Schema/ResultSet.pm @@ -123,7 +123,7 @@ sub find_seq_composition { } sub find_or_create_seq_composition { - my ($self, $composition) = @_; + my ($self, $composition, $check_digest) = @_; $self->_validate($composition); my $digest = $composition->digest; @@ -133,7 +133,14 @@ sub find_or_create_seq_composition { my $composition_row = $self->_find_composition($digest, $num_components); # If composition exists, we assume that it's properly defined, i.e. # all relevant components and records in the linking table exist. - if (!$composition_row) { + if ($composition_row) { + # If asked, ensure that the found row represents the same composition. + if ($check_digest && + ($composition->freeze ne $composition_row->create_composition()->freeze)) { + croak "A different composition object with the same digest '$digest' " . + 'already exists in the database'; + } + } else { $composition_row = $schema->resultset('SeqComposition') ->create({ 'digest' => $digest, @@ -306,6 +313,10 @@ for every component-composition pair. Gives an error if this resultset does not have a relationship to the seq_composition table. +If a true value is given as a second attrubute and a composition object is +found, a check for a clash of sha256 digest of composition objects is performed. +Error is raised if the clashing digests are detected. + =head2 composition_fk_column_name Returns the name of the column with a foreign key linking this table to the diff --git a/lib/npg_qc/autoqc/db_loader.pm b/lib/npg_qc/autoqc/db_loader.pm index 024e6159e..5c7875fad 100644 --- a/lib/npg_qc/autoqc/db_loader.pm +++ b/lib/npg_qc/autoqc/db_loader.pm @@ -244,7 +244,8 @@ sub _json2db{ if ($dbix_class_name && $self->_schema_has_source($dbix_class_name) && $self->_pass_filter($obj)) { my $rs = $self->schema->resultset($dbix_class_name); - my $related_composition = $rs->find_or_create_seq_composition($obj->composition()); + my $check_digest = 1; + my $related_composition = $rs->find_or_create_seq_composition($obj->composition(), $check_digest); if (!$related_composition) { croak 'Composition is not found/created'; } diff --git a/t/50-schema-resultset.t b/t/50-schema-resultset.t index d31b84814..7ea4c2450 100644 --- a/t/50-schema-resultset.t +++ b/t/50-schema-resultset.t @@ -530,7 +530,7 @@ subtest q[not saving composition subset value "all"] => sub { my $id_run; subtest q[finding existing composition] => sub { - plan tests => 15; + plan tests => 17; my $rs_component = $schema->resultset('SeqComponent'); my $rs_composition = $schema->resultset('SeqComposition'); @@ -592,12 +592,25 @@ subtest q[finding existing composition] => sub { $f->add_component(npg_tracking::glossary::composition::component::illumina ->new(%{$value}, tag_index => undef, subset => undef)); } - $row = $ssrs->find_or_create_seq_composition($f->create_composition()); + my $c = $f->create_composition(); + $row = $ssrs->find_or_create_seq_composition($c); is($row->id_seq_composition, $pk_value, 'existing row returned'); + + my $row_to_change = $rs_component->search( + {id_run => $id_run,position => 1,tag_index => undef, subset => undef})->next(); + $row_to_change or die 'Failed to find existing row'; + $row_to_change->update({subset => 'human'}); + my $d = $c->digest; + throws_ok {$ssrs->find_or_create_seq_composition($c, 1)} + qr/A different composition object with the same digest '$d' already exists in the database/, + 'error detecting composition digest clash'; + $row_to_change->update({subset => undef}); + lives_ok {$ssrs->find_or_create_seq_composition($c, 1)} + 'no error after removing the clash'; } $count++; - } + } }; subtest q[creating new composition from new and existing components] => sub {