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
'phenome_schema' => (
42 isa
=> 'CXGN::Phenome::Schema',
46 has
'check_name_exists' => (
53 isa
=> 'Bio::Chado::Schema::Result::Stock::Stock',
68 # Returns the stock_owners as [sp_person_id, sp_person_id2, ..]
70 isa
=> 'Maybe[ArrayRef[Int]]',
73 builder
=> '_retrieve_stock_owner',
77 isa
=> 'Bio::Chado::Schema::Result::Organism::Organism',
81 has
'organism_id' => (
96 has
'organism_common_name' => (
101 has
'organism_abbreviation' => (
106 has
'organism_comment' => (
114 default => 'accession',
127 has
'uniquename' => (
132 has
'description' => (
138 has
'is_obsolete' => (
144 has
'organization_name' => (
149 has
'population_name' => (
154 has
'populations' => (
155 isa
=> 'Maybe[ArrayRef[ArrayRef]]',
159 has
'sp_person_id' => (
169 has
'modification_note' => (
177 #print STDERR "RUNNING BUILD FOR STOCK.PM...\n";
179 if ($self->stock_id){
180 $stock = $self->schema()->resultset("Stock::Stock")->find({ stock_id
=> $self->stock_id() });
181 $self->stock($stock);
182 $self->stock_id($stock->stock_id);
184 if (defined $stock && !$self->is_saving) {
185 $self->organism_id($stock->organism_id);
186 $self->name($stock->name);
187 $self->uniquename($stock->uniquename);
188 $self->description($stock->description() || '');
189 $self->type_id($stock->type_id);
190 $self->type($self->schema()->resultset("Cv::Cvterm")->find({ cvterm_id
=>$self->type_id() })->name());
191 $self->is_obsolete($stock->is_obsolete);
192 $self->organization_name($self->_retrieve_stockprop('organization'));
193 $self->_retrieve_populations();
199 sub _retrieve_stock_owner
{
201 my $owner_rs = $self->phenome_schema->resultset("StockOwner")->search({
202 stock_id
=> $self->stock_id,
205 while (my $r = $owner_rs->next){
206 push @owners, $r->sp_person_id;
208 $self->owners(\
@owners);
214 Desc: store a new stock or update an existing stock
217 Side Effects: checks if the stock exists in the database (if a stock_id is provided), and if does, will attempt to update
226 my $stock = $self->stock;
227 my $schema = $self->schema();
229 #no stock id . Check first if the name exists in te database
231 if ($self->check_name_exists){
232 $exists= $self->exists_in_database();
235 if (!$self->type_id) {
236 my $type_id = SGN
::Model
::Cvterm
->get_cvterm_row($self->schema(), $self->type(), 'stock_type')->cvterm_id();
237 $self->type_id($type_id);
240 if (!$self->organism_id){
243 my $organism_rs = $self->schema->resultset("Organism::Organism")->search({ species
=>$self->species });
244 if ($organism_rs->count > 1){
245 return $return{error
} = "More than one organism returned for species: ".$self->species;
247 if ($organism_rs->count == 0){
248 return $return{error
} = "NO ORGANISM FOUND OF SPECIES: ".$self->species;
250 if ($organism_rs->count == 1){
251 my $organism = $organism_rs->first();
252 $self->organism($organism);
253 $self->organism_id($organism->organism_id);
254 $self->organism_abbreviation($organism->abbreviation);
255 $self->genus($organism->genus);
256 $self->species($organism->species);
257 $self->organism_common_name($organism->common_name);
258 $self->organism_comment($organism->comment);
263 if (!$stock) { #Trying to create a new stock
264 print STDERR
"Storing Stock ".localtime."\n";
267 my $new_row = $self->schema()->resultset("Stock::Stock")->create({
268 name
=> $self->name(),
269 uniquename
=> $self->uniquename(),
270 description
=> $self->description(),
271 type_id
=> $self->type_id(),
272 organism_id
=> $self->organism_id(),
273 is_obsolete
=> $self->is_obsolete(),
277 my $id = $new_row->stock_id();
278 $self->stock_id($id);
279 $self->stock($new_row);
281 if ($self->organization_name){
282 $self->_store_stockprop('organization', $self->organization_name());
284 if ($self->population_name){
285 $self->_store_population_relationship();
290 die "The entry ".$self->uniquename()." already exists in the database. Error: $exists\n";
294 print STDERR
"Updating Stock ".localtime."\n";
295 if (!$self->name && $self->uniquename){
296 $self->name($self->uniquename);
298 my $row = $self->schema()->resultset("Stock::Stock")->find({ stock_id
=> $self->stock_id() });
299 if ($self->name){ $row->name($self->name()) };
300 if ($self->uniquename){ $row->uniquename($self->uniquename()) };
301 if ($self->description){ $row->description($self->description()) };
302 if ($self->type_id){ $row->type_id($self->type_id()) };
303 if ($self->organism_id){ $row->organism_id($self->organism_id()) };
304 if ($self->is_obsolete){ $row->is_obsolete($self->is_obsolete()) };
306 if ($self->organization_name){
307 $self->_update_stockprop('organization', $self->organization_name());
309 if ($self->population_name){
310 $self->_update_population_relationship();
313 $self->associate_owner($self->sp_person_id, $self->sp_person_id, $self->user_name, $self->modification_note);
315 return $self->stock_id();
318 ########################
321 =head2 exists_in_database
323 Usage: $self->exists_in_database()
324 Desc: check if the uniquename exists in the stock table
332 sub exists_in_database
{
334 my $schema = $self->schema;
335 my $stock = $self->stock;
336 my $stock_id = $self->stock_id;
337 my $uniquename = $self->uniquename || '' ;
338 my $stock_lookup = CXGN
::Stock
::StockLookup
->new({
340 stock_name
=> $uniquename
342 my $s = $stock_lookup->get_stock();
344 # loading new stock - $stock_id is undef
346 if (defined($s) && !$stock ) {
347 return "Uniquename already exists in database with stock_id: ".$s->stock_id;
350 # updating an existing stock
352 elsif ($stock && defined($s) ) {
353 if ( ($s->stock_id == $stock_id) ) {
355 #trying to update the uniquename
357 elsif ( $s->stock_id != $stock_id ) {
358 return " Can't update an existing stock $stock_id uniquename:$uniquename.";
359 # if the new name we're trying to update/insert does not exist
360 # in the stock table..
363 elsif ($stock && !$s->stock_id) {
372 Usage: $self->get_organism
373 Desc: find the organism object of this stock
374 Ret: L<Bio::Chado::Schema::Organism::Organism> object
383 my $bcs_stock = $self->schema()->resultset("Stock::Stock")->find( { stock_id
=> $self->stock_id() });
385 return $bcs_stock->organism;
393 Usage: $self->get_species
394 Desc: find the species name of this stock , if one exists
404 my $organism = $self->get_organism;
406 return $organism->species;
415 Usage: $self->get_genus
416 Desc: find the genus name of this stock , if one exists
426 my $organism = $self->get_organism;
428 return $organism->genus;
435 =head2 get_species_authority
437 Usage: $self->get_species_authority
438 Desc: find the species_authority of this stock , if one exists
446 sub get_species_authority
{
448 return $self->_retrieve_organismprop('species authority');
453 Usage: $self->get_subtaxa
454 Desc: find the subtaxa of this stock , if one exists
464 return $self->_retrieve_organismprop('subtaxa');
467 =head2 get_subtaxa_authority
469 Usage: $self->get_subtaxa_authority
470 Desc: find the subtaxa_authority of this stock , if one exists
478 sub get_subtaxa_authority
{
480 return $self->_retrieve_organismprop('subtaxa authority');
485 Usage: $self->set_species
486 Desc: set organism_id for the stock using organism.species name
488 Args: species name (case insensitive)
489 Side Effects: sets the organism_id for the stock
496 my $species_name = shift; # this has to be EXACTLY as stored in the organism table
497 my $organism = $self->get_schema->resultset('Organism::Organism')->search(
498 { 'lower(species)' => { like
=> lc($species_name) } } )->single ; #should be 1 result
500 $self->organism_id($organism->organism_id);
503 warn "NO organism found for species name $species_name!!\n";
507 =head2 function get_image_ids
509 Synopsis: my @images = $self->get_image_ids()
511 Returns: a list of image ids
513 Description: a method for fetching all images associated with a stock
520 my $q = "select distinct image_id, cvterm.name, stock_image.display_order FROM phenome.stock_image JOIN stock USING(stock_id) JOIN cvterm ON(type_id=cvterm_id) WHERE stock_id = ? ORDER BY stock_image.display_order ASC";
521 my $h = $self->schema->storage->dbh()->prepare($q);
522 $h->execute($self->stock_id);
523 while (my ($image_id, $stock_type, $display_order) = $h->fetchrow_array()){
524 push @ids, [$image_id, $stock_type];
529 =head2 associate_allele
531 Usage: $self->associate_allele($allele_id, $sp_person_id)
532 Desc: store a stock-allele link in phenome.stock_allele
534 Args: allele_id, sp_person_id
535 Side Effects: store a metadata row
540 sub associate_allele
{
542 my $allele_id = shift;
543 my $sp_person_id = shift;
544 if (!$allele_id || !$sp_person_id) {
545 warn "Need both allele_id and person_id for linking the stock with an allele!";
548 my $metadata_id = $self->_new_metadata_id($sp_person_id);
549 #check if the allele is already linked
550 my $ids = $self->schema()->storage()->dbh()->selectcol_arrayref
551 ( "SELECT stock_allele_id FROM phenome.stock_allele WHERE stock_id = ? AND allele_id = ?",
556 if ($ids) { warn "Allele $allele_id is already linked with stock " . $self->stock_id ; }
557 #store the allele_id - stock_id link
558 my $q = "INSERT INTO phenome.stock_allele (stock_id, allele_id, metadata_id) VALUES (?,?,?) RETURNING stock_allele_id";
559 my $sth = $self->schema()->storage()->dbh()->prepare($q);
560 $sth->execute($self->stock_id, $allele_id, $metadata_id);
561 my ($id) = $sth->fetchrow_array;
565 =head2 associate_owner
567 Usage: $self->associate_owner($owner_sp_person_id, $sp_person_id)
568 Desc: store a stock-owner link in phenome.stock_owner
570 Args: owner_id, sp_person_id
571 Side Effects: store a metadata row
576 sub associate_owner
{
578 my $owner_id = shift;
579 my $sp_person_id = shift;
580 my $user_name = shift;
581 my $modification_note = shift;
582 if (!$owner_id || !$sp_person_id) {
583 warn "Need both owner_id and person_id for linking the stock with an owner!";
586 my $metadata_id = $self->_new_metadata_id($sp_person_id, $user_name, $modification_note);
587 #check if the owner is already linked
588 my $ids = $self->schema()->storage()->dbh()->selectcol_arrayref
589 ( "SELECT stock_owner_id FROM phenome.stock_owner WHERE stock_id = ? AND sp_person_id = ?",
594 if ($ids) { warn "Owner $owner_id is already linked with stock " . $self->stock_id ; }
595 #store the owner_id - stock_id link
596 my $q = "INSERT INTO phenome.stock_owner (stock_id, sp_person_id, metadata_id) VALUES (?,?,?) RETURNING stock_owner_id";
597 my $sth = $self->schema()->storage()->dbh()->prepare($q);
598 $sth->execute($self->stock_id, $owner_id, $metadata_id);
599 my ($id) = $sth->fetchrow_array;
603 =head2 get_trait_list
606 Desc: gets the list of traits that have been measured
608 Ret: a list of lists ( [ cvterm_id, cvterm_name] , ...)
618 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";
619 my $h = $self->schema()->storage()->dbh()->prepare($q);
620 my $numeric_regex = '^[0-9]+([,.][0-9]+)?$';
621 $h->execute($self->stock_id(), $numeric_regex);
623 while (my ($cvterm_id, $cvterm_accession, $cvterm_name, $avg, $stddev) = $h->fetchrow_array()) {
624 push @traits, [ $cvterm_id, $cvterm_accession, $cvterm_name, $avg, $stddev ];
627 # get directly associated traits
629 $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";
631 $h = $self->schema()->storage()->dbh()->prepare($q);
632 $numeric_regex = '^[0-9]+([,.][0-9]+)?$';
633 $h->execute($self->stock_id(), $numeric_regex);
635 while (my ($cvterm_id, $cvterm_accession, $cvterm_name, $avg, $stddev) = $h->fetchrow_array()) {
636 push @traits, [ $cvterm_id, $cvterm_accession, $cvterm_name, $avg, $stddev ];
645 Desc: gets the list of trails this stock was used in
655 my $dbh = $self->schema()->storage()->dbh();
657 my $geolocation_q = "SELECT nd_geolocation_id, description FROM nd_geolocation;";
658 my $geolocation_h = $dbh->prepare($geolocation_q);
659 $geolocation_h->execute();
662 while (my ($nd_geolocation_id, $description) = $geolocation_h->fetchrow_array()) {
663 $geolocations{$nd_geolocation_id} = $description;
666 my $geolocation_type_id = SGN
::Model
::Cvterm
->get_cvterm_row($self->schema(), 'project location', 'project_property')->cvterm_id();
667 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=?;";
669 my $h = $dbh->prepare($q);
670 $h->execute($self->stock_id());
673 while (my ($project_id, $project_name, $nd_geolocation_id) = $h->fetchrow_array()) {
674 push @trials, [ $project_id, $project_name, $nd_geolocation_id, $geolocations{$nd_geolocation_id} ];
679 =head2 get_ancestor_hash
682 Desc: gets a multi-dimensional hash of this stock's ancestors
690 sub get_ancestor_hash
{
691 my ($self, $stock_id, $direct_descendant_ids) = @_;
693 if (!$stock_id) { $stock_id = $self->stock_id(); }
694 push @
$direct_descendant_ids, $stock_id; #excluded in parent retrieval to prevent loops
696 my $stock = $self->schema->resultset("Stock::Stock")->find({stock_id
=> $stock_id});
697 #print STDERR "Stock ".$stock->uniquename()." decendants are: ".Dumper($direct_descendant_ids)."\n";
699 $pedigree{'id'} = $stock_id;
700 $pedigree{'name'} = $stock->uniquename();
701 $pedigree{'female_parent'} = undef;
702 $pedigree{'male_parent'} = undef;
703 $pedigree{'link'} = "/stock/$stock_id/view";
705 #get cvterms for parent relationships
706 my $cvterm_female_parent = SGN
::Model
::Cvterm
->get_cvterm_row($self->schema, 'female_parent', 'stock_relationship');
707 my $cvterm_male_parent = SGN
::Model
::Cvterm
->get_cvterm_row($self->schema, 'male_parent', 'stock_relationship');
709 #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.
710 my $stock_relationships = $stock->search_related("stock_relationship_objects",undef,{ prefetch
=> ['type','subject'] });
711 my $female_parent_relationship = $stock_relationships->find({type_id
=> $cvterm_female_parent->cvterm_id(), subject_id
=> {'not_in' => $direct_descendant_ids}});
712 if ($female_parent_relationship) {
713 my $female_parent_stock_id = $female_parent_relationship->subject_id();
714 $pedigree{'cross_type'} = $female_parent_relationship->value();
715 $pedigree{'female_parent'} = get_ancestor_hash
( $self, $female_parent_stock_id, $direct_descendant_ids );
717 my $male_parent_relationship = $stock_relationships->find({type_id
=> $cvterm_male_parent->cvterm_id(), subject_id
=> {'not_in' => $direct_descendant_ids}});
718 if ($male_parent_relationship) {
719 my $male_parent_stock_id = $male_parent_relationship->subject_id();
720 $pedigree{'male_parent'} = get_ancestor_hash
( $self, $male_parent_stock_id, $direct_descendant_ids );
722 pop @
$direct_descendant_ids; # falling back a level while recursing pedigree tree
726 =head2 get_descendant_hash
729 Desc: gets a multi-dimensional hash of this stock's descendants
737 sub get_descendant_hash
{
738 my ($self, $stock_id, $direct_ancestor_ids) = @_;
740 if (!$stock_id) { $stock_id = $self->stock_id(); }
741 push @
$direct_ancestor_ids, $stock_id; #excluded in child retrieval to prevent loops
743 my $stock = $self->schema->resultset("Stock::Stock")->find({stock_id
=> $stock_id});
744 #print STDERR "Stock ".$stock->uniquename()." ancestors are: ".Dumper($direct_ancestor_ids)."\n";
747 $descendants{'id'} = $stock_id;
748 $descendants{'name'} = $stock->uniquename();
749 $descendants{'link'} = "/stock/$stock_id/view";
750 #get cvterms for parent relationships
751 my $cvterm_female_parent = SGN
::Model
::Cvterm
->get_cvterm_row($self->schema, 'female_parent','stock_relationship');
752 my $cvterm_male_parent = SGN
::Model
::Cvterm
->get_cvterm_row($self->schema, 'male_parent', 'stock_relationship');
754 #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.
755 my $descendant_relationships = $stock->search_related("stock_relationship_subjects",{ object_id
=> {'not_in' => $direct_ancestor_ids}},{ prefetch
=> ['type','object'] });
756 if ($descendant_relationships) {
757 while (my $descendant_relationship = $descendant_relationships->next) {
758 my $descendant_stock_id = $descendant_relationship->object_id();
759 if (($descendant_relationship->type_id() == $cvterm_female_parent->cvterm_id()) || ($descendant_relationship->type_id() == $cvterm_male_parent->cvterm_id())) {
760 $progeny{$descendant_stock_id} = get_descendant_hash
($self, $descendant_stock_id, $direct_ancestor_ids);
763 $descendants{'descendants'} = \
%progeny;
764 pop @
$direct_ancestor_ids; # falling back a level while recursing descendant tree
765 return \
%descendants;
769 =head2 get_pedigree_rows
772 Desc: get an array of pedigree rows from an array of stock ids, conatining female parent, male parent, and cross type if defined
774 Args: $accession_ids, $format (either 'parents_only' or 'full')
780 sub get_pedigree_rows
{
781 my ($self, $accession_ids, $format) = @_;
782 #print STDERR "Accession ids are: ".Dumper(@$accession_ids)."\n";
784 my $placeholders = join ( ',', ('?') x @
$accession_ids );
785 my ($query, $pedigree_rows);
787 if ($format eq 'parents_only') {
789 SELECT child.uniquename AS Accession,
790 mother.uniquename AS Female_Parent,
791 father.uniquename AS Male_Parent,
792 m_rel.value AS cross_type
794 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'))
795 LEFT JOIN stock mother ON(m_rel.subject_id = mother.stock_id)
796 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'))
797 LEFT JOIN stock father ON(f_rel.subject_id = father.stock_id)
798 WHERE child.stock_id IN ($placeholders)
802 elsif ($format eq 'full') {
804 WITH RECURSIVE included_rows(child, child_id, mother, mother_id, father, father_id, type, depth, path, cycle) AS (
805 SELECT c.uniquename AS child,
806 c.stock_id AS child_id,
807 m.uniquename AS mother,
808 m.stock_id AS mother_id,
809 f.uniquename AS father,
810 f.stock_id AS father_id,
816 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'))
817 LEFT JOIN stock m ON(m_rel.subject_id = m.stock_id)
818 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'))
819 LEFT JOIN stock f ON(f_rel.subject_id = f.stock_id)
820 WHERE c.stock_id IN ($placeholders)
821 GROUP BY 1,2,3,4,5,6,7,8,9,10
823 SELECT c.uniquename AS child,
824 c.stock_id AS child_id,
825 m.uniquename AS mother,
826 m.stock_id AS mother_id,
827 f.uniquename AS father,
828 f.stock_id AS father_id,
830 included_rows.depth + 1,
832 c.stock_id = ANY(path)
833 FROM included_rows, stock c
834 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'))
835 LEFT JOIN stock m ON(m_rel.subject_id = m.stock_id)
836 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'))
837 LEFT JOIN stock f ON(f_rel.subject_id = f.stock_id)
838 WHERE c.stock_id IN (included_rows.mother_id, included_rows.father_id) AND NOT cycle
839 GROUP BY 1,2,3,4,5,6,7,8,9,10
841 SELECT child, mother, father, type, depth
847 my $sth = $self->schema()->storage()->dbh()->prepare($query);
848 $sth->execute(@
$accession_ids);
850 no warnings
'uninitialized';
851 while (my ($name, $mother, $father, $cross_type, $depth) = $sth->fetchrow_array()) {
852 #print STDERR "For child $name:\n\tMother:$mother\n\tFather:$father\n\tCross Type:$cross_type\n\tDepth:$depth\n\n";
853 push @
$pedigree_rows, "$name\t$mother\t$father\t$cross_type\n";
855 return $pedigree_rows;
858 =head2 get_pedigree_string
861 Desc: get the properly formatted pedigree string of the given level (Parents, Grandparents, or Great-Grandparents) for this stock
869 sub get_pedigree_string
{
870 my ($self, $level) = @_;
872 my $pedigree_hashref = $self->get_ancestor_hash();
874 #print STDERR "Getting string of level $level from pedigree hashref ".Dumper($pedigree_hashref)."\n";
875 if ($level eq "Parents") {
876 return $self->_get_parent_string($pedigree_hashref);
878 elsif ($level eq "Grandparents") {
879 my $maternal_parent_string = $self->_get_parent_string($pedigree_hashref->{'female_parent'});
880 my $paternal_parent_string = $self->_get_parent_string($pedigree_hashref->{'male_parent'});
881 return "$maternal_parent_string//$paternal_parent_string";
883 elsif ($level eq "Great-Grandparents") {
884 my $mm_parent_string = $self->_get_parent_string($pedigree_hashref->{'female_parent'}->{'female_parent'});
885 my $mf_parent_string = $self->_get_parent_string($pedigree_hashref->{'female_parent'}->{'male_parent'});
886 my $pm_parent_string = $self->_get_parent_string($pedigree_hashref->{'male_parent'}->{'female_parent'});
887 my $pf_parent_string = $self->_get_parent_string($pedigree_hashref->{'male_parent'}->{'male_parent'});
888 return "$mm_parent_string//$mf_parent_string///$pm_parent_string//$pf_parent_string";
892 sub _get_parent_string
{
893 my ($self, $pedigree_hashref) = @_;
894 my $mother = $pedigree_hashref->{'female_parent'}->{'name'} || 'NA';
895 my $father = $pedigree_hashref->{'male_parent'}->{'name'} || 'NA';
896 return "$mother/$father";
901 my $pedigree_hashref = $self->get_ancestor_hash();
903 $parents{'mother'} = $pedigree_hashref->{'female_parent'}->{'name'};
904 $parents{'mother_id'} = $pedigree_hashref->{'female_parent'}->{'id'};
905 $parents{'father'} = $pedigree_hashref->{'male_parent'}->{'name'};
906 $parents{'father_id'} = $pedigree_hashref->{'male_parent'}->{'id'};
910 sub _store_stockprop
{
914 #print STDERR Dumper $type;
915 my $stockprop = SGN
::Model
::Cvterm
->get_cvterm_row($self->schema, $type, 'stock_property')->name();
916 my @arr = split ',', $value;
918 my $stored_stockprop = $self->stock->create_stockprops({ $stockprop => $_});
922 sub _update_stockprop
{
926 my $stockprop_cvterm_id = SGN
::Model
::Cvterm
->get_cvterm_row($self->schema, $type, 'stock_property')->cvterm_id();
927 my $rs = $self->stock->search_related('stockprops', {'type_id'=>$stockprop_cvterm_id});
928 while(my $r=$rs->next){
931 $self->_store_stockprop($type,$value);
934 sub _retrieve_stockprop
{
940 my $stockprop_type_id = SGN
::Model
::Cvterm
->get_cvterm_row($self->schema, $type, 'stock_property')->cvterm_id();
941 my $rs = $self->schema()->resultset("Stock::Stockprop")->search({ stock_id
=> $self->stock_id(), type_id
=> $stockprop_type_id }, { order_by
=> {-asc
=> 'stockprop_id'} });
943 while (my $r = $rs->next()){
944 push @results, $r->value;
947 #print STDERR "Cvterm $type does not exist in this database\n";
950 my $res = join ',', @results;
954 sub _remove_stockprop
{
958 my $type_id = SGN
::Model
::Cvterm
->get_cvterm_row($self->schema, $type, 'stock_property')->cvterm_id();
959 my $rs = $self->schema()->resultset("Stock::Stockprop")->search( { type_id
=>$type_id, stock_id
=> $self->stock_id(), value
=>$value } );
961 if ($rs->count() == 1) {
962 $rs->first->delete();
965 elsif ($rs->count() == 0) {
969 print STDERR
"Error removing stockprop from stock ".$self->stock_id().". Please check this manually.\n";
975 sub _retrieve_organismprop
{
981 my $organismprop_type_id = SGN
::Model
::Cvterm
->get_cvterm_row($self->schema, $type, 'organism_property')->cvterm_id();
982 my $rs = $self->schema()->resultset("Organism::Organismprop")->search({ organism_id
=> $self->stock->organism_id, type_id
=> $organismprop_type_id }, { order_by
=> {-asc
=> 'organismprop_id'} });
984 while (my $r = $rs->next()){
985 push @results, $r->value;
988 #print STDERR "Cvterm $type does not exist in this database\n";
991 my $res = join ',', @results;
995 sub _store_population_relationship
{
997 my $schema = $self->schema;
998 my $population_cvterm_id = SGN
::Model
::Cvterm
->get_cvterm_row($schema, 'population','stock_type')->cvterm_id();
999 my $population_member_cvterm_id = SGN
::Model
::Cvterm
->get_cvterm_row($schema, 'member_of','stock_relationship')->cvterm_id();
1001 my $population = $schema->resultset("Stock::Stock")->find_or_create({
1002 uniquename
=> $self->population_name(),
1003 name
=> $self->population_name(),
1004 organism_id
=> $self->organism_id(),
1005 type_id
=> $population_cvterm_id,
1007 $self->stock->find_or_create_related('stock_relationship_subjects', {
1008 type_id
=> $population_member_cvterm_id,
1009 object_id
=> $population->stock_id(),
1010 subject_id
=> $self->stock_id(),
1014 sub _update_population_relationship
{
1016 my $population_member_cvterm_id = SGN
::Model
::Cvterm
->get_cvterm_row($self->schema, 'member_of','stock_relationship')->cvterm_id();
1017 my $pop_rs = $self->stock->search_related('stock_relationship_subjects', {'type_id'=>$population_member_cvterm_id});
1018 while (my $r=$pop_rs->next){
1021 $self->_store_population_relationship();
1024 sub _retrieve_populations
{
1026 my $schema = $self->schema;
1027 my $population_member_cvterm_id = SGN
::Model
::Cvterm
->get_cvterm_row($schema, 'member_of','stock_relationship')->cvterm_id();
1029 my $rs = $schema->resultset("Stock::StockRelationship")->search({
1030 type_id
=> $population_member_cvterm_id,
1031 subject_id
=> $self->stock_id(),
1033 if ($rs->count == 0) {
1034 #print STDERR "No population saved for this stock!\n";
1037 my @population_names;
1038 my @population_name;
1039 while (my $row = $rs->next) {
1040 my $population = $row->object;
1041 push @population_name, $population->uniquename();
1042 push @population_names, [$population->stock_id(), $population->uniquename()];
1044 my $pop_string = join ',', @population_name;
1045 $self->populations(\
@population_names);
1046 $self->population_name($pop_string);
1050 =head2 _new_metadata_id
1052 Usage: my $md_id = $self->_new_metatada_id($sp_person_id)
1053 Desc: Store a new md_metadata row with a $sp_person_id
1059 sub _new_metadata_id
{
1061 my $sp_person_id = shift;
1062 my $user_name = shift;
1063 my $modification_note = shift;
1064 my $metadata_schema = CXGN
::Metadata
::Schema
->connect(
1065 sub { $self->schema()->storage()->dbh() },
1067 $metadata_schema->storage->dbh->do('SET search_path TO metadata');
1068 my $metadata = CXGN
::Metadata
::Metadbdata
->new($metadata_schema);
1069 $metadata->set_create_person_id($sp_person_id);
1070 my $metadata_id = $metadata->store()->get_metadata_id();
1071 if ($modification_note){
1072 my $metadata = CXGN
::Metadata
::Metadbdata
->new($metadata_schema, $user_name, $metadata_id);
1073 $metadata->set_modification_note($modification_note);
1074 $metadata_id = $metadata->store()->get_metadata_id();
1076 $metadata_schema->storage->dbh->do('SET search_path TO public,sgn');
1077 return $metadata_id;
1082 Usage: $s->merge(221, 1);
1083 Desc: merges stock $s with stock_id 221. Optional delete boolean
1084 parameter indicates whether other stock should be deleted.
1094 my $other_stock_id = shift;
1095 my $delete_other_stock = shift;
1097 if ($other_stock_id == $self->stock_id()) {
1098 print STDERR
"Trying to merge stock into itself ($other_stock_id) Skipping...\n";
1104 my $stockprop_count=0;
1105 my $subject_rel_count=0;
1106 my $object_rel_count=0;
1107 my $stock_allele_count=0;
1109 my $experiment_stock_count=0;
1110 my $stock_dbxref_count=0;
1111 my $stock_owner_count=0;
1112 my $parent_1_count=0;
1113 my $parent_2_count=0;
1114 my $other_stock_deleted = 'NO';
1117 my $schema = $self->schema();
1121 my $sprs = $schema->resultset("Stock::Stockprop")->search( { stock_id
=> $other_stock_id });
1122 while (my $row = $sprs->next()) {
1124 # check if this stockprop already exists for this stock; save only if not
1126 my $thissprs = $schema->resultset("Stock::Stockprop")->search(
1128 stock_id
=> $self->stock_id(),
1129 type_id
=> $row->type_id(),
1130 value
=> $row->value()
1133 if ($thissprs->count() == 0) {
1134 my $value = $row->value();
1135 my $type_id = $row->type_id();
1137 my $rank_rs = $schema->resultset("Stock::Stockprop")->search( { stock_id
=> $self->stock_id(), type_id
=> $type_id });
1140 if ($rank_rs->count() > 0) {
1141 $rank = $rank_rs->get_column("rank")->max();
1146 $row->stock_id($self->stock_id());
1150 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";
1155 # move subject relationships
1157 my $ssrs = $schema->resultset("Stock::StockRelationship")->search( { subject_id
=> $other_stock_id });
1159 while (my $row = $ssrs->next()) {
1161 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() });
1163 if ($this_subject_rel_rs->count() == 0) { # this stock does not have the relationship
1165 my $rank_rs = $schema->resultset("Stock::StockRelationship")->search( { subject_id
=> $self->stock_id(), type_id
=> $row->type_id() });
1167 if ($rank_rs->count() > 0) {
1168 $rank = $rank_rs->get_column("rank")->max();
1172 $row->subject_id($self->stock_id());
1174 print STDERR
"Moving subject relationships from stock $other_stock_id to stock ".$self->stock_id()."\n";
1175 $subject_rel_count++;
1179 # move object relationships
1181 my $osrs = $schema->resultset("Stock::StockRelationship")->search( { object_id
=> $other_stock_id });
1182 while (my $row = $osrs->next()) {
1183 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() });
1185 if ($this_object_rel_rs->count() == 0) {
1186 my $rank_rs = $schema->resultset("Stock::StockRelationship")->search( { object_id
=> $self->stock_id(), type_id
=> $row->type_id() });
1188 if ($rank_rs->count() > 0) {
1189 $rank = $rank_rs->get_column("rank")->max();
1193 $row->object_id($self->stock_id());
1195 print STDERR
"Moving object relationships from stock $other_stock_id to stock ".$self->stock_id()."\n";
1196 $object_rel_count++;
1200 # move experiment_stock
1202 my $esrs = $schema->resultset("NaturalDiversity::NdExperimentStock")->search( { stock_id
=> $other_stock_id });
1203 while (my $row = $esrs->next()) {
1204 $row->stock_id($self->stock_id());
1206 print STDERR
"Moving experiments for stock $other_stock_id to stock ".$self->stock_id()."\n";
1207 $experiment_stock_count++;
1210 # move stock_cvterm relationships
1216 my $sdrs = $schema->resultset("Stock::StockDbxref")->search( { stock_id
=> $other_stock_id });
1217 while (my $row = $sdrs->next()) {
1218 $row->stock_id($self->stock_id());
1220 $stock_dbxref_count++;
1223 # move sgn.pcr_exp_accession relationships
1227 # move sgn.pcr_experiment relationships
1232 # move stock_genotype relationships
1236 my $phenome_schema = CXGN
::Phenome
::Schema
->connect(
1237 sub { $self->schema()->storage()->dbh() }, { on_connect_do
=> [ 'SET search_path TO phenome, public, sgn'], limit_dialect
=> 'LimitOffset' }
1240 # move phenome.stock_allele relationships
1242 my $sars = $phenome_schema->resultset("StockAllele")->search( { stock_id
=> $other_stock_id });
1243 while (my $row = $sars->next()) {
1244 $row->stock_id($self->stock_id());
1246 print STDERR
"Moving stock alleles from stock $other_stock_id to stock ".$self->stock_id()."\n";
1247 $stock_allele_count++;
1250 # move image relationships
1252 my $irs = $phenome_schema->resultset("StockImage")->search( { stock_id
=> $other_stock_id });
1253 while (my $row = $irs->next()) {
1255 my $this_rs = $phenome_schema->resultset("StockImage")->search( { stock_id
=> $self->stock_id(), image_id
=> $row->image_id() } );
1256 if ($this_rs->count() == 0) {
1257 $row->stock_id($self->stock_id());
1259 print STDERR
"Moving image ".$row->image_id()." from stock $other_stock_id to stock ".$self->stock_id()."\n";
1263 print STDERR
"Removing stock_image entry...\n";
1264 $row->delete(); # there is no cascade delete on image relationships, so we need to remove dangling relationships.
1270 my $sors = $phenome_schema->resultset("StockOwner")->search( { stock_id
=> $other_stock_id });
1271 while (my $row = $sors->next()) {
1273 my $this_rs = $phenome_schema->resultset("StockOwner")->search( { stock_id
=> $self->stock_id(), sp_person_id
=> $row->sp_person_id() });
1274 if ($this_rs->count() == 0) {
1275 $row->stock_id($self->stock_id());
1277 print STDERR
"Moved stock_owner ".$row->sp_person_id()." of stock $other_stock_id to stock ".$self->stock_id()."\n";
1278 $stock_owner_count++;
1281 print STDERR
"(Deleting stock owner entry for stock $other_stock_id, owner ".$row->sp_person_id()."\n";
1282 $row->delete(); # see comment for move image relationships
1288 my $sgn_schema = SGN
::Schema
->connect(
1289 sub { $self->schema()->storage()->dbh() }, { limit_dialect
=> 'LimitOffset' }
1292 my $mrs1 = $sgn_schema->resultset("Map")->search( { parent_1
=> $other_stock_id });
1293 while (my $row = $mrs1->next()) {
1294 $row->parent_1($self->stock_id());
1296 print STDERR
"Move map parent_1 $other_stock_id to ".$self->stock_id()."\n";
1300 my $mrs2 = $sgn_schema->resultset("Map")->search( { parent_2
=> $other_stock_id });
1301 while (my $row = $mrs2->next()) {
1302 $row->parent_2($self->stock_id());
1304 print STDERR
"Move map parent_2 $other_stock_id to ".$self->stock_id()."\n";
1308 if ($delete_other_stock) {
1309 my $row = $self->schema()->resultset("Stock::Stock")->find( { stock_id
=> $other_stock_id });
1311 $other_stock_deleted = 'YES';
1315 print STDERR
"Done with merge of stock_id $other_stock_id into ".$self->stock_id()."\n";
1316 print STDERR
"Relationships moved: \n";
1317 print STDERR
<<COUNTS;
1318 Stock props: $stockprop_count
1319 Subject rels: $subject_rel_count
1320 Object rels: $object_rel_count
1321 Alleles: $stock_allele_count
1322 Images: $image_count
1323 Experiments: $experiment_stock_count
1324 Dbxrefs: $stock_dbxref_count
1325 Stock owners: $stock_owner_count
1326 Map parents: $parent_1_count
1327 Map parents: $parent_2_count
1328 Other stock deleted: $other_stock_deleted.
1333 __PACKAGE__
->meta->make_immutable;