3 SGN::Controller::AJAX::Onto - a REST controller class to provide the
4 backend for the SGN ontology browser
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.
21 Lukas Mueller <lam87@cornell.edu>
27 package SGN
::Controller
::AJAX
::Onto
;
30 use CXGN
::Chado
::Cvterm
;
32 use namespace
::autoclean
;
34 BEGIN { extends
'Catalyst::Controller::REST' }
37 default => 'application/json',
39 map => { 'application/json' => 'JSON', 'text/html' => 'JSON' },
45 Public Path: /<ns>/children
47 L<Catalyst::Action::REST> action.
49 Provides a list of child terms, each child term being a hashref (or
50 equivalent) with keys accession, cvterm_name, cvterm_id, has_children,
55 sub children
: Local
: ActionClass
('REST') { }
58 my ( $self, $c ) = @_;
59 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
61 my ($db_name, $accession) = split ":", $c->request->param('node');
63 my $db = $schema->resultset('General::Db')->search({ name
=> uc($db_name) })->first();
64 my $dbxref = $db->find_related('dbxrefs', { accession
=> $accession });
66 my $cvterm = $dbxref->cvterm;
68 my $cvrel_rs = $cvterm->children(); # returns a result set
70 my @response_list = ();
71 while (my $cvrel_row = $cvrel_rs->next()) {
72 my $relationship_node = $cvrel_row->type();
73 my $child_node = $cvrel_row->subject();
75 #only report back children of the same cv namespace
76 if ($child_node->cv_id() != $cvterm->cv_id()) {
80 my $responsehash = $self->flatten_node($child_node, $relationship_node);
81 push @response_list, $responsehash;
83 @response_list = sort { lc $a->{cvterm_name
} cmp lc $b->{cvterm_name
} } @response_list;
84 $c->stash->{rest
} = \
@response_list;
90 Public Path: /<ns>/parents
92 L<Catalyst::Action::REST> action.
94 Returns a list of hashes with parents information in json, a list of
95 hashrefs with the keys: accession, relationship, has_children, cvterm_id
100 sub parents
: Local
: ActionClass
('REST') { }
105 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
107 my ($db_name, $accession) = split ":", $c->request->param('node');
110 my $db = $schema->resultset('General::Db')->search({ 'upper(name)' => uc($db_name) })->first();
111 if (!$db || !$accession) {
112 #not sure we need here to send an error key, since cache is usually called after parents (? )
113 $response{error
} = "Did not pass a legal ontology term ID! ( $db_name : $accession)";
114 $c->stash->{rest
} = \
%response;
117 $dbxref = $db->find_related('dbxrefs', { accession
=> $accession }) if $db;
119 $response{error
} = "Could not find term $db_name : $accession in the database! Check your input and try again";
120 $c->stash->{rest
} = \
%response;
123 my $cvterm = $dbxref->cvterm;
125 my @response_list = ();
127 my $parents_rs = $cvterm->recursive_parents(); # returns a result set
128 while (my $parent = $parents_rs->next()) {
129 #only report back children of the same cv namespace
130 if ($parent->cv_id() != $cvterm->cv_id()) {
133 my $responsehash = $self->flatten_node($parent, undef);
134 push @response_list, $responsehash;
137 $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.";
138 $c->stash->{rest
} = \
%response;
141 $c->stash->{rest
} = \
@response_list;
155 sub menu
: Local
: ActionClass
('REST') { }
161 my $menudata = $c->config->{onto_root_namespaces
};
163 print STDERR
"MENUDATA: $menudata\n";
164 my @menuitems = split ",", $menudata;
166 my $menu = '<select name="cv_select">';
168 foreach my $mi (@menuitems) {
169 print STDERR
"MENU ITEM: $mi\n";
170 if ($mi =~ /\s*(\w+)?\s*(.*)$/) {
174 $menu .= qq { <option value
="$value">$value $name</option
>\n };
178 $menu .= "</select>\n";
179 $c->stash->{rest
} = [ $menu ];
188 Public Path: /<ns>/roots
190 L<Catalyst::Action::REST> action.
192 Provides the default roots for drawing the ontology browser
196 nodes: optional, a string with namespace definitions, separated by white
197 space (for example, "PO SP SO"). If not provided, will This overrides the standard
198 namespaces provided when called without arguments.
202 sub roots
: Local
: ActionClass
('REST') { }
207 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
209 my $namespace = $c->request->param('nodes');
211 my @response_nodes = ();
212 #my $empty_cvterm = CXGN::Chado::Cvterm->new($c->dbc()->dbh());
213 if (!$namespace) { # should namespaces be db names ? (SO, GO,PO, SP, PATO)
224 @namespaces = split /\s+/, $namespace; #split on whitespace
228 foreach my $ns (@namespaces) {
229 $is_rel = 1 if $ns eq 'OBO_REL';
230 my $q = "SELECT cvterm.cvterm_id FROM cvterm
231 JOIN dbxref USING(dbxref_id) JOIN db USING(db_id)
232 LEFT JOIN cvterm_relationship ON (cvterm.cvterm_id=cvterm_relationship.subject_id)
233 WHERE cvterm_relationship.subject_id IS NULL AND is_obsolete= ? AND is_relationshiptype = ? AND db.name= ? ";
234 my $sth = $schema->storage->dbh->prepare($q);
235 $sth->execute(0,$is_rel,$ns);
236 while (my ($cvterm_id) = $sth->fetchrow_array() ) {
237 my $root = $schema->resultset("Cv::Cvterm")->find( { cvterm_id
=> $cvterm_id } );
241 my @response_list = ();
243 foreach my $r (@roots) {
244 my $hashref = $self->flatten_node($r, undef);
245 push @response_list, $hashref;
247 $c->stash->{rest
}= \
@response_list;
253 Public Path: /<ns>/match
255 L<Catalyst::Action::REST> action.
264 sub match
: Local
: ActionClass
('REST') { }
269 my $db_name = $c->request->param("db_name");
270 my $term_name = $c->request->param("term_name");
272 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
273 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
275 JOIN dbxref USING (db_id ) JOIN cvterm USING (dbxref_id)
276 JOIN cv USING (cv_id )
277 LEFT JOIN cvtermsynonym USING (cvterm_id )
278 WHERE db.name = ? AND (cvterm.name ilike ? OR cvtermsynonym.synonym ilike ? OR cvterm.definition ilike ?) AND cvterm.is_obsolete = 0
279 GROUP BY cvterm.cvterm_id,cv.name, cvterm.name, dbxref.accession, db.name ";
280 my $sth= $schema->storage->dbh->prepare($query);
281 $sth->execute($db_name, "\%$term_name\%", "\%$term_name\%", "\%$term_name\%");
283 while (my $hashref = $sth->fetchrow_hashref ) {
284 push @response_list, $hashref;
286 $c->stash->{rest
} = \
@response_list;
291 Public Path: /<ns>/cache
293 L<Catalyst::Action::REST> action.
295 Provides a list of parents and their direct children in a denormalized
296 list. The parameter node is used to determine all the children that
297 need to be cached for the parentage view to render fast (without
298 having to call the children ajax function).
302 sub cache
: Local
: ActionClass
('REST') { }
308 $self->{duplicates
} = {};
309 $self->{cache_list
} = [];
311 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
313 my ($db_name, $accession) = split ":", $c->request->param('node');
314 if (!$db_name || !$accession) {
315 $response{error
} = "Looks like you passed an illegal ontology term ID ! ($db_name : $accession) Please try again.";
316 $c->stash->{rest
} = \
%response;
320 my $db = $schema->resultset('General::Db')->search({ name
=> $db_name })->first();
321 my $dbxref = $db->find_related('dbxrefs', { accession
=> $accession });
323 $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";
324 $c->stash->{rest
} = \
%response;
328 my $cvterm = $dbxref->cvterm;
330 $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 fic this error ASAP";
331 $c->stash->{rest
} = \
%response;
334 my $parents_rs = $cvterm->recursive_parents(); # returns a result set
335 if (!$parents_rs->next) {
336 $response{error
} = "did not find recursive parents for cvterm " . $cvterm->name;
337 $c->stash->{rest
} = \
%response;
341 # $self->add_cache_list(undef, $cvterm, $cvterm->type());
342 while (my $p = $parents_rs->next()) {
343 my $children_rs = $p->children();
344 while (my $rel_rs = $children_rs->next()) { # returns a list of cvterm rows
345 my $child = $rel_rs->subject();
346 $self->add_cache_list($p, $child, $rel_rs->type());
349 $c->stash->{rest
} = $self->{cache_list
};
353 =head1 PRIVATE ACTIONS
355 =head2 add_cache_list
359 Adds an entry to the cache list.
361 Argsuments: 3 cvterm row objects: Parent, child, relationship
365 sub add_cache_list
:Private
{
367 my $parent = shift; # object
368 my $child = shift; # object
369 my $relationship = shift; #object
371 my $unique_hashkey = $parent->cvterm_id()." ".$child->cvterm_id();
372 if (exists($self->{duplicates
}->{$unique_hashkey})) {
376 $self->{duplicates
}->{$unique_hashkey}++;
378 my $hashref = $self->flatten_node($child, $relationship);
379 ###$hashref->{parent} = $parent->get_full_accession();
381 my $dbxref = $parent->dbxref();
382 my $parent_accession = $dbxref->db()->name().":".$dbxref->accession();
383 $hashref->{parent
} = $parent_accession;
384 ##print STDERR "Adding to cache list: parent=$parent. child=$child\n";
385 push @
{$self->{cache_list
}}, $hashref;
389 ### used for cvterm resultset
392 my $node_row = shift;
395 my $has_children = 0;
396 if ($node_row->children()->first()) {
402 $rel_name = $rel_row->name();
405 my $dbxref = $node_row->dbxref();
408 { accession
=> $dbxref->db->name().":".$dbxref->accession,
409 cvterm_name
=> $node_row->name(),
410 cvterm_id
=> $node_row->cvterm_id(),
411 has_children
=> $has_children,
412 relationship
=> $rel_name,