1 package CXGN
::BrAPI
::v2
::Germplasm
;
5 use SGN
::Model
::Cvterm
;
7 use CXGN
::Stock
::Search
;
9 use CXGN
::BrAPI
::v2
::ExternalReferences
;
10 use CXGN
::Chado
::Organism
;
11 use CXGN
::BrAPI
::Pagination
;
12 use CXGN
::BrAPI
::JSONResponse
;
17 extends
'CXGN::BrAPI::v2::Common';
24 my $page_size = $self->page_size;
25 my $page = $self->page;
26 my $status = $self->status;
29 my $crop_names_arrayref = $params->{commonCropName
} || ($params->{commonCropNames
} || ());
30 my $germplasm_names_arrayref = $params->{germplasmName
} || ($params->{germplasmNames
} || ());
31 my $accession_numbers_arrayref = $params->{accessionNumber
} || ($params->{accessionNumbers
} || ());
32 my $genera_arrayref = $params->{genus
} || ($params->{genera
} || ());
33 my $germplasm_ids_arrayref = $params->{germplasmDbId
} || ($params->{germplasmDbIds
} || ());
34 my $germplasm_puis_arrayref = $params->{germplasmPUI
} || ($params->{germplasmPUIs
} || ());
35 my $species_arrayref = $params->{species
} || ($params->{species
} || ());
36 my $synonyms_arrayref = $params->{synonym
} || ($params->{synonyms
} || ());
37 my $subtaxa = $params->{germplasmSubTaxa
}->[0];
38 my $match_method = $params->{matchMethod
}->[0] || 'exact';
39 my $collection = $params->{collection
} || ($params->{collections
} || ());
40 my $study_db_id = $params->{studyDbId
} || ($params->{studyDbIds
} || ());
41 my $study_names = $params->{studyName
} || ($params->{studyNames
} || ());
42 my $parent_db_id = $params->{parentDbId
} || ($params->{parentDbIds
} || ());
43 my $progeny_db_id = $params->{progenyDbId
} || ($params->{progenyDbIds
} || ());
44 my $external_reference_id_arrayref = $params->{externalReferenceID
} || ($params->{externalReferenceIDs
} || ());
45 my $external_reference_source_arrayref = $params->{externalReferenceSource
} || ($params->{externalReferenceSources
} || ());
47 if ( $collection || $progeny_db_id || $parent_db_id ){
48 push @
$status, { 'error' => 'The following search parameters are not implemented: collection, parentDbId, progenyDbId' };
51 if ($match_method ne 'exact' && $match_method ne 'wildcard') {
52 push @
$status, { 'error' => "matchMethod '$match_method' not recognized. Allowed matchMethods: wildcard, exact. Wildcard allows % or * for multiple characters and ? for single characters." };
55 if ($match_method eq 'exact'){
56 $match_type = 'exactly';
58 if ($match_method eq 'wildcard'){
59 $match_type = 'contains';
62 my $accession_type_cvterm_id = SGN
::Model
::Cvterm
->get_cvterm_row($self->bcs_schema, 'accession', 'stock_type')->cvterm_id();
64 my $limit = $page_size*($page+1)-1;
65 my $offset = $page_size*$page;
68 'accession number'=>1,
69 'acquisition date'=>1,
70 'biological status of accession code'=>1,
71 'country of origin'=>1,
76 'ncbi_taxonomy_id'=>1,
79 'stock_additional_info'=>1,
80 'type of germplasm storage code'=>1 );
82 ## Additional stock props for additional info.
83 my %additional_stock_props;
84 my @editable_stock_props = SGN
::Context
->new()->get_conf('editable_stock_props') ?
split ',', SGN
::Context
->new()->get_conf('editable_stock_props'): undef;
86 my %editable_stock_props = map { $_=>1 } @editable_stock_props;
88 foreach (keys %editable_stock_props){
89 if(!%stock_props{$_}){
90 $additional_stock_props{$_} = 1;
94 if (%additional_stock_props){
95 %stock_props = (%stock_props, %additional_stock_props);
99 my %stockprops_values;
100 if ($accession_numbers_arrayref && scalar(@
$accession_numbers_arrayref)>0){
101 $stockprops_values{'accession number'} = {
102 matchtype
=> 'one of',
103 value
=> join(',', @
$accession_numbers_arrayref)
106 if ($germplasm_puis_arrayref && scalar(@
$germplasm_puis_arrayref)>0){
107 foreach (@
$germplasm_puis_arrayref) {
108 $stockprops_values{'PUI'} = {
109 matchtype
=> 'contains',
114 if ($synonyms_arrayref && scalar(@
$synonyms_arrayref)>0){
115 foreach (@
$synonyms_arrayref) {
116 $stockprops_values{'stock_synonym'} = {
117 matchtype
=> 'contains',
123 my $references = CXGN
::BrAPI
::v2
::ExternalReferences
->new({
124 bcs_schema
=> $self->bcs_schema,
125 table_name
=> 'stock',
126 table_id_key
=> 'stock_id',
127 id
=> $germplasm_ids_arrayref
129 my $reference_result = $references->search();
132 my $stock_search = CXGN
::Stock
::Search
->new({
133 bcs_schema
=>$self->bcs_schema,
134 people_schema
=>$self->people_schema,
135 phenome_schema
=>$self->phenome_schema,
136 match_type
=>$match_type,
137 uniquename_list
=>$germplasm_names_arrayref,
138 genus_list
=>$genera_arrayref,
139 species_list
=>$species_arrayref,
140 crop_name_list
=>$crop_names_arrayref,
141 stock_id_list
=>$germplasm_ids_arrayref,
142 stock_type_id
=>$accession_type_cvterm_id,
143 stockprops_values
=>\
%stockprops_values,
144 stockprop_columns_view
=>\
%stock_props,
145 trial_id_list
=>$study_db_id,
146 trial_name_list
=>$study_names,
147 external_ref_id_list
=>$external_reference_id_arrayref,
148 external_ref_source_list
=>$external_reference_source_arrayref,
153 my ($result, $total_count) = $stock_search->search();
155 my $main_production_site_url = SGN
::Context
->new()->get_conf('main_production_site_url');
159 # my @type_of_germplasm_storage_codes = $_->{'type of germplasm storage code'} ? split ',', $_->{'type of germplasm storage code'} : ();
160 my @type_of_germplasm_storage_codes;
161 if($_->{'type of germplasm storage code'}){
162 my @items = split ',', $_->{'type of germplasm storage code'};
164 push @type_of_germplasm_storage_codes ,{
171 donorAccessionNumber
=>$_->{'donor'} ne '' ?
$_->{'donor'} : undef ,
172 donorInstituteCode
=>$_->{'donor institute'} ne '' ?
$_->{'donor institute'} : undef ,
176 foreach(@
{ $_->{synonyms
} }){
183 my @ncbi_taxon_ids = split ',', $_->{'ncbi_taxonomy_id'};
185 foreach (@ncbi_taxon_ids){
187 sourceName
=> 'NCBI',
192 #Get external references and check for search params
194 if (%$reference_result{$_->{stock_id
}}){
195 foreach (@
{%$reference_result{$_->{stock_id
}}}){
197 push @references, $_;
201 my $female_parent_cvterm_id = SGN
::Model
::Cvterm
->get_cvterm_row($self->bcs_schema, 'female_parent', 'stock_relationship')->cvterm_id();
202 my $q = "SELECT value FROM stock_relationship WHERE object_id = ? AND type_id = ?;";
203 my $h = $self->bcs_schema->storage()->dbh()->prepare($q);
204 $h->execute($_->{stock_id
}, $female_parent_cvterm_id);
205 my ($cross_type) = $h->fetchrow_array();
206 if ( ! defined $cross_type) {
207 $cross_type = "unknown";
210 #getting additional info
213 foreach my $prop (keys %additional_stock_props){
215 $additional{$prop} = $_->{$prop};
219 if (defined $_->{'stock_additional_info'} && $_->{'stock_additional_info'} ne '' && %additional) {
220 $additional_info = decode_json
($_->{'stock_additional_info'});
221 $additional_info = {%$additional_info , ("additionalProps" => \
%additional)} ;
222 } elsif (defined $_->{'stock_additional_info'} && $_->{'stock_additional_info'} ne '') {
223 $additional_info = decode_json
($_->{'stock_additional_info'});
224 } elsif (%additional) {
225 $additional_info = {"additionalProps" => \
%additional};
230 accessionNumber
=>$_->{'accession number'},
231 acquisitionDate
=>$_->{'acquisition date'} eq '' ?
undef : $_->{'acquisition date'},
232 additionalInfo
=>$additional_info,
233 biologicalStatusOfAccessionCode
=>$_->{'biological status of accession code'} || 0,
234 biologicalStatusOfAccessionDescription
=>undef,
235 breedingMethodDbId
=>$cross_type,
237 commonCropName
=>$_->{common_name
},
238 countryOfOriginCode
=>$_->{'country of origin'},
239 defaultDisplayName
=>$_->{stock_name
},
240 documentationURL
=>$_->{'PUI'} && $_->{'PUI'} ne '' ?
$_->{'PUI'} : $main_production_site_url . "/stock/$_->{stock_id}/view",
242 externalReferences
=>\
@references,
244 germplasmName
=>$_->{uniquename
},
246 germplasmDbId
=>qq|$_->{stock_id
}|,
247 germplasmPUI
=>$_->{'PUI'} || $main_production_site_url . "/stock/$_->{stock_id}/view",
248 germplasmPreprocessing
=>undef,
249 instituteCode
=>$_->{'institute code'},
250 instituteName
=>$_->{'institute name'},
251 pedigree
=>$_->{pedigree
},
252 seedSource
=>$_->{'seed source'},
253 seedSourceDescription
=>$_->{'seed source'},
254 species
=>$_->{species
},
255 speciesAuthority
=>$_->{speciesAuthority
},
256 storageTypes
=>\
@type_of_germplasm_storage_codes,
257 subtaxa
=>$_->{subtaxa
},
258 subtaxaAuthority
=>$_->{subtaxaAuthority
},
259 synonyms
=> \
@synonyms,
264 my %result = (data
=> \
@data);
265 my $pagination = CXGN
::BrAPI
::Pagination
->pagination_response($total_count,$page_size,$page);
266 return CXGN
::BrAPI
::JSONResponse
->return_success(\
%result, $pagination, \
@data_files, $status, 'Germplasm result constructed');
269 sub germplasm_detail
{
271 my $stock_id = shift;
274 my $status = $self->status;
275 my $page_size = $self->page_size;
276 my $page = $self->page;
278 my $verify_id = $self->bcs_schema->resultset('Stock::Stock')->find({stock_id
=>$stock_id});
280 return CXGN
::BrAPI
::JSONResponse
->return_error($status, 'GermplasmDbId does not exist in the database');
283 my @result = _simple_search
($self,[$stock_id],undef,$c);
284 my $total_count = scalar(@result);
286 print STDERR
"germ detail: " . Dumper
@result ."\n";
288 my $pagination = CXGN
::BrAPI
::Pagination
->pagination_response($total_count,$page_size,$page);
289 return CXGN
::BrAPI
::JSONResponse
->return_success(@result, $pagination, \
@data_files, $status, 'Germplasm detail result constructed');
292 sub germplasm_pedigree
{
295 my $stock_id = $inputs->{stock_id
};
296 my $status = $self->status;
298 my $direct_descendant_ids;
303 push @
$direct_descendant_ids, $stock_id; #excluded in parent retrieval to prevent loops
305 my $stock = $self->bcs_schema->resultset("Stock::Stock")->find({stock_id
=> $stock_id});
309 my $stock_uniquename = $stock->uniquename();
310 my $stock_type = $stock->type_id();
315 ## Get parents relationships
316 my $cvterm_female_parent = SGN
::Model
::Cvterm
->get_cvterm_row($self->bcs_schema, 'female_parent', 'stock_relationship')->cvterm_id();
317 my $cvterm_male_parent = SGN
::Model
::Cvterm
->get_cvterm_row($self->bcs_schema, 'male_parent', 'stock_relationship')->cvterm_id();
319 my $cvterm_rootstock_of = SGN
::Model
::Cvterm
->get_cvterm_row($self->bcs_schema, 'rootstock_of', 'stock_relationship')->cvterm_id();
320 my $cvterm_scion_of = SGN
::Model
::Cvterm
->get_cvterm_row($self->bcs_schema, 'scion_of', 'stock_relationship')->cvterm_id();
322 my $accession_cvterm = SGN
::Model
::Cvterm
->get_cvterm_row($self->bcs_schema, 'accession', 'stock_type')->cvterm_id();
324 #get the stock relationships for the stock
325 my $female_parent_stock_id;
326 my $male_parent_stock_id;
328 my $stock_relationships = $stock->search_related("stock_relationship_objects",undef,{ prefetch
=> ['type','subject'] });
330 my $female_parent_relationship = $stock_relationships->find({type_id
=> { in => [ $cvterm_female_parent, $cvterm_scion_of ]}, subject_id
=> {'not_in' => $direct_descendant_ids}});
331 if ($female_parent_relationship) {
332 $female_parent_stock_id = $female_parent_relationship->subject_id();
333 $mother = $self->bcs_schema->resultset("Stock::Stock")->find({stock_id
=> $female_parent_stock_id})->uniquename();
335 my $male_parent_relationship = $stock_relationships->find({type_id
=> { in => [ $cvterm_male_parent, $cvterm_rootstock_of ]}, subject_id
=> {'not_in' => $direct_descendant_ids}});
336 if ($male_parent_relationship) {
337 $male_parent_stock_id = $male_parent_relationship->subject_id();
338 $father = $self->bcs_schema->resultset("Stock::Stock")->find({stock_id
=> $male_parent_stock_id})->uniquename();
342 my $q = "SELECT DISTINCT female_parent.stock_id, female_parent.uniquename, male_parent.stock_id, male_parent.uniquename, progeny.stock_id, progeny.uniquename, stock_relationship1.value
343 FROM stock_relationship as stock_relationship1
344 INNER JOIN stock AS female_parent ON (stock_relationship1.subject_id = female_parent.stock_id) AND stock_relationship1.type_id = ?
345 INNER JOIN stock AS progeny ON (stock_relationship1.object_id = progeny.stock_id) AND progeny.type_id = ?
346 LEFT JOIN stock_relationship AS stock_relationship2 ON (progeny.stock_id = stock_relationship2.object_id) AND stock_relationship2.type_id = ?
347 LEFT JOIN stock AS male_parent ON (stock_relationship2.subject_id = male_parent.stock_id) ";
351 if($female_parent_stock_id && $male_parent_stock_id){
352 $q = $q . "WHERE female_parent.stock_id = ? AND male_parent.stock_id = ?";
353 $h = $self->bcs_schema()->storage->dbh()->prepare($q);
354 $h->execute($cvterm_female_parent, $accession_cvterm, $cvterm_male_parent, $female_parent_stock_id, $male_parent_stock_id);
356 elsif ($female_parent_stock_id) {
357 $q = $q . "WHERE female_parent.stock_id = ? ORDER BY male_parent.stock_id";
358 $h = $self->bcs_schema()->storage->dbh()->prepare($q);
359 $h->execute($cvterm_female_parent, $accession_cvterm, $cvterm_male_parent, $female_parent_stock_id);
361 elsif ($male_parent_stock_id) {
362 $q = $q . "WHERE male_parent.stock_id = ? ORDER BY female_parent.stock_id";
363 $h = $self->bcs_schema()->storage->dbh()->prepare($q);
364 $h->execute($cvterm_female_parent, $accession_cvterm, $cvterm_male_parent, $male_parent_stock_id);
367 $h = $self->bcs_schema()->storage->dbh()->prepare($q);
368 $h->execute($cvterm_female_parent, $accession_cvterm, $cvterm_male_parent);
374 while (my($female_parent_id, $female_parent_name, $male_parent_id, $male_parent_name, $progeny_id, $progeny_name, $cross_type) = $h->fetchrow_array()){
375 if ($progeny_id ne $stock_id){
377 germplasmDbId
=> qq|$progeny_id|,
378 germplasmName
=> $progeny_name
381 $cross_plan = $cross_type;
385 my @membership_info = ();
386 my $cross_cvterm = SGN
::Model
::Cvterm
->get_cvterm_row($self->bcs_schema, 'cross', 'stock_type')->cvterm_id();
388 if ($stock_type eq $cross_cvterm){
390 my $cross_member_of_type_id = SGN
::Model
::Cvterm
->get_cvterm_row($self->bcs_schema, "cross_member_of", "stock_relationship")->cvterm_id();
391 my $cross_experiment_type_id = SGN
::Model
::Cvterm
->get_cvterm_row($self->bcs_schema, 'cross_experiment', 'experiment_type')->cvterm_id();
392 my $family_name_type_id = SGN
::Model
::Cvterm
->get_cvterm_row($self->bcs_schema, "family_name", "stock_type")->cvterm_id();
393 my $project_year_cvterm_id = SGN
::Model
::Cvterm
->get_cvterm_row($self->bcs_schema, 'project year', 'project_property')->cvterm_id();
395 my $q = "SELECT project.project_id, project.name, project.description, stock.stock_id, stock.uniquename, year.value
396 FROM nd_experiment_stock
397 JOIN nd_experiment ON (nd_experiment_stock.nd_experiment_id = nd_experiment.nd_experiment_id) AND nd_experiment.type_id = ?
398 JOIN nd_experiment_project ON (nd_experiment_project.nd_experiment_id = nd_experiment.nd_experiment_id)
399 JOIN project ON (nd_experiment_project.project_id = project.project_id)
400 LEFT JOIN projectprop AS year ON (project.project_id=year.project_id)
401 LEFT JOIN stock_relationship ON (nd_experiment_stock.stock_id = stock_relationship.subject_id) AND stock_relationship.type_id = ?
402 LEFT JOIN stock ON (stock_relationship.object_id = stock.stock_id) AND stock.type_id = ?
403 WHERE nd_experiment_stock.stock_id = ? AND year.type_id = ?";
405 my $h = $self->bcs_schema->storage->dbh()->prepare($q);
406 $h->execute($cross_experiment_type_id, $cross_member_of_type_id, $family_name_type_id, $stock_id, $project_year_cvterm_id);
409 while (my ($crossing_experiment_id, $crossing_experiment_name, $description, $family_id, $family_name, $year) = $h->fetchrow_array()){
410 push @membership_info, [$crossing_experiment_id, $crossing_experiment_name, $description, $family_id, $family_name, $year]
416 if ($female_parent_stock_id){
418 germplasmDbId
=>$female_parent_stock_id ?
qq|$female_parent_stock_id| : $female_parent_stock_id ,
419 germplasmName
=>$mother,
420 parentType
=>'FEMALE',
423 if ($male_parent_stock_id){
425 germplasmDbId
=>$male_parent_stock_id ?
qq|$male_parent_stock_id| : $male_parent_stock_id,
426 germplasmName
=>$father,
433 crossingProjectDbId
=>$membership_info[0][0],
434 crossingYear
=>$membership_info[0][5],
435 familyCode
=>$membership_info[0][4],
436 germplasmDbId
=>qq|$stock_id|,
437 germplasmName
=>$stock_uniquename,
439 pedigree
=>"$mother/$father",
444 my $pagination = CXGN
::BrAPI
::Pagination
->pagination_response($total_count,1,0);
445 return CXGN
::BrAPI
::JSONResponse
->return_success(\
%result, $pagination, \
@data_files, $status, 'Germplasm pedigree result constructed');
448 sub germplasm_progeny
{
451 my $stock_id = $inputs->{stock_id
};
452 my $status = $self->status;
453 my $mother_cvterm = SGN
::Model
::Cvterm
->get_cvterm_row($self->bcs_schema, 'female_parent', 'stock_relationship')->cvterm_id();
454 my $father_cvterm = SGN
::Model
::Cvterm
->get_cvterm_row($self->bcs_schema, 'male_parent', 'stock_relationship')->cvterm_id();
455 my $accession_cvterm = SGN
::Model
::Cvterm
->get_cvterm_row($self->bcs_schema, 'accession', 'stock_type')->cvterm_id();
457 my $stock = $self->bcs_schema()->resultset("Stock::Stock")->find({
458 'type_id'=> $accession_cvterm,
459 'stock_id'=> $stock_id,
461 my $edges = $self->bcs_schema()->resultset("Stock::StockRelationship")->search(
464 'me.subject_id' => $stock_id,
465 'me.type_id' => $father_cvterm,
466 'object.type_id'=> $accession_cvterm
469 'me.subject_id' => $stock_id,
470 'me.type_id' => $mother_cvterm,
471 'object.type_id'=> $accession_cvterm
476 '+select' => ['object.uniquename'],
477 '+as' => ['progeny_uniquename']
481 while (my $edge = $edges->next) {
482 if ($edge->type_id==$mother_cvterm){
483 push @
{$full_data}, {
484 germplasmDbId
=> "". $edge->object_id,
485 germplasmName
=> $edge->get_column('progeny_uniquename'),
486 parentType
=> "FEMALE"
489 push @
{$full_data}, {
490 germplasmDbId
=> "". $edge->object_id,
491 germplasmName
=> $edge->get_column('progeny_uniquename'),
496 my $total_count = scalar @
{$full_data};
498 if ($total_count > $page_size){
499 $page_size = $total_count;
503 germplasmName
=>$stock->uniquename,
504 germplasmDbId
=>$stock_id,
505 progeny
=>[@
{$full_data}],
508 my $pagination = CXGN
::BrAPI
::Pagination
->pagination_response($total_count,$page_size,$page);
509 return CXGN
::BrAPI
::JSONResponse
->return_success($result, $pagination, \
@data_files, $status, 'Germplasm progeny result constructed');
514 my $stock_id = shift;
516 my $status = $self->status;
517 my $page_size = $self->page_size;
518 my $page = $self->page;
520 my $schema = $self->bcs_schema();
521 my $accession_type_cvterm_id = SGN
::Model
::Cvterm
->get_cvterm_row($self->bcs_schema, 'accession', 'stock_type')->cvterm_id();
523 my $stock_search = CXGN
::Stock
::Search
->new({
524 bcs_schema
=>$self->bcs_schema,
525 people_schema
=>$self->people_schema,
526 phenome_schema
=>$self->phenome_schema,
527 match_type
=>'exactly',
528 stock_id_list
=>[$stock_id],
529 stock_type_id
=>$accession_type_cvterm_id,
530 stockprop_columns_view
=>{'accession number'=>1, 'PUI'=>1, 'seed source'=>1, 'institute code'=>1, 'institute name'=>1, 'biological status of accession code'=>1, 'country of origin'=>1, 'type of germplasm storage code'=>1, 'acquisition date'=>1, 'ncbi_taxonomy_id'=>1},
534 my ($result, $total_count) = $stock_search->search();
539 my $donors = $_->{donors
};
543 donorAccessionNumber
=>$_->{donorAccessionNumber
},
545 instituteCode
=>$_->{donorInstituteCode
},
546 instituteName
=>undef,
548 donorAccessionPui
=>$_->{germplasmPUI
}
552 my @type_of_germplasm_storage_codes;
553 if($_->{'type of germplasm storage code'}){
554 my @items = split ',', $_->{'type of germplasm storage code'};
556 push @type_of_germplasm_storage_codes, $_;
560 if($_->{uniquename
}){
561 push @names, $_->{uniquename
};
564 foreach(@
{ $_->{synonyms
} }){
568 if($_->{stock_name
}){
569 push @names, $_->{stock_name
};
574 push @ids, $_->{stock_id
};
577 push @ids, $_->{'PUI'};
579 if($_->{ncbi_taxonomy_id
}){
580 push @ids, $_->{ncbi_taxonomy_id
};
584 accessionNames
=>\
@names,
586 breedingInstitutes
=>{
587 instituteCode
=>$_->{'institute code'},
588 instituteName
=>$_->{'institute name'},
593 safetyDuplicateInstitutes
=>undef,
594 germplasmDbId
=>qq|$_->{stock_id
}|,
595 accessionNumber
=>$_->{'accession number'},
596 germplasmPUI
=>$_->{'PUI'},
597 ancestralData
=>$_->{pedigree
},
598 commonCropName
=>$_->{common_name
},
599 instituteCode
=>$_->{'institute code'},
600 biologicalStatusOfAccessionCode
=>qq|$_->{'biological status of accession code'}| || "0",
601 countryOfOrigin
=>$_->{'country of origin'},
602 storageTypeCodes
=>\
@type_of_germplasm_storage_codes,
604 species
=>$_->{species
},
605 speciesAuthority
=>$_->{speciesAuthority
},
606 subtaxon
=>$_->{subtaxa
},
607 subtaxonAuthority
=>$_->{subtaxaAuthority
},
609 acquisitionDate
=>$_->{'acquisition date'} eq '' ?
undef : $_->{'acquisition date'}
612 my $total_count = (%result) ?
1 : 0;
615 my $pagination = CXGN
::BrAPI
::Pagination
->pagination_response($total_count,$page_size,$page);
616 return CXGN
::BrAPI
::JSONResponse
->return_success(\
%result, $pagination, \
@data_files, $status, 'Germplasm detail result constructed');
627 return CXGN
::BrAPI
::JSONResponse
->return_error($self->status, sprintf('You must be logged in to add a seedlot!'), 401);
630 my $page_size = $self->page_size;
631 my $page = $self->page;
632 my $status = $self->status;
634 my $schema = $self->bcs_schema;
635 my $dbh = $self->bcs_schema()->storage()->dbh();
636 my $person = CXGN
::People
::Person
->new($dbh, $user_id);
637 my $user_name = $person->get_username;
639 my $main_production_site_url = $c->config->{main_production_site_url
};
643 my $pedigree_parents;
644 my $default_species = $c->config->{preferred_species
};
647 my $accession = $_->{germplasmName
} || undef;
648 my $organism = $_->{species
} || $default_species;
649 my $pedigree = $_->{pedigree
} || undef;
650 push @
$accession_list, $accession;
651 push @
$organism_list, $organism;
652 my $pedigree_array = _process_pedigree_string
($pedigree);
653 if (defined $pedigree_array) {
654 push @
$pedigree_parents, @
$pedigree_array;
659 my $search_accession_list;
660 push @
$search_accession_list, @
$accession_list;
661 if (defined $pedigree_parents) {
662 push @
$search_accession_list, @
$pedigree_parents;
664 my %accessions_missing_hash = _get_nonexisting_accessions
($self, $search_accession_list);
666 # Check if new germplasm already exist
667 my $existing_accessions = '';
668 foreach (@
$accession_list){
669 if (!exists($accessions_missing_hash{$_})){
670 $existing_accessions = $existing_accessions . $_ ."," ;
674 if (length($existing_accessions) >0){
675 return CXGN
::BrAPI
::JSONResponse
->return_error($self->status, sprintf('Existing germplasm in the database: %s', $existing_accessions), 409);
678 # Check if pedigree parents don't exist
679 my $missing_parents = '';
680 foreach (@
$pedigree_parents){
681 if (length($_) > 0 && exists($accessions_missing_hash{$_})){
682 $missing_parents = $missing_parents . $_ ."," ;
686 if (length($missing_parents) >0){
687 return CXGN
::BrAPI
::JSONResponse
->return_error($self->status, sprintf('Missing parent accessions: %s', $missing_parents), 404);
691 my $organism_search = CXGN
::BreedersToolbox
::OrganismFuzzySearch
->new({schema
=> $schema});
692 my $organism_result = $organism_search->get_matches($organism_list, '1');
694 my @allowed_organisms;
695 my $missing_organisms = '';
696 my $found = $organism_result->{found
};
699 push @allowed_organisms, $_->{unique_name
};
701 my %allowed_organisms = map {$_=>1} @allowed_organisms;
703 foreach (@
$organism_list){
704 if (!exists($allowed_organisms{$_})){
705 $missing_organisms = $missing_organisms . $_ . ",";
708 if (length($missing_organisms) >0){
709 return CXGN
::BrAPI
::JSONResponse
->return_error($self->status, sprintf('Organisms were not found on the database: %s', $missing_organisms), 404);
712 my $type_id = SGN
::Model
::Cvterm
->get_cvterm_row($schema, 'accession', 'stock_type')->cvterm_id();
715 my $coderef_bcs = sub {
716 foreach my $params (@
$data){
717 my $species = $params->{species
} || $default_species;
718 my $uniquename = $params->{germplasmName
} || undef;
719 my $name = $params->{defaultDisplayName
} || $uniquename;
720 my $accessionNumber = $params->{accessionNumber
} || undef;
721 my $germplasmPUI = $params->{germplasmPUI
} || undef;
722 my $germplasmSeedSource = $params->{seedSource
} || undef;
723 my $instituteCode = $params->{instituteCode
} || undef;
724 my $instituteName = $params->{instituteName
} || undef;
725 my $biologicalStatusOfAccessionCode = $params->{biologicalStatusOfAccessionCode
} || undef;
726 my $countryOfOriginCode = $params->{countryOfOriginCode
} || undef;
727 my $typeOfGermplasmStorageCode = $params->{storageTypes
}->[0]->{code
} || undef;
728 my $donors = $params->{donors
} || undef;
729 my $acquisitionDate = $params->{acquisitionDate
} || undef;
730 my $externalReferences = $params->{externalReferences
} || undef;
731 #adding breedbase specific info using additionalInfo
732 my $population_name = $params->{collection
} || undef;
733 my $organization_name = $params->{additionalInfo
}->{organizationName
} || undef;
734 my $transgenic = $params->{additionalInfo
}->{transgenic
} || undef;
735 my $notes = $params->{additionalInfo
}->{notes
} || undef;
736 my $state = $params->{additionalInfo
}->{state} || undef;
737 my $variety = $params->{additionalInfo
}->{variety
} || undef;
738 my $locationCode = $params->{additionalInfo
}->{locationCode
} || undef;
739 my $description = $params->{additionalInfo
}->{description
} || undef;
740 my $stock_id = $params->{additionalInfo
}->{stock_id
} || undef;
741 # Get misc additionalInfo and remove specific codes above
742 my %specific_keys = map { $_ => 1 } ("organizationName", "transgenic", "notes", "state", "variety", "locationCode", "description", "stock_id");
743 my $raw_additional_info = $params->{additionalInfo
} || undef;
745 if (defined $raw_additional_info) {
746 foreach my $key (keys %$raw_additional_info) {
747 if (!exists($specific_keys{$key})) {
748 $additional_info{$key} = $raw_additional_info->{$key};
752 my $pedigree = $params->{pedigree
} || undef;
753 my $pedigree_array = _process_pedigree_string
($pedigree);
754 my $mother = defined $pedigree_array && scalar(@
$pedigree_array) > 0 && length(@
$pedigree_array[0]) > 0 ? @
$pedigree_array[0] : undef;
755 my $father = defined $pedigree_array && scalar(@
$pedigree_array) > 1 ? @
$pedigree_array[1] : undef;
756 my $synonyms = $params->{synonyms
} || [];
758 foreach(@
$synonyms) {
760 push @synonymNames, $_->{synonym
};
767 # biologicalStatusOfAccessionDescription
768 # germplasmSeedSourceDescription
772 # germplasmPreprocessing
777 if (exists($allowed_organisms{$species})){
778 my $stock = CXGN
::Stock
::Accession
->new({
780 check_name_exists
=> 0,
781 main_production_site_url
=> $main_production_site_url,
786 uniquename
=> $uniquename,
787 organization_name
=> $organization_name,
788 population_name
=> $population_name,
789 description
=> $description,
790 accessionNumber
=> $accessionNumber,
791 germplasmPUI
=> $germplasmPUI,
792 germplasmSeedSource
=> $germplasmSeedSource,
793 synonyms
=> \
@synonymNames,
794 instituteCode
=> $instituteCode,
795 instituteName
=> $instituteName,
796 biologicalStatusOfAccessionCode
=> $biologicalStatusOfAccessionCode,
797 countryOfOriginCode
=> $countryOfOriginCode,
798 typeOfGermplasmStorageCode
=> $typeOfGermplasmStorageCode,
800 acquisitionDate
=> $acquisitionDate eq '' ?
undef : $acquisitionDate,
801 transgenic
=> $transgenic,
805 locationCode
=> $locationCode,
806 sp_person_id
=> $user_id,
807 user_name
=> $user_name,
808 modification_note
=> 'Bulk load of accession information',
809 mother_accession
=> $mother,
810 father_accession
=> $father,
811 additional_info
=> \
%additional_info
813 my $added_stock_id = $stock->store();
814 push @added_stocks, $added_stock_id;
816 if ($externalReferences && scalar $externalReferences > 0) {
817 my $references = CXGN
::BrAPI
::v2
::ExternalReferences
->new({
818 bcs_schema
=> $self->bcs_schema,
819 table_name
=> 'stock',
820 table_id_key
=> 'stock_id',
821 external_references
=> $externalReferences,
822 id
=> $added_stock_id
824 my $reference_result = $references->store();
831 my $transaction_error;
834 $schema->txn_do($coderef_bcs);
837 $transaction_error = $_;
840 if ($transaction_error){
841 return CXGN
::BrAPI
::JSONResponse
->return_error($self->status, sprintf('There was an error storing germplasm %s', $transaction_error));
844 my $bs = CXGN
::BreederSearch
->new( { dbh
=>$dbh, dbname
=>$c->config->{dbname
}, } );
846 my $refresh = $bs->refresh_matviews($c->config->{dbhost
}, $c->config->{dbname
}, $c->config->{dbuser
}, $c->config->{dbpass
}, 'stockprop', 'concurrent', $c->config->{basepath
}, 0);
848 #retrieve saved items
849 my @data = _simple_search
($self,undef,$accession_list);
850 my $total_count = scalar(@data);
853 my %result = (data
=> \
@data);
854 my $pagination = CXGN
::BrAPI
::Pagination
->pagination_response($total_count,$page_size,$page);
855 return CXGN
::BrAPI
::JSONResponse
->return_success(\
%result, $pagination, \
@data_files, $status, 'Germplasm saved');
861 my $germplasm_id = shift;
866 my $default_species = $c->config->{preferred_species
};
869 return CXGN
::BrAPI
::JSONResponse
->return_error($self->status, sprintf('You must be logged in to add a seedlot!'));
872 my $page_size = $self->page_size;
873 my $page = $self->page;
874 my $status = $self->status;
876 my $schema = $self->bcs_schema;
877 my $dbh = $self->bcs_schema()->storage()->dbh();
878 my $person = CXGN
::People
::Person
->new($dbh, $user_id);
879 my $user_name = $person->get_username;
881 my $stock_exists = $schema->resultset('Stock::Stock')->find({stock_id
=>$germplasm_id});
882 if (!$stock_exists) {
883 return CXGN
::BrAPI
::JSONResponse
->return_error($status, 'GermplasmDbId does not exist in the database',400);
886 my $main_production_site_url = $c->config->{main_production_site_url
};
892 my $organism = $_->{species
} || $default_species;
893 push @
$organism_list, $organism;
896 my $organism_search = CXGN
::BreedersToolbox
::OrganismFuzzySearch
->new({schema
=> $schema});
897 my $organism_result = $organism_search->get_matches($organism_list, '1');
899 my @allowed_organisms;
900 my $missing_organisms = '';
901 my $found = $organism_result->{found
};
904 push @allowed_organisms, $_->{unique_name
};
906 my %allowed_organisms = map {$_=>1} @allowed_organisms;
908 foreach (@
$organism_list){
909 if (!exists($allowed_organisms{$_})){
910 $missing_organisms = $missing_organisms . $_ . ",";
913 if (length($missing_organisms) >0){
914 return CXGN
::BrAPI
::JSONResponse
->return_error($self->status, sprintf('Organisms were not found on the database: %s', $missing_organisms));
917 my $type_id = SGN
::Model
::Cvterm
->get_cvterm_row($schema, 'accession', 'stock_type')->cvterm_id();
919 #sub rutine to save data
921 my $coderef_bcs = sub {
922 foreach my $params (@
$data){
923 my $species = $params->{species
} || $default_species;
924 my $uniquename = $params->{germplasmName
} || undef;
925 my $name = $params->{defaultDisplayName
} || $uniquename;
926 my $accessionNumber = $params->{accessionNumber
} || undef;
927 my $germplasmPUI = $params->{germplasmPUI
} || undef;
928 my $germplasmSeedSource = $params->{seedSource
} || undef;
929 my $instituteCode = $params->{instituteCode
} || undef;
930 my $instituteName = $params->{instituteName
} || undef;
931 my $biologicalStatusOfAccessionCode = $params->{biologicalStatusOfAccessionCode
} || undef;
932 my $countryOfOriginCode = $params->{countryOfOriginCode
} || undef;
933 my $typeOfGermplasmStorageCode = $params->{storageTypes
}->[0]->{code
} || undef;
934 my $donors = $params->{donors
} || undef;
935 my $acquisitionDate = $params->{acquisitionDate
} || undef;
936 my $externalReferences = $params->{externalReferences
} || undef;
937 #adding breedbase specific info using additionalInfo
938 my $population_name = $params->{collection
} || undef;
939 my $organization_name = $params->{additionalInfo
}->{organizationName
} || undef;
940 my $transgenic = $params->{additionalInfo
}->{transgenic
} || undef;
941 my $notes = $params->{additionalInfo
}->{notes
} || undef;
942 my $state = $params->{additionalInfo
}->{state} || undef;
943 my $variety = $params->{additionalInfo
}->{variety
} || undef;
944 my $locationCode = $params->{additionalInfo
}->{locationCode
} || undef;
945 my $description = $params->{additionalInfo
}->{description
} || undef;
946 my $stock_id = $params->{additionalInfo
}->{stock_id
} || undef;
947 # Get misc additionalInfo and remove specific codes above
948 my %specific_keys = map { $_ => 1 } ("organizationName", "transgenic", "notes", "state", "variety", "locationCode", "description", "stock_id");
949 my $raw_additional_info = $params->{additionalInfo
} || undef;
951 if (defined $raw_additional_info) {
952 foreach my $key (keys %$raw_additional_info) {
953 if (!exists($specific_keys{$key})) {
954 $additional_info{$key} = $raw_additional_info->{$key};
958 my $pedigree = $params->{pedigree
} || undef;
959 my $pedigree_array = _process_pedigree_string
($pedigree);
960 my $mother = defined $pedigree_array && scalar(@
$pedigree_array) > 0 ? @
$pedigree_array[0] : undef;
961 my $father = defined $pedigree_array && scalar(@
$pedigree_array) > 1 ? @
$pedigree_array[1] : undef;
962 my $synonyms = $params->{synonyms
} || [];
964 foreach(@
$synonyms) {
966 push @synonymNames, $_->{synonym
};
973 # biologicalStatusOfAccessionDescription
974 # germplasmSeedSourceDescription
979 # germplasmPreprocessing
985 if (exists($allowed_organisms{$species})){
986 my $stock = CXGN
::Stock
::Accession
->new({
988 check_name_exists
=> 0,
989 main_production_site_url
=> $main_production_site_url,
993 stock_id
=> $germplasm_id,
995 uniquename
=> $uniquename,
996 organization_name
=> $organization_name,
997 population_name
=> $population_name,
998 description
=> $description,
999 accessionNumber
=> $accessionNumber,
1000 germplasmPUI
=> $germplasmPUI,
1001 germplasmSeedSource
=> $germplasmSeedSource,
1002 synonyms
=> \
@synonymNames,
1003 instituteCode
=> $instituteCode,
1004 instituteName
=> $instituteName,
1005 biologicalStatusOfAccessionCode
=> $biologicalStatusOfAccessionCode,
1006 countryOfOriginCode
=> $countryOfOriginCode,
1007 typeOfGermplasmStorageCode
=> $typeOfGermplasmStorageCode,
1009 acquisitionDate
=> $acquisitionDate eq '' ?
undef : $acquisitionDate,
1010 transgenic
=> $transgenic,
1013 variety
=> $variety,
1014 locationCode
=> $locationCode,
1015 sp_person_id
=> $user_id,
1016 user_name
=> $user_name,
1017 modification_note
=> 'Bulk load of accession information',
1018 mother_accession
=> $mother,
1019 father_accession
=> $father,
1020 additional_info
=> \
%additional_info
1022 my $added_stock_id = $stock->store();
1024 my $previous_name = $stock_exists->uniquename();
1026 if($previous_name ne $uniquename){
1027 $stock_exists->uniquename($uniquename);
1028 $stock_exists->update();
1031 push @added_stocks, $added_stock_id;
1033 my $references = CXGN
::BrAPI
::v2
::ExternalReferences
->new({
1034 bcs_schema
=> $self->bcs_schema,
1035 table_name
=> 'stock',
1036 table_id_key
=> 'stock_id',
1037 external_references
=> $externalReferences ?
$externalReferences : [],
1040 my $reference_result = $references->store();
1046 my $transaction_error;
1049 $schema->txn_do($coderef_bcs);
1053 $transaction_error = $_;
1056 if ($transaction_error){
1057 return CXGN
::BrAPI
::JSONResponse
->return_error($self->status, sprintf('There was an error storing germplasm %s', $transaction_error));
1061 my $bs = CXGN
::BreederSearch
->new( { dbh
=>$dbh, dbname
=>$c->config->{dbname
}, } );
1062 my $refresh = $bs->refresh_matviews($c->config->{dbhost
}, $c->config->{dbname
}, $c->config->{dbuser
}, $c->config->{dbpass
}, 'stockprop', 'concurrent', $c->config->{basepath
}, 0);
1064 #retrieve updated item
1065 my @result = _simple_search
($self,[$germplasm_id]);
1067 my $total_count = scalar(@result);
1068 my $pagination = CXGN
::BrAPI
::Pagination
->pagination_response($total_count,$page_size,$page);
1069 return CXGN
::BrAPI
::JSONResponse
->return_success(@result, $pagination, \
@data_files, $status, 'Germplasm updated');
1072 sub _simple_search
{
1074 my $germplasm_ids_arrayref = shift;
1075 my $germplasm_names_arrayref = shift;
1078 my $accession_type_cvterm_id = SGN
::Model
::Cvterm
->get_cvterm_row($self->bcs_schema, 'accession', 'stock_type')->cvterm_id();
1081 'accession number'=>1,
1082 'acquisition date'=>1,
1083 'biological status of accession code'=>1,
1084 'country of origin'=>1,
1086 'donor institute'=>1,
1087 'institute code'=>1,
1088 'institute name'=>1,
1089 'ncbi_taxonomy_id'=>1,
1092 'stock_additional_info'=>1,
1093 'type of germplasm storage code'=>1 );
1095 ## Additional stock props for additional info.
1096 my %additional_stock_props;
1097 my @editable_stock_props = SGN
::Context
->new()->get_conf('editable_stock_props') ?
split ',', SGN
::Context
->new()->get_conf('editable_stock_props'): undef;
1098 my %editable_stock_props = map { $_=>1 } @editable_stock_props;
1100 foreach (keys %editable_stock_props){
1101 if(!%stock_props{$_}){
1102 $additional_stock_props{$_} = 1;
1106 if (%additional_stock_props){
1107 %stock_props = (%stock_props, %additional_stock_props);
1110 ##Getting references
1111 my $references = CXGN
::BrAPI
::v2
::ExternalReferences
->new({
1112 bcs_schema
=> $self->bcs_schema,
1113 table_name
=> 'stock',
1114 table_id_key
=> 'stock_id',
1115 id
=> $germplasm_ids_arrayref
1117 my $reference_result = $references->search();
1119 my $stock_search = CXGN
::Stock
::Search
->new({
1120 bcs_schema
=>$self->bcs_schema,
1121 people_schema
=>$self->people_schema,
1122 phenome_schema
=>$self->phenome_schema,
1123 match_type
=>'exactly',
1124 uniquename_list
=>$germplasm_names_arrayref,
1125 stock_id_list
=>$germplasm_ids_arrayref,
1126 stock_type_id
=>$accession_type_cvterm_id,
1127 stockprop_columns_view
=>\
%stock_props,
1130 my ($result, $total_count) = $stock_search->search();
1132 my $main_production_site_url = SGN
::Context
->new()->get_conf('main_production_site_url');
1136 # my @type_of_germplasm_storage_codes = $_->{'type of germplasm storage code'} ? split ',', $_->{'type of germplasm storage code'} : ();
1137 my @type_of_germplasm_storage_codes;
1138 if($_->{'type of germplasm storage code'}){
1139 my @items = split ',', $_->{'type of germplasm storage code'};
1141 push @type_of_germplasm_storage_codes ,{
1148 donorAccessionNumber
=>$_->{donor
} ne '' ?
$_->{'donor'} : undef ,
1149 donorInstituteCode
=>$_->{'donor institute'} ne '' ?
$_->{'donor institute'} : undef ,
1152 if($_->{synonyms
} && scalar @
{ $_->{synonyms
} } > 0){
1153 foreach(@
{ $_->{synonyms
} }){
1154 print STDERR
"pushing synonym: " . Dumper
$_;
1161 my @ncbi_taxon_ids = split ',', $_->{'ncbi_taxonomy_id'};
1163 foreach (@ncbi_taxon_ids){
1165 sourceName
=> 'NCBI',
1171 if (%$reference_result{$_->{stock_id
}}){
1172 foreach (@
{%$reference_result{$_->{stock_id
}}}){
1173 push @references, $_;
1177 my $female_parent_cvterm_id = SGN
::Model
::Cvterm
->get_cvterm_row($self->bcs_schema, 'female_parent', 'stock_relationship')->cvterm_id();
1178 my $q = "SELECT value FROM stock_relationship WHERE object_id = ? AND type_id = ?;";
1179 my $h = $self->bcs_schema->storage()->dbh()->prepare($q);
1180 $h->execute($_->{stock_id
}, $female_parent_cvterm_id);
1181 my ($cross_type) = $h->fetchrow_array();
1182 if ( ! defined $cross_type) {
1183 $cross_type = "unknown";
1186 my $additional_info;
1188 foreach my $prop (keys %additional_stock_props){
1190 $additional{$prop} = $_->{$prop};
1194 if (defined $_->{'stock_additional_info'} && $_->{'stock_additional_info'} ne '' && %additional) {
1195 $additional_info = decode_json
($_->{'stock_additional_info'});
1196 $additional_info = {%$additional_info , ("additionalProps" => \
%additional)} ;
1197 } elsif (defined $_->{'stock_additional_info'} && $_->{'stock_additional_info'} ne '') {
1198 $additional_info = decode_json
($_->{'stock_additional_info'});
1199 } elsif (%additional) {
1200 $additional_info = {"additionalProps" => \
%additional};
1204 accessionNumber
=>$_->{'accession number'},
1205 acquisitionDate
=>$_->{'acquisition date'} eq '' ?
undef : $_->{'acquisition date'},
1206 additionalInfo
=> $additional_info,
1207 biologicalStatusOfAccessionCode
=>$_->{'biological status of accession code'} || 0,
1208 biologicalStatusOfAccessionDescription
=>undef,
1209 breedingMethodDbId
=>$cross_type,
1210 collection
=>$_->{population_name
},
1211 commonCropName
=>$_->{common_name
},
1212 countryOfOriginCode
=>$_->{'country of origin'},
1213 defaultDisplayName
=>$_->{stock_name
},
1214 documentationURL
=>$_->{'PUI'} && $_->{'PUI'} ne '' ?
$_->{'PUI'} : $main_production_site_url . "/stock/$_->{stock_id}/view",
1216 externalReferences
=>\
@references,
1218 germplasmName
=>$_->{uniquename
},
1219 germplasmOrigin
=>[],
1220 germplasmDbId
=>qq|$_->{stock_id
}|,
1221 germplasmPUI
=>$_->{'PUI'} || $main_production_site_url . "/stock/$_->{stock_id}/view",
1222 germplasmPreprocessing
=>undef,
1223 instituteCode
=>$_->{'institute code'},
1224 instituteName
=>$_->{'institute name'},
1225 pedigree
=>$_->{pedigree
},
1226 seedSource
=>$_->{'seed source'},
1227 seedSourceDescription
=>$_->{'seed source'},
1228 species
=>$_->{species
},
1229 speciesAuthority
=>$_->{speciesAuthority
},
1230 storageTypes
=>\
@type_of_germplasm_storage_codes,
1231 subtaxa
=>$_->{subtaxa
},
1232 subtaxaAuthority
=>$_->{subtaxaAuthority
},
1233 synonyms
=> @synonyms ? \
@synonyms : [],
1240 sub _process_pedigree_string
{
1241 my $pedigree = shift;
1243 my $pedigree_parents;
1245 if (defined $pedigree) {
1246 my @pedigree_array = split('/', $pedigree);
1247 if (scalar(@pedigree_array) > 0){
1248 my $mother = @pedigree_array[0];
1249 push @
$pedigree_parents, $mother;
1250 if (scalar(@pedigree_array) > 1){
1251 my $father = @pedigree_array[1];
1252 push @
$pedigree_parents, $father;
1257 return $pedigree_parents;
1260 sub _get_nonexisting_accessions
{
1262 my $accession_list = shift;
1264 my $schema = $self->bcs_schema;
1266 my $validator = CXGN
::List
::Validate
->new();
1267 my @absent_accessions = @
{$validator->validate($schema, 'accessions', $accession_list)->{'missing'}};
1268 my %accessions_missing_hash = map { $_ => 1 } @absent_accessions;
1270 return %accessions_missing_hash;