3 CXGN::Stock - a second-level object for Stock
9 This object was re-factored from CXGN::Chado::Stock and moosified.
11 Functions such as 'get_obsolete' , 'store' , and 'exists_in_database' are required , and do not use standard DBIC syntax.
15 Naama Menda <nm249@cornell.edu>
16 Lukas Mueller <lam87@cornell.edu>
26 use Bio
::Chado
::Schema
;
27 use CXGN
::Metadata
::Schema
;
28 use SGN
::Model
::Cvterm
;
29 use Bio
::GeneticRelationships
::Pedigree
;
30 use Bio
::GeneticRelationships
::Individual
;
31 use base qw
/ CXGN::DB::Object / ;
32 use CXGN
::Stock
::StockLookup
;
36 isa
=> 'Bio::Chado::Schema',
41 has
'check_name_exists' => (
48 isa
=> 'Bio::Chado::Schema::Result::Stock::Stock',
58 isa
=> 'Bio::Chado::Schema::Result::Organism::Organism',
62 has
'organism_id' => (
77 has
'organism_common_name' => (
82 has
'organism_abbreviation' => (
87 has
'organism_comment' => (
95 default => 'accession',
108 has
'uniquename' => (
113 has
'description' => (
119 has
'is_obsolete' => (
125 has
'organization_name' => (
130 has
'population_name' => (
135 has
'populations' => (
136 isa
=> 'Maybe[ArrayRef[Str]]',
144 print STDERR
"RUNNING BUILD FOR STOCK.PM...\n";
146 if ($self->stock_id){
147 $stock = $self->schema()->resultset("Stock::Stock")->find({ stock_id
=> $self->stock_id() });
149 if (defined $stock) {
150 $self->stock($stock);
151 $self->stock_id($stock->stock_id);
152 $self->name($stock->name);
153 $self->uniquename($stock->uniquename);
154 $self->description($stock->description() || '');
155 $self->type_id($stock->type_id);
156 $self->type($self->schema()->resultset("Cv::Cvterm")->find({ cvterm_id
=>$self->type_id() })->name());
157 $self->is_obsolete($stock->is_obsolete);
158 $self->organization_name($self->_retrieve_stockprop('organization'));
159 $self->_retrieve_populations();
170 Desc: store a new stock or update an existing stock
173 Side Effects: checks if the stock exists in the database (if a stock_id is provided), and if does, will attempt to update
182 my $stock = $self->stock;
183 my $schema = $self->schema();
185 #no stock id . Check first if the name exists in te database
187 if ($self->check_name_exists){
188 $exists= $self->exists_in_database();
191 if (!$self->type_id) {
192 my $type_id = SGN
::Model
::Cvterm
->get_cvterm_row($self->schema(), $self->type(), 'stock_type')->cvterm_id();
193 $self->type_id($type_id);
196 if (!$self->organism_id){
199 my $organism_rs = $self->schema->resultset("Organism::Organism")->search({ species
=>$self->species });
200 if ($organism_rs->count > 1){
201 return $return{error
} = "More than one organism returned for species: ".$self->species;
203 if ($organism_rs->count == 0){
204 return $return{error
} = "NO ORGANISM FOUND OF SPECIES: ".$self->species;
206 if ($organism_rs->count == 1){
207 my $organism = $organism_rs->first();
208 $self->organism($organism);
209 $self->organism_id($organism->organism_id);
210 $self->organism_abbreviation($organism->abbreviation);
211 $self->genus($organism->genus);
212 $self->species($organism->species);
213 $self->organism_common_name($organism->common_name);
214 $self->organism_comment($organism->comment);
219 if (!$stock) { #Trying to create a new stock
222 my $new_row = $self->schema()->resultset("Stock::Stock")->create({
223 name
=> $self->name(),
224 uniquename
=> $self->uniquename(),
225 description
=> $self->description(),
226 type_id
=> $self->type_id(),
227 organism_id
=> $self->organism_id(),
228 is_obsolete
=> $self->is_obsolete(),
232 my $id = $new_row->stock_id();
233 $self->stock_id($id);
234 $self->stock($new_row);
236 if ($self->organization_name){
237 $self->_store_stockprop('organization', $self->organization_name());
239 if ($self->population_name){
240 $self->_store_population_relationship();
245 die "The entry ".$self->uniquename()." already exists in the database. Error: $exists\n";
248 else { # entry exists, so update
249 print STDERR
"EXISTS: $exists\n";
250 my $row = $self->schema()->resultset("Stock::Stock")->find({ stock_id
=> $self->stock_id() });
251 $row->name($self->name());
252 $row->uniquename($self->uniquename());
253 $row->description($self->description());
254 $row->type_id($self->type_id());
255 $row->organism_id($self->organism_id());
256 $row->is_obsolete($self->is_obsolete());
259 return $self->stock_id();
262 ########################
265 =head2 exists_in_database
267 Usage: $self->exists_in_database()
268 Desc: check if the uniquename exists in the stock table
276 sub exists_in_database
{
278 my $schema = $self->schema;
279 my $stock = $self->stock;
280 my $stock_id = $self->stock_id;
281 my $uniquename = $self->uniquename || '' ;
282 my $stock_lookup = CXGN
::Stock
::StockLookup
->new({
284 stock_name
=> $uniquename
286 my $s = $stock_lookup->get_stock();
288 # loading new stock - $stock_id is undef
290 if (defined($s) && !$stock ) {
291 return "Uniquename already exists in database with stock_id: ".$s->stock_id;
294 # updating an existing stock
296 elsif ($stock && defined($s) ) {
297 if ( ($s->stock_id == $stock_id) ) {
299 #trying to update the uniquename
301 elsif ( $s->stock_id != $stock_id ) {
302 return " Can't update an existing stock $stock_id uniquename:$uniquename.";
303 # if the new name we're trying to update/insert does not exist
304 # in the stock table..
307 elsif ($stock && !$s->stock_id) {
316 Usage: $self->get_organism
317 Desc: find the organism object of this stock
318 Ret: L<Bio::Chado::Schema::Organism::Organism> object
327 my $bcs_stock = $self->schema()->resultset("Stock::Stock")->find( { stock_id
=> $self->stock_id() });
329 return $bcs_stock->organism;
337 Usage: $self->get_species
338 Desc: find the species name of this stock , if one exists
348 my $organism = $self->get_organism;
350 return $organism->species;
359 Usage: $self->get_genus
360 Desc: find the genus name of this stock , if one exists
370 my $organism = $self->get_organism;
372 return $organism->genus;
379 =head2 get_species_authority
381 Usage: $self->get_species_authority
382 Desc: find the species_authority of this stock , if one exists
390 sub get_species_authority
{
392 return $self->_retrieve_organismprop('species authority');
397 Usage: $self->get_subtaxa
398 Desc: find the subtaxa of this stock , if one exists
408 return $self->_retrieve_organismprop('subtaxa');
411 =head2 get_subtaxa_authority
413 Usage: $self->get_subtaxa_authority
414 Desc: find the subtaxa_authority of this stock , if one exists
422 sub get_subtaxa_authority
{
424 return $self->_retrieve_organismprop('subtaxa authority');
429 Usage: $self->set_species
430 Desc: set organism_id for the stock using organism.species name
432 Args: species name (case insensitive)
433 Side Effects: sets the organism_id for the stock
440 my $species_name = shift; # this has to be EXACTLY as stored in the organism table
441 my $organism = $self->get_schema->resultset('Organism::Organism')->search(
442 { 'lower(species)' => { like
=> lc($species_name) } } )->single ; #should be 1 result
444 $self->organism_id($organism->organism_id);
447 warn "NO organism found for species name $species_name!!\n";
451 =head2 function get_image_ids
453 Synopsis: my @images = $self->get_image_ids()
455 Returns: a list of image ids
457 Description: a method for fetching all images associated with a stock
463 my $ids = $self->schema()->storage->dbh->selectcol_arrayref
464 ( "SELECT image_id FROM phenome.stock_image WHERE stock_id=? ",
471 =head2 associate_allele
473 Usage: $self->associate_allele($allele_id, $sp_person_id)
474 Desc: store a stock-allele link in phenome.stock_allele
476 Args: allele_id, sp_person_id
477 Side Effects: store a metadata row
482 sub associate_allele
{
484 my $allele_id = shift;
485 my $sp_person_id = shift;
486 if (!$allele_id || !$sp_person_id) {
487 warn "Need both allele_id and person_id for linking the stock with an allele!";
490 my $metadata_id = $self->_new_metadata_id($sp_person_id);
491 #check if the allele is already linked
492 my $ids = $self->schema()->storage()->dbh()->selectcol_arrayref
493 ( "SELECT stock_allele_id FROM phenome.stock_allele WHERE stock_id = ? AND allele_id = ?",
498 if ($ids) { warn "Allele $allele_id is already linked with stock " . $self->stock_id ; }
499 #store the allele_id - stock_id link
500 my $q = "INSERT INTO phenome.stock_allele (stock_id, allele_id, metadata_id) VALUES (?,?,?) RETURNING stock_allele_id";
501 my $sth = $self->schema()->storage()->dbh()->prepare($q);
502 $sth->execute($self->stock_id, $allele_id, $metadata_id);
503 my ($id) = $sth->fetchrow_array;
507 =head2 associate_owner
509 Usage: $self->associate_owner($owner_sp_person_id, $sp_person_id)
510 Desc: store a stock-owner link in phenome.stock_owner
512 Args: owner_id, sp_person_id
513 Side Effects: store a metadata row
518 sub associate_owner
{
520 my $owner_id = shift;
521 my $sp_person_id = shift;
522 if (!$owner_id || !$sp_person_id) {
523 warn "Need both owner_id and person_id for linking the stock with an owner!";
526 my $metadata_id = $self->_new_metadata_id($sp_person_id);
527 #check if the owner is already linked
528 my $ids = $self->schema()->storage()->dbh()->selectcol_arrayref
529 ( "SELECT stock_owner_id FROM phenome.stock_owner WHERE stock_id = ? AND owner_id = ?",
534 if ($ids) { warn "Owner $owner_id is already linked with stock " . $self->stock_id ; }
535 #store the owner_id - stock_id link
536 my $q = "INSERT INTO phenome.stock_owner (stock_id, owner_id, metadata_id) VALUES (?,?,?) RETURNING stock_owner_id";
537 my $sth = $self->schema()->storage()->dbh()->prepare($q);
538 $sth->execute($self->stock_id, $owner_id, $metadata_id);
539 my ($id) = $sth->fetchrow_array;
543 =head2 get_trait_list
546 Desc: gets the list of traits that have been measured
548 Ret: a list of lists ( [ cvterm_id, cvterm_name] , ...)
558 my $q = "select distinct(cvterm.cvterm_id), db.name || ':' || dbxref.accession, cvterm.name, avg(phenotype.value::Real), stddev(phenotype.value::Real) from stock as accession join stock_relationship on (accession.stock_id=stock_relationship.object_id) JOIN stock as plot on (plot.stock_id=stock_relationship.subject_id) JOIN nd_experiment_stock ON (plot.stock_id=nd_experiment_stock.stock_id) JOIN nd_experiment_phenotype USING(nd_experiment_id) JOIN phenotype USING (phenotype_id) JOIN cvterm ON (phenotype.cvalue_id = cvterm.cvterm_id) JOIN dbxref ON(cvterm.dbxref_id = dbxref.dbxref_id) JOIN db USING(db_id) where accession.stock_id=? and phenotype.value~? group by cvterm.cvterm_id, db.name || ':' || dbxref.accession, cvterm.name";
559 my $h = $self->schema()->storage()->dbh()->prepare($q);
560 my $numeric_regex = '^[0-9]+([,.][0-9]+)?$';
561 $h->execute($self->stock_id(), $numeric_regex);
563 while (my ($cvterm_id, $cvterm_accession, $cvterm_name, $avg, $stddev) = $h->fetchrow_array()) {
564 push @traits, [ $cvterm_id, $cvterm_accession, $cvterm_name, $avg, $stddev ];
567 # get directly associated traits
569 $q = "select distinct(cvterm.cvterm_id), db.name || ':' || dbxref.accession, cvterm.name, avg(phenotype.value::Real), stddev(phenotype.value::Real) from stock JOIN nd_experiment_stock ON (stock.stock_id=nd_experiment_stock.stock_id) JOIN nd_experiment_phenotype USING(nd_experiment_id) JOIN phenotype USING (phenotype_id) JOIN cvterm ON (phenotype.cvalue_id = cvterm.cvterm_id) JOIN dbxref ON(cvterm.dbxref_id = dbxref.dbxref_id) JOIN db USING(db_id) where stock.stock_id=? and phenotype.value~? group by cvterm.cvterm_id, db.name || ':' || dbxref.accession, cvterm.name";
571 $h = $self->schema()->storage()->dbh()->prepare($q);
572 $numeric_regex = '^[0-9]+([,.][0-9]+)?$';
573 $h->execute($self->stock_id(), $numeric_regex);
575 while (my ($cvterm_id, $cvterm_accession, $cvterm_name, $avg, $stddev) = $h->fetchrow_array()) {
576 push @traits, [ $cvterm_id, $cvterm_accession, $cvterm_name, $avg, $stddev ];
585 Desc: gets the list of trails this stock was used in
595 my $dbh = $self->schema()->storage()->dbh();
597 my $geolocation_q = "SELECT nd_geolocation_id, description FROM nd_geolocation;";
598 my $geolocation_h = $dbh->prepare($geolocation_q);
599 $geolocation_h->execute();
602 while (my ($nd_geolocation_id, $description) = $geolocation_h->fetchrow_array()) {
603 $geolocations{$nd_geolocation_id} = $description;
606 my $geolocation_type_id = SGN
::Model
::Cvterm
->get_cvterm_row($self->schema(), 'project location', 'project_property')->cvterm_id();
607 my $q = "select distinct(project.project_id), project.name, projectprop.value from stock as accession join stock_relationship on (accession.stock_id=stock_relationship.object_id) JOIN stock as plot on (plot.stock_id=stock_relationship.subject_id) JOIN nd_experiment_stock ON (plot.stock_id=nd_experiment_stock.stock_id) JOIN nd_experiment_project USING(nd_experiment_id) JOIN project USING (project_id) LEFT JOIN projectprop ON (project.project_id=projectprop.project_id) where projectprop.type_id=$geolocation_type_id AND accession.stock_id=?;";
609 my $h = $dbh->prepare($q);
610 $h->execute($self->stock_id());
613 while (my ($project_id, $project_name, $nd_geolocation_id) = $h->fetchrow_array()) {
614 push @trials, [ $project_id, $project_name, $nd_geolocation_id, $geolocations{$nd_geolocation_id} ];
619 =head2 get_ancestor_hash
622 Desc: gets a multi-dimensional hash of this stock's ancestors
630 sub get_ancestor_hash
{
631 my ($self, $stock_id, $direct_descendant_ids) = @_;
633 if (!$stock_id) { $stock_id = $self->stock_id(); }
634 push @
$direct_descendant_ids, $stock_id; #excluded in parent retrieval to prevent loops
636 my $stock = $self->schema->resultset("Stock::Stock")->find({stock_id
=> $stock_id});
637 #print STDERR "Stock ".$stock->uniquename()." decendants are: ".Dumper($direct_descendant_ids)."\n";
639 $pedigree{'id'} = $stock_id;
640 $pedigree{'name'} = $stock->uniquename();
641 $pedigree{'female_parent'} = undef;
642 $pedigree{'male_parent'} = undef;
643 $pedigree{'link'} = "/stock/$stock_id/view";
645 #get cvterms for parent relationships
646 my $cvterm_female_parent = SGN
::Model
::Cvterm
->get_cvterm_row($self->schema, 'female_parent', 'stock_relationship');
647 my $cvterm_male_parent = SGN
::Model
::Cvterm
->get_cvterm_row($self->schema, 'male_parent', 'stock_relationship');
649 #get the stock relationships for the stock, find stock relationships for types "female_parent" and "male_parent", and get the corresponding subject stock IDs and stocks.
650 my $stock_relationships = $stock->search_related("stock_relationship_objects",undef,{ prefetch
=> ['type','subject'] });
651 my $female_parent_relationship = $stock_relationships->find({type_id
=> $cvterm_female_parent->cvterm_id(), subject_id
=> {'not_in' => $direct_descendant_ids}});
652 if ($female_parent_relationship) {
653 my $female_parent_stock_id = $female_parent_relationship->subject_id();
654 $pedigree{'cross_type'} = $female_parent_relationship->value();
655 $pedigree{'female_parent'} = get_ancestor_hash
( $self, $female_parent_stock_id, $direct_descendant_ids );
657 my $male_parent_relationship = $stock_relationships->find({type_id
=> $cvterm_male_parent->cvterm_id(), subject_id
=> {'not_in' => $direct_descendant_ids}});
658 if ($male_parent_relationship) {
659 my $male_parent_stock_id = $male_parent_relationship->subject_id();
660 $pedigree{'male_parent'} = get_ancestor_hash
( $self, $male_parent_stock_id, $direct_descendant_ids );
662 pop @
$direct_descendant_ids; # falling back a level while recursing pedigree tree
666 =head2 get_descendant_hash
669 Desc: gets a multi-dimensional hash of this stock's descendants
677 sub get_descendant_hash
{
678 my ($self, $stock_id, $direct_ancestor_ids) = @_;
680 if (!$stock_id) { $stock_id = $self->stock_id(); }
681 push @
$direct_ancestor_ids, $stock_id; #excluded in child retrieval to prevent loops
683 my $stock = $self->schema->resultset("Stock::Stock")->find({stock_id
=> $stock_id});
684 #print STDERR "Stock ".$stock->uniquename()." ancestors are: ".Dumper($direct_ancestor_ids)."\n";
687 $descendants{'id'} = $stock_id;
688 $descendants{'name'} = $stock->uniquename();
689 $descendants{'link'} = "/stock/$stock_id/view";
690 #get cvterms for parent relationships
691 my $cvterm_female_parent = SGN
::Model
::Cvterm
->get_cvterm_row($self->schema, 'female_parent','stock_relationship');
692 my $cvterm_male_parent = SGN
::Model
::Cvterm
->get_cvterm_row($self->schema, 'male_parent', 'stock_relationship');
694 #get the stock relationships for the stock, find stock relationships for types "female_parent" and "male_parent", and get the corresponding subject stock IDs and stocks.
695 my $descendant_relationships = $stock->search_related("stock_relationship_subjects",{ object_id
=> {'not_in' => $direct_ancestor_ids}},{ prefetch
=> ['type','object'] });
696 if ($descendant_relationships) {
697 while (my $descendant_relationship = $descendant_relationships->next) {
698 my $descendant_stock_id = $descendant_relationship->object_id();
699 if (($descendant_relationship->type_id() == $cvterm_female_parent->cvterm_id()) || ($descendant_relationship->type_id() == $cvterm_male_parent->cvterm_id())) {
700 $progeny{$descendant_stock_id} = get_descendant_hash
($self, $descendant_stock_id, $direct_ancestor_ids);
703 $descendants{'descendants'} = \
%progeny;
704 pop @
$direct_ancestor_ids; # falling back a level while recursing descendant tree
705 return \
%descendants;
709 =head2 get_pedigree_rows
712 Desc: get an array of pedigree rows from an array of stock ids, conatining female parent, male parent, and cross type if defined
714 Args: $accession_ids, $format (either 'parents_only' or 'full')
720 sub get_pedigree_rows
{
721 my ($self, $accession_ids, $format) = @_;
722 #print STDERR "Accession ids are: ".Dumper(@$accession_ids)."\n";
724 my $placeholders = join ( ',', ('?') x @
$accession_ids );
725 my ($query, $pedigree_rows);
727 if ($format eq 'parents_only') {
729 SELECT child.uniquename AS Accession,
730 mother.uniquename AS Female_Parent,
731 father.uniquename AS Male_Parent,
732 m_rel.value AS cross_type
734 LEFT JOIN stock_relationship m_rel ON(child.stock_id = m_rel.object_id and m_rel.type_id = (SELECT cvterm_id FROM cvterm WHERE name = 'female_parent'))
735 LEFT JOIN stock mother ON(m_rel.subject_id = mother.stock_id)
736 LEFT JOIN stock_relationship f_rel ON(child.stock_id = f_rel.object_id and f_rel.type_id = (SELECT cvterm_id FROM cvterm WHERE name = 'male_parent'))
737 LEFT JOIN stock father ON(f_rel.subject_id = father.stock_id)
738 WHERE child.stock_id IN ($placeholders)
742 elsif ($format eq 'full') {
744 WITH RECURSIVE included_rows(child, child_id, mother, mother_id, father, father_id, type, depth, path, cycle) AS (
745 SELECT c.uniquename AS child,
746 c.stock_id AS child_id,
747 m.uniquename AS mother,
748 m.stock_id AS mother_id,
749 f.uniquename AS father,
750 f.stock_id AS father_id,
756 LEFT JOIN stock_relationship m_rel ON(c.stock_id = m_rel.object_id and m_rel.type_id = (SELECT cvterm_id FROM cvterm WHERE name = 'female_parent'))
757 LEFT JOIN stock m ON(m_rel.subject_id = m.stock_id)
758 LEFT JOIN stock_relationship f_rel ON(c.stock_id = f_rel.object_id and f_rel.type_id = (SELECT cvterm_id FROM cvterm WHERE name = 'male_parent'))
759 LEFT JOIN stock f ON(f_rel.subject_id = f.stock_id)
760 WHERE c.stock_id IN ($placeholders)
761 GROUP BY 1,2,3,4,5,6,7,8,9,10
763 SELECT c.uniquename AS child,
764 c.stock_id AS child_id,
765 m.uniquename AS mother,
766 m.stock_id AS mother_id,
767 f.uniquename AS father,
768 f.stock_id AS father_id,
770 included_rows.depth + 1,
772 c.stock_id = ANY(path)
773 FROM included_rows, stock c
774 LEFT JOIN stock_relationship m_rel ON(c.stock_id = m_rel.object_id and m_rel.type_id = (SELECT cvterm_id FROM cvterm WHERE name = 'female_parent'))
775 LEFT JOIN stock m ON(m_rel.subject_id = m.stock_id)
776 LEFT JOIN stock_relationship f_rel ON(c.stock_id = f_rel.object_id and f_rel.type_id = (SELECT cvterm_id FROM cvterm WHERE name = 'male_parent'))
777 LEFT JOIN stock f ON(f_rel.subject_id = f.stock_id)
778 WHERE c.stock_id IN (included_rows.mother_id, included_rows.father_id) AND NOT cycle
779 GROUP BY 1,2,3,4,5,6,7,8,9,10
781 SELECT child, mother, father, type, depth
787 my $sth = $self->schema()->storage()->dbh()->prepare($query);
788 $sth->execute(@
$accession_ids);
790 no warnings
'uninitialized';
791 while (my ($name, $mother, $father, $cross_type, $depth) = $sth->fetchrow_array()) {
792 #print STDERR "For child $name:\n\tMother:$mother\n\tFather:$father\n\tCross Type:$cross_type\n\tDepth:$depth\n\n";
793 push @
$pedigree_rows, "$name\t$mother\t$father\t$cross_type\n";
795 return $pedigree_rows;
798 =head2 get_pedigree_string
801 Desc: get the properly formatted pedigree string of the given level (Parents, Grandparents, or Great-Grandparents) for this stock
809 sub get_pedigree_string
{
810 my ($self, $level) = @_;
812 my $pedigree_hashref = $self->get_ancestor_hash();
814 #print STDERR "Getting string of level $level from pedigree hashref ".Dumper($pedigree_hashref)."\n";
815 if ($level eq "Parents") {
816 return $self->_get_parent_string($pedigree_hashref);
818 elsif ($level eq "Grandparents") {
819 my $maternal_parent_string = $self->_get_parent_string($pedigree_hashref->{'female_parent'});
820 my $paternal_parent_string = $self->_get_parent_string($pedigree_hashref->{'male_parent'});
821 return "$maternal_parent_string//$paternal_parent_string";
823 elsif ($level eq "Great-Grandparents") {
824 my $mm_parent_string = $self->_get_parent_string($pedigree_hashref->{'female_parent'}->{'female_parent'});
825 my $mf_parent_string = $self->_get_parent_string($pedigree_hashref->{'female_parent'}->{'male_parent'});
826 my $pm_parent_string = $self->_get_parent_string($pedigree_hashref->{'male_parent'}->{'female_parent'});
827 my $pf_parent_string = $self->_get_parent_string($pedigree_hashref->{'male_parent'}->{'male_parent'});
828 return "$mm_parent_string//$mf_parent_string///$pm_parent_string//$pf_parent_string";
832 sub _get_parent_string
{
833 my ($self, $pedigree_hashref) = @_;
834 my $mother = $pedigree_hashref->{'female_parent'}->{'name'} || 'NA';
835 my $father = $pedigree_hashref->{'male_parent'}->{'name'} || 'NA';
836 return "$mother/$father";
841 my $pedigree_hashref = $self->get_ancestor_hash();
843 $parents{'mother'} = $pedigree_hashref->{'female_parent'}->{'name'};
844 $parents{'mother_id'} = $pedigree_hashref->{'female_parent'}->{'id'};
845 $parents{'father'} = $pedigree_hashref->{'male_parent'}->{'name'};
846 $parents{'father_id'} = $pedigree_hashref->{'male_parent'}->{'id'};
850 sub _store_stockprop
{
854 my $stockprop = SGN
::Model
::Cvterm
->get_cvterm_row($self->schema, $type, 'stock_property')->name();
855 my $stored_stockprop = $self->stock->create_stockprops({ $stockprop => $value});
858 sub _retrieve_stockprop
{
864 my $stockprop_type_id = SGN
::Model
::Cvterm
->get_cvterm_row($self->schema, $type, 'stock_property')->cvterm_id();
865 my $rs = $self->schema()->resultset("Stock::Stockprop")->search({ stock_id
=> $self->stock_id(), type_id
=> $stockprop_type_id }, { order_by
=> {-asc
=> 'stockprop_id'} });
867 while (my $r = $rs->next()){
868 push @results, $r->value;
871 #print STDERR "Cvterm $type does not exist in this database\n";
874 my $res = join ',', @results;
878 sub _remove_stockprop
{
882 my $type_id = SGN
::Model
::Cvterm
->get_cvterm_row($self->schema, $type, 'stock_property')->cvterm_id();
883 my $rs = $self->schema()->resultset("Stock::Stockprop")->search( { type_id
=>$type_id, stock_id
=> $self->stock_id(), value
=>$value } );
885 if ($rs->count() == 1) {
886 $rs->first->delete();
889 elsif ($rs->count() == 0) {
893 print STDERR
"Error removing stockprop from stock ".$self->stock_id().". Please check this manually.\n";
899 sub _retrieve_organismprop
{
905 my $organismprop_type_id = SGN
::Model
::Cvterm
->get_cvterm_row($self->schema, $type, 'organism_property')->cvterm_id();
906 my $rs = $self->schema()->resultset("Organism::Organismprop")->search({ organism_id
=> $self->stock->organism_id, type_id
=> $organismprop_type_id }, { order_by
=> {-asc
=> 'organismprop_id'} });
908 while (my $r = $rs->next()){
909 push @results, $r->value;
912 #print STDERR "Cvterm $type does not exist in this database\n";
915 my $res = join ',', @results;
919 sub _store_population_relationship
{
921 my $schema = $self->schema;
922 my $population_cvterm_id = SGN
::Model
::Cvterm
->get_cvterm_row($schema, 'population','stock_type')->cvterm_id();
923 my $population_member_cvterm_id = SGN
::Model
::Cvterm
->get_cvterm_row($schema, 'member_of','stock_relationship')->cvterm_id();
925 my $population = $schema->resultset("Stock::Stock")->find_or_create({
926 uniquename
=> $self->population_name(),
927 name
=> $self->population_name(),
928 organism_id
=> $self->organism_id(),
929 type_id
=> $population_cvterm_id,
931 $self->stock->find_or_create_related('stock_relationship_objects', {
932 type_id
=> $population_member_cvterm_id,
933 object_id
=> $population->stock_id(),
934 subject_id
=> $self->stock_id(),
938 sub _retrieve_populations
{
940 my $schema = $self->schema;
941 my $population_member_cvterm_id = SGN
::Model
::Cvterm
->get_cvterm_row($schema, 'member_of','stock_relationship')->cvterm_id();
943 my $rs = $schema->resultset("Stock::StockRelationship")->search({
944 type_id
=> $population_member_cvterm_id,
945 subject_id
=> $self->stock_id(),
947 if ($rs->count == 0) {
948 #print STDERR "No population saved for this stock!\n";
951 my @population_names;
952 while (my $row = $rs->next) {
953 my $population = $row->object;
954 push @population_names, $population->uniquename();
956 $self->populations(\
@population_names);
957 #print STDERR "This stock is a member of the following populations: ".Dumper($self->populations())."\n";
961 =head2 _new_metadata_id
963 Usage: my $md_id = $self->_new_metatada_id($sp_person_id)
964 Desc: Store a new md_metadata row with a $sp_person_id
970 sub _new_metadata_id
{
972 my $sp_person_id = shift;
973 my $metadata_schema = CXGN
::Metadata
::Schema
->connect(
974 sub { $self->schema()->storage()->dbh() },
976 my $metadata = CXGN
::Metadata
::Metadbdata
->new($metadata_schema);
977 $metadata->set_create_person_id($sp_person_id);
978 my $metadata_id = $metadata->store()->get_metadata_id();
984 Usage: $s->merge(221, 1);
985 Desc: merges stock $s with stock_id 221. Optional delete boolean
986 parameter indicates whether other stock should be deleted.
996 my $other_stock_id = shift;
997 my $delete_other_stock = shift;
999 if ($other_stock_id == $self->stock_id()) {
1000 print STDERR
"Trying to merge stock into itself ($other_stock_id) Skipping...\n";
1006 my $stockprop_count=0;
1007 my $subject_rel_count=0;
1008 my $object_rel_count=0;
1009 my $stock_allele_count=0;
1011 my $experiment_stock_count=0;
1012 my $stock_dbxref_count=0;
1013 my $stock_owner_count=0;
1014 my $parent_1_count=0;
1015 my $parent_2_count=0;
1016 my $other_stock_deleted = 'NO';
1019 my $schema = $self->schema();
1023 my $sprs = $schema->resultset("Stock::Stockprop")->search( { stock_id
=> $other_stock_id });
1024 while (my $row = $sprs->next()) {
1026 # check if this stockprop already exists for this stock; save only if not
1028 my $thissprs = $schema->resultset("Stock::Stockprop")->search(
1030 stock_id
=> $self->stock_id(),
1031 type_id
=> $row->type_id(),
1032 value
=> $row->value()
1035 if ($thissprs->count() == 0) {
1036 my $value = $row->value();
1037 my $type_id = $row->type_id();
1039 my $rank_rs = $schema->resultset("Stock::Stockprop")->search( { stock_id
=> $self->stock_id(), type_id
=> $type_id });
1042 if ($rank_rs->count() > 0) {
1043 $rank = $rank_rs->get_column("rank")->max();
1048 $row->stock_id($self->stock_id());
1052 print STDERR
"MERGED stockprop_id ".$row->stockprop_id." for stock $other_stock_id type_id $type_id value $value into stock ".$self->stock_id()."\n";
1057 # move subject relationships
1059 my $ssrs = $schema->resultset("Stock::StockRelationship")->search( { subject_id
=> $other_stock_id });
1061 while (my $row = $ssrs->next()) {
1063 my $this_subject_rel_rs = $schema->resultset("Stock::StockRelationship")->search( { subject_id
=> $self->stock_id(), object_id
=> $row->object_id, type_id
=> $row->type_id() });
1065 if ($this_subject_rel_rs->count() == 0) { # this stock does not have the relationship
1067 my $rank_rs = $schema->resultset("Stock::StockRelationship")->search( { subject_id
=> $self->stock_id(), type_id
=> $row->type_id() });
1069 if ($rank_rs->count() > 0) {
1070 $rank = $rank_rs->get_column("rank")->max();
1074 $row->subject_id($self->stock_id());
1076 print STDERR
"Moving subject relationships from stock $other_stock_id to stock ".$self->stock_id()."\n";
1077 $subject_rel_count++;
1081 # move object relationships
1083 my $osrs = $schema->resultset("Stock::StockRelationship")->search( { object_id
=> $other_stock_id });
1084 while (my $row = $osrs->next()) {
1085 my $this_object_rel_rs = $schema->resultset("Stock::StockRelationship")->search( { object_id
=> $self->stock_id, subject_id
=> $row->subject_id(), type_id
=> $row->type_id() });
1087 if ($this_object_rel_rs->count() == 0) {
1088 my $rank_rs = $schema->resultset("Stock::StockRelationship")->search( { object_id
=> $self->stock_id(), type_id
=> $row->type_id() });
1090 if ($rank_rs->count() > 0) {
1091 $rank = $rank_rs->get_column("rank")->max();
1095 $row->object_id($self->stock_id());
1097 print STDERR
"Moving object relationships from stock $other_stock_id to stock ".$self->stock_id()."\n";
1098 $object_rel_count++;
1102 # move experiment_stock
1104 my $esrs = $schema->resultset("NaturalDiversity::NdExperimentStock")->search( { stock_id
=> $other_stock_id });
1105 while (my $row = $esrs->next()) {
1106 $row->stock_id($self->stock_id());
1108 print STDERR
"Moving experiments for stock $other_stock_id to stock ".$self->stock_id()."\n";
1109 $experiment_stock_count++;
1112 # move stock_cvterm relationships
1118 my $sdrs = $schema->resultset("Stock::StockDbxref")->search( { stock_id
=> $other_stock_id });
1119 while (my $row = $sdrs->next()) {
1120 $row->stock_id($self->stock_id());
1122 $stock_dbxref_count++;
1125 # move sgn.pcr_exp_accession relationships
1129 # move sgn.pcr_experiment relationships
1134 # move stock_genotype relationships
1138 my $phenome_schema = CXGN
::Phenome
::Schema
->connect(
1139 sub { $self->schema()->storage()->dbh() }, { on_connect_do
=> [ 'SET search_path TO phenome, public, sgn'], limit_dialect
=> 'LimitOffset' }
1142 # move phenome.stock_allele relationships
1144 my $sars = $phenome_schema->resultset("StockAllele")->search( { stock_id
=> $other_stock_id });
1145 while (my $row = $sars->next()) {
1146 $row->stock_id($self->stock_id());
1148 print STDERR
"Moving stock alleles from stock $other_stock_id to stock ".$self->stock_id()."\n";
1149 $stock_allele_count++;
1152 # move image relationships
1154 my $irs = $phenome_schema->resultset("StockImage")->search( { stock_id
=> $other_stock_id });
1155 while (my $row = $irs->next()) {
1157 my $this_rs = $phenome_schema->resultset("StockImage")->search( { stock_id
=> $self->stock_id(), image_id
=> $row->image_id() } );
1158 if ($this_rs->count() == 0) {
1159 $row->stock_id($self->stock_id());
1161 print STDERR
"Moving image ".$row->image_id()." from stock $other_stock_id to stock ".$self->stock_id()."\n";
1165 print STDERR
"Removing stock_image entry...\n";
1166 $row->delete(); # there is no cascade delete on image relationships, so we need to remove dangling relationships.
1172 my $sors = $phenome_schema->resultset("StockOwner")->search( { stock_id
=> $other_stock_id });
1173 while (my $row = $sors->next()) {
1175 my $this_rs = $phenome_schema->resultset("StockOwner")->search( { stock_id
=> $self->stock_id(), sp_person_id
=> $row->sp_person_id() });
1176 if ($this_rs->count() == 0) {
1177 $row->stock_id($self->stock_id());
1179 print STDERR
"Moved stock_owner ".$row->sp_person_id()." of stock $other_stock_id to stock ".$self->stock_id()."\n";
1180 $stock_owner_count++;
1183 print STDERR
"(Deleting stock owner entry for stock $other_stock_id, owner ".$row->sp_person_id()."\n";
1184 $row->delete(); # see comment for move image relationships
1190 my $sgn_schema = SGN
::Schema
->connect(
1191 sub { $self->schema()->storage()->dbh() }, { limit_dialect
=> 'LimitOffset' }
1194 my $mrs1 = $sgn_schema->resultset("Map")->search( { parent_1
=> $other_stock_id });
1195 while (my $row = $mrs1->next()) {
1196 $row->parent_1($self->stock_id());
1198 print STDERR
"Move map parent_1 $other_stock_id to ".$self->stock_id()."\n";
1202 my $mrs2 = $sgn_schema->resultset("Map")->search( { parent_2
=> $other_stock_id });
1203 while (my $row = $mrs2->next()) {
1204 $row->parent_2($self->stock_id());
1206 print STDERR
"Move map parent_2 $other_stock_id to ".$self->stock_id()."\n";
1210 if ($delete_other_stock) {
1211 my $row = $self->schema()->resultset("Stock::Stock")->find( { stock_id
=> $other_stock_id });
1213 $other_stock_deleted = 'YES';
1217 print STDERR
"Done with merge of stock_id $other_stock_id into ".$self->stock_id()."\n";
1218 print STDERR
"Relationships moved: \n";
1219 print STDERR
<<COUNTS;
1220 Stock props: $stockprop_count
1221 Subject rels: $subject_rel_count
1222 Object rels: $object_rel_count
1223 Alleles: $stock_allele_count
1224 Images: $image_count
1225 Experiments: $experiment_stock_count
1226 Dbxrefs: $stock_dbxref_count
1227 Stock owners: $stock_owner_count
1228 Map parents: $parent_1_count
1229 Map parents: $parent_2_count
1230 Other stock deleted: $other_stock_deleted.
1235 __PACKAGE__
->meta->make_immutable;