Merge pull request #5205 from solgenomics/topic/generic_trial_upload
[sgn.git] / lib / SGN / Controller / AJAX / Onto.pm
blob2729f21e8b7c59017da3444bcf636c7f309ef9d8
1 =head1 NAME
3 SGN::Controller::AJAX::Onto - a REST controller class to provide the
4 backend for the SGN ontology browser
6 =head1 DESCRIPTION
8 Essentially provides four services: roots, children, parents, and
9 cache, that the SGN ontology browser relies on. Output is JSON, as a
10 list of hashes, that has the following keys: accession, has_children,
11 cvterm_name, cvterm_id, and for some functions, parent.
13 The ontologies that should be displayed must be configured in the configuration file (sgn.conf or sgn_local.conf for SGN). Insert a line of the following format into the conf file:
15 C<onto_root_namespaces GO (Gene Ontology), PO (Plant Ontology), SO (Sequence Ontology), PATO (Phenotype and Trait Ontology), SP (Solanaceae Ontology)>
17 where onto_root_namespaces is the conf key, "GO" the two letter code of the ontology (as it appears in the db database table), and in parenthesis is the human readable name of the ontology.
19 =head1 AUTHOR
21 Lukas Mueller <lam87@cornell.edu>
23 =head1 PUBLIC ACTIONS
25 =cut
27 package SGN::Controller::AJAX::Onto;
29 use Moose;
30 use SGN::Model::Cvterm;
31 use CXGN::Chado::Cvterm;
32 use CXGN::Onto;
33 use Data::Dumper;
34 use JSON;
36 use namespace::autoclean;
38 BEGIN { extends 'Catalyst::Controller::REST' }
40 __PACKAGE__->config(
41 default => 'application/json',
42 stash_key => 'rest',
43 map => { 'application/json' => 'JSON' },
46 =head2 compose_trait
48 Creates a new term in the designated composed trait cv and links it to component terms through cvterm_relationship
50 =cut
52 sub compose_trait: Path('/ajax/onto/store_composed_term') Args(0) {
54 my $self = shift;
55 my $c = shift;
57 #my @ids = $c->req->param("ids[]");
58 #print STDERR "Ids array for composing in AJAX Onto = @ids\n";
60 my $new_trait_names = decode_json $c->req->param("new_trait_names");
61 #print STDERR Dumper $new_trait_names;
62 my $new_terms;
63 eval {
64 my $onto = CXGN::Onto->new( { schema => $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado') } );
65 $new_terms = $onto->store_composed_term($new_trait_names);
67 if ($@) {
68 $c->stash->{rest} = { error => "An error occurred saving the new trait details: $@" };
70 else {
71 my $message = '';
72 my @names;
73 foreach (@$new_terms){
74 $message .= 'Saved new trait <a href="/cvterm/'.$_->[0].'/view">'.$_->[1].'</a><br>';
75 push @names, $_->[1];
77 $c->stash->{rest} = { success => $message,
78 names => \@names };
83 =head2 store_ontology_identifier
85 Creates a ontology identifier by adding an entry in the DB, cv, and cvterm tables.
87 =cut
89 sub store_ontology_identifier: Path('/ajax/onto/store_ontology_identifier') Args(0) {
90 my $self = shift;
91 my $c = shift;
92 #print STDERR Dumper $c->req->params();
94 my $user_id;
95 my $user_name;
96 my $user_role;
97 my $session_id = $c->req->param("sgn_session_id");
99 if ($session_id){
100 my $dbh = $c->dbc->dbh;
101 my @user_info = CXGN::Login->new($dbh)->query_from_cookie($session_id);
102 if (!$user_info[0]){
103 $c->stash->{rest} = {error=>'You must be logged in to create ontology!'};
104 $c->detach();
106 $user_id = $user_info[0];
107 $user_role = $user_info[1];
108 my $p = CXGN::People::Person->new($dbh, $user_id);
109 $user_name = $p->get_username;
110 } else{
111 if (!$c->user){
112 $c->stash->{rest} = {error=>'You must be logged in to create ontology!'};
113 $c->detach();
115 $user_id = $c->user()->get_object()->get_sp_person_id();
116 $user_name = $c->user()->get_object()->get_username();
117 $user_role = $c->user->get_object->get_user_type();
120 if ($user_role ne 'curator') {
121 $c->stash->{rest} = {error => "You have insufficient privileges to add ontology." };
122 $c->detach();
125 my $ontology_name = $c->req->param("ontology_name");
126 my $ontology_description = $c->req->param("ontology_description");
127 my $ontology_identifier = $c->req->param("ontology_identifier");
128 my $ontology_type = $c->req->param("ontology_type");
130 my %finish;
131 if ($c->config->{allow_observation_variable_submission_interface}) {
132 my $onto = CXGN::Onto->new( { schema => $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado') } );
133 my $return = $onto->store_ontology_identifier(
134 $ontology_name,
135 $ontology_description,
136 $ontology_identifier,
137 $ontology_type
139 if ($return->{error}) {
140 $finish{error} = $return->{error};
141 } elsif ($return->{success}) {
142 $finish{success} = 'Saved new ontology <a href="/cvterm/'.$return->{new_term}->[0].'/view">'.$return->{new_term}->[1].'</a><br>';
143 } else {
144 $finish{error} = 'Something went wrong!';
146 } else {
147 $finish{error} = 'On this database it is not allowed for users to add their own ontology! Please contact us!';
149 $c->stash->{rest} = \%finish;
152 =head2 store_trait_method_scale_observation_variable
154 Creates a new term in the designated observation variable cv and links it to component trait, method, and scale terms through cvterm_relationship. will create trait, method, and scale terms in their own ontologies if they need to be.
156 =cut
158 sub store_trait_method_scale_observation_variable: Path('/ajax/onto/store_trait_method_scale_observation_variable') Args(0) {
159 my $self = shift;
160 my $c = shift;
161 #print STDERR Dumper $c->req->params();
163 my $user_id;
164 my $user_name;
165 my $user_role;
166 my $session_id = $c->req->param("sgn_session_id");
168 if ($session_id){
169 my $dbh = $c->dbc->dbh;
170 my @user_info = CXGN::Login->new($dbh)->query_from_cookie($session_id);
171 if (!$user_info[0]){
172 $c->stash->{rest} = {error=>'You must be logged in to create observation variables!'};
173 $c->detach();
175 $user_id = $user_info[0];
176 $user_role = $user_info[1];
177 my $p = CXGN::People::Person->new($dbh, $user_id);
178 $user_name = $p->get_username;
179 } else{
180 if (!$c->user){
181 $c->stash->{rest} = {error=>'You must be logged in to create observation variables!'};
182 $c->detach();
184 $user_id = $c->user()->get_object()->get_sp_person_id();
185 $user_name = $c->user()->get_object()->get_username();
186 $user_role = $c->user->get_object->get_user_type();
189 if ($user_role ne 'curator') {
190 $c->stash->{rest} = {error => "You have insufficient privileges to add observation variables." };
191 $c->detach();
194 my $selected_observation_variable_db_id = $c->req->param("selected_observation_variable_db_id");
195 my $new_observation_variable_name = $c->req->param("new_observation_variable_name");
196 my $new_observation_variable_definition = $c->req->param("new_observation_variable_definition");
197 my $selected_trait_db_id = $c->req->param("selected_trait_db_id");
198 my $selected_trait_cvterm_id = $c->req->param("selected_trait_cvterm_id");
199 my $new_trait_name = $c->req->param("new_trait_name");
200 my $new_trait_definition = $c->req->param("new_trait_definition");
201 my $selected_method_db_id = $c->req->param("selected_method_db_id");
202 my $selected_method_cvterm_id = $c->req->param("selected_method_cvterm_id");
203 my $new_method_name = $c->req->param("new_method_name");
204 my $new_method_definition = $c->req->param("new_method_definition");
205 my $selected_scale_db_id = $c->req->param("selected_scale_db_id");
206 my $selected_scale_cvterm_id = $c->req->param("selected_scale_cvterm_id");
207 my $new_scale_name = $c->req->param("new_scale_name");
208 my $new_scale_definition = $c->req->param("new_scale_definition");
209 my $new_scale_format = $c->req->param("new_scale_format");
210 my $new_scale_minumum = $c->req->param("new_scale_minimum");
211 my $new_scale_maximum = $c->req->param("new_scale_maximum");
212 my $new_scale_default = $c->req->param("new_scale_default");
213 my $new_scale_categories = $c->req->param("new_scale_categories");
215 my %finish;
216 if ($c->config->{allow_observation_variable_submission_interface}) {
217 my $onto = CXGN::Onto->new( { schema => $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado') } );
218 my $return = $onto->store_observation_variable_trait_method_scale(
219 $selected_observation_variable_db_id,
220 $new_observation_variable_name,
221 $new_observation_variable_definition,
222 $selected_trait_db_id,
223 $selected_trait_cvterm_id,
224 $new_trait_name,
225 $new_trait_definition,
226 $selected_method_db_id,
227 $selected_method_cvterm_id,
228 $new_method_name,
229 $new_method_definition,
230 $selected_scale_db_id,
231 $selected_scale_cvterm_id,
232 $new_scale_name,
233 $new_scale_definition,
234 $new_scale_format,
235 $new_scale_minumum,
236 $new_scale_maximum,
237 $new_scale_default,
238 $new_scale_categories
240 if ($return->{error}) {
241 $finish{error} = $return->{error};
242 } elsif ($return->{success}) {
243 $finish{success} = 'Saved new observation variable <a href="/cvterm/'.$return->{new_term}->[0].'/view">'.$return->{new_term}->[1].'</a><br>';
244 } else {
245 $finish{error} = 'Something went wrong!';
247 } else {
248 $finish{error} = 'On this database it is not allowed for users to add their own observation variables! Please contact us!';
250 $c->stash->{rest} = \%finish;
253 =head2 get_trait_from_exact_components
255 searches for and returns (if found) a composed trait that contains the exact components supplied
257 =cut
259 sub get_trait_from_exact_components: Path('/ajax/onto/get_trait_from_exact_components') Args(0) {
261 my $self = shift;
262 my $c = shift;
263 my @component_ids = $c->req->param("ids[]");
264 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
266 my $trait_id = SGN::Model::Cvterm->get_trait_from_exact_components($schema, \@component_ids);
267 if (!$trait_id) {
268 $c->stash->{rest} = { error => "No exact matches found."};
270 else {
271 $c->stash->{rest} = { trait_id => $trait_id };
275 =head2 get_trait_from_component_categories
277 searches for and returns traits that contain one of the ids from each id category supplied
279 =cut
281 sub get_traits_from_component_categories: Path('/ajax/onto/get_traits_from_component_categories') Args(0) {
283 my $self = shift;
284 my $c = shift;
285 my @allowed_composed_cvs = split ',', $c->config->{composable_cvs};
286 my $composable_cvterm_delimiter = $c->config->{composable_cvterm_delimiter};
287 my $composable_cvterm_format = $c->config->{composable_cvterm_format};
288 my @object_ids = $c->req->param("object_ids[]");
289 my @attribute_ids = $c->req->param("attribute_ids[]");
290 my @method_ids = $c->req->param("method_ids[]");
291 my @unit_ids = $c->req->param("unit_ids[]");
292 my @trait_ids = $c->req->param("trait_ids[]");
293 my @tod_ids = $c->req->param("tod_ids[]");
294 my @toy_ids = $c->req->param("toy_ids[]");
295 my @gen_ids = $c->req->param("gen_ids[]");
296 my @evt_ids = $c->req->param("evt_ids[]");
298 print STDERR "Obj ids are @object_ids\n Attr ids are @attribute_ids\n Method ids are @method_ids\n unit ids are @unit_ids\n trait ids are @trait_ids\n tod ids are @tod_ids\n toy ids are @toy_ids\n gen ids are @gen_ids\n evt ids are @evt_ids\n";
299 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
301 my $traits = SGN::Model::Cvterm->get_traits_from_component_categories($schema, \@allowed_composed_cvs, $composable_cvterm_delimiter, $composable_cvterm_format, {
302 object => \@object_ids,
303 attribute => \@attribute_ids,
304 method => \@method_ids,
305 unit => \@unit_ids,
306 trait => \@trait_ids,
307 tod => \@tod_ids,
308 toy => \@toy_ids,
309 gen => \@gen_ids,
310 evt => \@evt_ids,
313 if (!$traits) {
314 $c->stash->{rest} = { error => "No matches found."};
316 else {
317 $c->stash->{rest} = {
318 existing_traits => $traits->{existing_traits},
319 new_traits => $traits->{new_traits}
325 =head2 children
327 Public Path: /<ns>/children
329 L<Catalyst::Action::REST> action.
331 Provides a list of child terms, each child term being a hashref (or
332 equivalent) with keys accession, cvterm_name, cvterm_id, has_children,
333 and relationship.
335 =cut
337 sub children : Local : ActionClass('REST') { }
339 sub children_GET {
340 my ( $self, $c ) = @_;
341 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
343 my ($db_name, $accession) = split ":", $c->request->param('node');
345 my $db = $schema->resultset('General::Db')->search({ name => uc($db_name) })->first();
346 my $dbxref = $db->find_related('dbxrefs', { accession => $accession });
348 my $cvterm = $dbxref->cvterm;
350 my $cvrel_rs = $cvterm->children(); # returns a result set
352 my @response_list = ();
353 while (my $cvrel_row = $cvrel_rs->next()) {
354 my $relationship_node = $cvrel_row->type();
355 my $child_node = $cvrel_row->subject();
357 #only report back children of the same cv namespace
358 # if ($child_node->cv_id() != $cvterm->cv_id()) {
359 # next();
362 my $responsehash = $self->flatten_node($child_node, $relationship_node);
363 push @response_list, $responsehash;
365 @response_list = sort { lc $a->{cvterm_name} cmp lc $b->{cvterm_name} } @response_list;
366 $c->stash->{rest} = \@response_list;
370 =head2 parents
372 Public Path: /<ns>/parents
374 L<Catalyst::Action::REST> action.
376 Returns a list of hashes with parents information in json, a list of
377 hashrefs with the keys: accession, relationship, has_children, cvterm_id
378 and cvterm_name.
380 =cut
382 sub parents : Local : ActionClass('REST') { }
384 sub parents_GET {
385 my ($self, $c) = @_;
387 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
389 my ($db_name, $accession) = split ":", $c->request->param('node');
390 my $dbxref;
391 my %response;
392 my $db = $schema->resultset('General::Db')->search(
393 { 'upper(me.name)' => uc($db_name),
394 'cvterm.name' => {'!=', undef },
395 'dbxrefs.accession' => $accession
397 {join => { 'dbxrefs' => 'cvterm' }
400 my $db_id;
401 if (!$db || !$accession) {
402 #not sure we need here to send an error key, since cache is usually called after parents (? )
403 $response{error} = "Did not pass a legal ontology term ID! ( $db_name : $accession)";
404 $c->stash->{rest} = \%response;
405 return;
406 } elsif ( $db->count > 1 ) {
407 $response{error} = "Found more than one db row for db.name $db_name : check your database";
408 $c->stash->{rest} = \%response;
409 return;
411 $db_id=$db->next->db_id;
412 my $sql = 'IS NOT NULL ';
413 my $dbxref_rs = $schema->resultset('General::Dbxref')->search(
414 { 'me.accession' => $accession,
415 'db_id' => $db_id,
416 'cvterm.cvterm_id' => \$sql
419 { join => 'cvterm' },
422 if ($dbxref_rs->count >1 ) {
423 while (my $d = $dbxref_rs->next() ) { print STDERR "DBXREF = " . $d->dbxref_id . " CVTERM = " . $d->cvterm->cvterm_id . "NAME = " . $d->cvterm->name . " \n\n" ; }
424 $response{error} = "Found more than one dbxref row for accession $accession : check your database";
425 $c->stash->{rest} = \%response;
426 return;
427 } else {
428 $dbxref = $dbxref_rs->next();
430 #print STDERR "***Onto.pm: My db_name = $db_name , accession = $accession, db = " . $db_name . "db id = " . $db_id . " cvterm = " . $dbxref->cvterm->cvterm_id . "\n\n";
431 if (!$dbxref) {
432 $response{error} = "Could not find term $db_name : $accession in the database! Check your input and try again";
433 $c->stash->{rest} = \%response;
434 return;
436 my $cvterm = $dbxref->cvterm;
438 my @response_list = ();
439 if ($cvterm) {
440 my $parents_rs = $cvterm->recursive_parents(); # returns a result set
441 while (my $parent = $parents_rs->next()) {
442 #only report back children of the same cv namespace
443 if ($parent->cv_id() != $cvterm->cv_id()) {
444 next();
446 my $responsehash = $self->flatten_node($parent, undef);
447 push @response_list, $responsehash;
449 } else {
450 $response{error} = "Could not find term $db_name : $accession in the database! Check your input and try again. THIS MAY BE AN INTERNAL DATABASE PROBLEM! Please contact sgn-feedback\@sgn.cornell.edu for help.";
451 $c->stash->{rest} = \%response;
452 return;
454 $c->stash->{rest} = \@response_list;
457 =head2 menu
459 Usage:
460 Desc:
461 Ret:
462 Args:
463 Side Effects:
464 Example:
466 =cut
468 sub menu : Local : ActionClass('REST') { }
470 sub menu_GET {
471 my $self = shift;
472 my $c = shift;
474 my $menudata = $c->config->{onto_root_namespaces};
476 print STDERR "MENUDATA: $menudata\n";
477 my @menuitems = split ",", $menudata;
479 my $menu = '<select name="cv_select">';
481 foreach my $mi (@menuitems) {
482 print STDERR "MENU ITEM: $mi\n";
483 if ($mi =~ /\s*(\w+)?\s*(.*)$/) {
484 my $value = $1;
485 my $name = $2;
487 $menu .= qq { <option value="$value">$value $name</option>\n };
491 $menu .= "</select>\n";
492 $c->stash->{rest} = [ $menu ];
499 =head2 roots
501 Public Path: /<ns>/roots
503 L<Catalyst::Action::REST> action.
505 Provides the default roots for drawing the ontology browser
507 Query/Body Params:
509 nodes: optional, a string with namespace definitions, separated by white
510 space (for example, "PO SP SO"). If not provided, will This overrides the standard
511 namespaces provided when called without arguments.
513 =cut
515 sub roots : Local : ActionClass('REST') { }
517 sub roots_GET {
518 my $self = shift;
519 my $c = shift;
520 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
522 my $namespace = $c->request->param('nodes');
523 my @namespaces = ();
524 my @response_nodes = ();
525 #my $empty_cvterm = CXGN::Chado::Cvterm->new($c->dbc()->dbh());
526 if (!$namespace) { # should namespaces be db names ? (SO, GO,PO, SP, PATO)
527 @namespaces = (
528 'GO',
529 'PO',
530 'SP',
531 'SO',
532 'PATO',
533 'CO',
536 else {
537 @namespaces = split /\s+/, $namespace; #split on whitespace
539 my @roots = ();
540 my $is_rel = 0;
541 foreach my $ns (@namespaces) {
542 $is_rel = 1 if $ns eq 'OBO_REL';
543 my $q = "SELECT cvterm.cvterm_id FROM cvterm
544 JOIN dbxref USING(dbxref_id) JOIN db USING(db_id)
545 LEFT JOIN cvterm_relationship ON (cvterm.cvterm_id=cvterm_relationship.subject_id)
546 WHERE cvterm_relationship.subject_id IS NULL AND is_obsolete= ? AND is_relationshiptype = ? AND db.name= ? ";
547 my $sth = $schema->storage->dbh->prepare($q);
548 $sth->execute(0,$is_rel,$ns);
549 while (my ($cvterm_id) = $sth->fetchrow_array() ) {
550 my $root = $schema->resultset("Cv::Cvterm")->find( { cvterm_id => $cvterm_id } );
551 push @roots, $root;
554 my @response_list = ();
556 foreach my $r (@roots) {
557 my $hashref = $self->flatten_node($r, undef);
558 push @response_list, $hashref;
560 $c->stash->{rest}= \@response_list;
564 =head2 match
566 Public Path: /<ns>/match
568 L<Catalyst::Action::REST> action.
570 Query/Body Params:
572 db_name
573 term_name
575 =cut
577 sub match : Local : ActionClass('REST') { }
579 sub match_GET {
580 my $self = shift;
581 my $c = shift;
582 my $db_name = $c->request->param("db_name");
583 my $term_name = $c->request->param("term_name");
585 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
586 my $query = "SELECT distinct cvterm.cvterm_id as cvterm_id , cv.name as cv_name , cvterm.name as cvterm_name , db.name || ':' || dbxref.accession as accession
587 FROM db
588 JOIN dbxref USING (db_id ) JOIN cvterm USING (dbxref_id)
589 JOIN cv USING (cv_id )
590 LEFT JOIN cvtermsynonym USING (cvterm_id )
591 WHERE db.name = ? AND (cvterm.name ilike ? OR cvtermsynonym.synonym ilike ? OR cvterm.definition ilike ?) AND cvterm.is_obsolete = 0
592 GROUP BY cvterm.cvterm_id,cv.name, cvterm.name, dbxref.accession, db.name ";
593 my $sth= $schema->storage->dbh->prepare($query);
594 $sth->execute($db_name, "\%$term_name\%", "\%$term_name\%", "\%$term_name\%");
595 my @response_list;
596 while (my $hashref = $sth->fetchrow_hashref ) {
597 push @response_list, $hashref;
599 $c->stash->{rest} = \@response_list;
602 =head2 cache
604 Public Path: /<ns>/cache
606 L<Catalyst::Action::REST> action.
608 Provides a list of parents and their direct children in a denormalized
609 list. The parameter node is used to determine all the children that
610 need to be cached for the parentage view to render fast (without
611 having to call the children ajax function).
613 =cut
615 sub cache : Local : ActionClass('REST') { }
617 sub cache_GET {
618 my $self =shift;
619 my $c = shift;
621 $self->{duplicates} = {};
622 $self->{cache_list} = [];
624 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
625 my %response;
626 my ($db_name, $accession) = split ":", $c->request->param('node');
627 if (!$db_name || !$accession) {
628 $response{error} = "Looks like you passed an illegal ontology term ID ! ($db_name : $accession) Please try again.";
629 $c->stash->{rest} = \%response;
630 return;
633 ###############
634 my $db = $schema->resultset('General::Db')->search(
635 { 'upper(me.name)' => uc($db_name),
636 'cvterm.name' => {'!=', undef },
637 'dbxrefs.accession' => $accession
639 {join => { 'dbxrefs' => 'cvterm' }
642 my ($db_id, $dbxref);
643 $db_id=$db->next->db_id;
644 my $sql = 'IS NOT NULL ';
645 my $dbxref_rs = $schema->resultset('General::Dbxref')->search(
646 { 'me.accession' => $accession,
647 'db_id' => $db_id,
648 'cvterm.cvterm_id' => \$sql
651 { join => 'cvterm' },
654 if ($dbxref_rs->count >1 ) {
655 while (my $d = $dbxref_rs->next() ) { print STDERR "DBXREF = " . $d->dbxref_id . " CVTERM = " . $d->cvterm->cvterm_id . "NAME = " . $d->cvterm->name . " \n\n" ; }
656 $response{error} = "Found more than one dbxref row for accession $accession : check your database";
657 $c->stash->{rest} = \%response;
658 return;
659 } else {
660 $dbxref = $dbxref_rs->next();
662 if (!$dbxref) {
663 $response{error} = "Did not find ontology term $db_name : $accession in the database. Please try again. If you think this term should exist please contact sgn-feedback\@sgn.cornell.edu";
664 $c->stash->{rest} = \%response;
665 return;
667 ######################
668 my $cvterm = $dbxref->cvterm;
669 if (!$cvterm) {
670 $response{error} = "Did not find ontology term $db_name : $accession in the database. This may be an internal database issue. Please contact sgn-feedback\@sgn.cornell.edu and we will fix this error ASAP";
671 $c->stash->{rest} = \%response;
672 return;
674 my $parents_rs = $cvterm->recursive_parents(); # returns a result set
675 if (!$parents_rs->next) {
676 $response{error} = "did not find recursive parents for cvterm " . $cvterm->name;
677 $c->stash->{rest} = \%response;
678 return;
681 # $self->add_cache_list(undef, $cvterm, $cvterm->type());
682 while (my $p = $parents_rs->next()) {
683 my $children_rs = $p->children();
684 while (my $rel_rs = $children_rs->next()) { # returns a list of cvterm rows
685 my $child = $rel_rs->subject();
686 $self->add_cache_list($p, $child, $rel_rs->type());
689 $c->stash->{rest} = $self->{cache_list};
693 =head1 PRIVATE ACTIONS
695 =head2 add_cache_list
697 Private action.
699 Adds an entry to the cache list.
701 Argsuments: 3 cvterm row objects: Parent, child, relationship
703 =cut
705 sub add_cache_list :Private {
706 my $self = shift;
707 my $parent = shift; # object
708 my $child = shift; # object
709 my $relationship = shift; #object
711 my $unique_hashkey = $parent->cvterm_id()." ".$child->cvterm_id();
712 if (exists($self->{duplicates}->{$unique_hashkey})) {
713 return;
716 $self->{duplicates}->{$unique_hashkey}++;
718 my $hashref = $self->flatten_node($child, $relationship);
719 ###$hashref->{parent} = $parent->get_full_accession();
721 my $dbxref = $parent->dbxref();
722 my $parent_accession = $dbxref->db()->name().":".$dbxref->accession();
723 $hashref->{parent} = $parent_accession;
724 ##print STDERR "Adding to cache list: parent=$parent. child=$child\n";
725 push @{$self->{cache_list}}, $hashref;
729 ### used for cvterm resultset
730 sub flatten_node {
731 my $self = shift;
732 my $node_row = shift;
733 my $rel_row = shift;
735 my $has_children = 0;
736 if ($node_row->children()->first()) {
737 $has_children = 1;
740 my $rel_name = "";
741 if ($rel_row) {
742 $rel_name = $rel_row->name();
745 my $dbxref = $node_row->dbxref();
747 my $hashref =
748 { accession => $dbxref->db->name().":".$dbxref->accession,
749 cvterm_name => $node_row->name(),
750 cvterm_id => $node_row->cvterm_id(),
751 has_children => $has_children,
752 relationship => $rel_name,