comparison variant_effect_predictor/Bio/EnsEMBL/DBSQL/OntologyTermAdaptor.pm @ 0:1f6dce3d34e0

Uploaded
author mahtabm
date Thu, 11 Apr 2013 02:01:53 -0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:1f6dce3d34e0
1 =head1 LICENSE
2
3 Copyright (c) 1999-2012 The European Bioinformatics Institute and
4 Genome Research Limited. All rights reserved.
5
6 This software is distributed under a modified Apache license.
7 For license details, please see
8
9 http://www.ensembl.org/info/about/code_licence.html
10
11 =head1 CONTACT
12
13 Please email comments or questions to the public Ensembl
14 developers list at <dev@ensembl.org>.
15
16 Questions may also be sent to the Ensembl help desk at
17 <helpdesk@ensembl.org>.
18
19 =cut
20
21 =head1 NAME
22
23 Bio::EnsEMBL::DBSQL::OntologyTermAdaptor
24
25 =head1 SYNOPSIS
26
27 my $goa =
28 $registry->get_adaptor( 'Multi', 'Ontology', 'OntologyTerm' );
29
30 my $term = $goa->fetch_by_accession('GO:0010885');
31
32 my @children = @{ $goa->fetch_all_by_parent_term($term) };
33 my @descendants = @{ $goa->fetch_all_by_ancestor_term($term) };
34
35 my @parents = @{ $goa->fetch_all_by_child_term($term) };
36 my @ancestors = @{ $goa->fetch_all_by_descendant_term($term) };
37
38 my %ancestor_chart = %{ $goa->_fetch_ancestor_chart($term) };
39
40 =head1 DESCRIPTION
41
42 An abstract adaptor class for fetching ontology
43 terms, creates Bio::EnsEMBL::OntologyTerm objects.
44
45 =head1 METHODS
46
47 =cut
48
49 package Bio::EnsEMBL::DBSQL::OntologyTermAdaptor;
50
51 use strict;
52 use warnings;
53
54 use DBI qw( :sql_types );
55
56 use Bio::EnsEMBL::Utils::Exception qw( throw );
57 use Bio::EnsEMBL::Utils::Scalar qw( assert_ref );
58
59 use Bio::EnsEMBL::OntologyTerm;
60
61 use base qw( Bio::EnsEMBL::DBSQL::BaseAdaptor );
62
63 =head2 fetch_all_by_name
64
65 Arg [1] : String, name of term, or SQL pattern
66 Arg [2] : (optional) String, name of ontology
67
68 Description : Fetches ontology term(s) given a name, a synonym, or a
69 SQL pattern like "%splice_site%"
70
71 Example :
72
73 my ($term) =
74 @{ $ot_adaptor->fetch_by_name( 'DNA_binding_site', 'SO' ) };
75
76 # Will find terms in both SO and GO:
77 my @terms = @{ $ot_adaptor->fetch_by_name('%splice_site%') };
78
79 Return type : listref of Bio::EnsEMBL::OntologyTerm
80
81 =cut
82
83 sub fetch_all_by_name {
84 my ( $this, $pattern, $ontology ) = @_;
85
86 my $statement = q(
87 SELECT DISTINCT
88 term.term_id,
89 term.accession,
90 term.name,
91 term.definition,
92 term.subsets,
93 ontology.namespace
94 FROM ontology
95 JOIN term USING (ontology_id)
96 LEFT JOIN synonym USING (term_id)
97 WHERE ( term.name LIKE ? OR synonym.name LIKE ? ));
98
99 if ( defined($ontology) ) {
100 $statement .= " AND ontology.name = ?";
101 }
102
103 my $sth = $this->prepare($statement);
104 $sth->bind_param( 1, $pattern, SQL_VARCHAR );
105 $sth->bind_param( 2, $pattern, SQL_VARCHAR );
106
107 if ( defined($ontology) ) {
108 $sth->bind_param( 3, $ontology, SQL_VARCHAR );
109 }
110
111 $sth->execute();
112
113 my ( $dbid, $accession, $name, $definition, $subsets, $namespace );
114 $sth->bind_columns(
115 \( $dbid, $accession, $name, $definition, $subsets, $namespace ) );
116
117 my @terms;
118
119 while ( $sth->fetch() ) {
120 $subsets ||= '';
121
122 push @terms,
123 Bio::EnsEMBL::OntologyTerm->new(
124 '-dbid' => $dbid,
125 '-adaptor' => $this,
126 '-accession' => $accession,
127 '-namespace' => $namespace,
128 '-subsets' => [ split( /,/, $subsets ) ],
129 '-name' => $name,
130 '-definition' => $definition, );
131 }
132
133 return \@terms;
134 } ## end sub fetch_all_by_name
135
136
137 =head2 fetch_by_accession
138
139 Arg [1] : String
140
141 Description : Fetches an ontology term given an accession.
142
143 Example :
144
145 my $term = $ot_adaptor->fetch_by_accession('GO:0030326');
146
147 Return type : Bio::EnsEMBL::OntologyTerm
148
149 =cut
150
151 sub fetch_by_accession {
152 my ( $this, $accession ) = @_;
153
154 my $statement = q(
155 SELECT term.term_id,
156 term.name,
157 term.definition,
158 term.subsets,
159 ontology.name,
160 ontology.namespace
161 FROM ontology
162 JOIN term USING (ontology_id)
163 WHERE term.accession = ?);
164
165 my $sth = $this->prepare($statement);
166 $sth->bind_param( 1, $accession, SQL_VARCHAR );
167
168 $sth->execute();
169
170 my ( $dbid, $name, $definition, $subsets, $ontology, $namespace );
171 $sth->bind_columns(
172 \( $dbid, $name, $definition, $subsets, $ontology, $namespace ) );
173
174 $sth->fetch();
175 $subsets ||= '';
176
177 my $term =
178 Bio::EnsEMBL::OntologyTerm->new(
179 '-dbid' => $dbid,
180 '-adaptor' => $this,
181 '-accession' => $accession,
182 '-ontology' => $ontology,
183 '-namespace' => $namespace,
184 '-subsets' => [ split( /,/, $subsets ) ],
185 '-name' => $name,
186 '-definition' => $definition,
187 '-synonyms' => $this->_fetch_synonyms_by_dbID($dbid)
188 );
189 $sth->finish();
190
191 return $term;
192 } ## end sub fetch_by_accession
193
194 =head2 fetch_all_by_parent_term
195
196 Arg [1] : Bio::EnsEMBL::OntologyTerm
197 The term whose children terms should be fetched.
198
199 Description : Given a parent ontology term, returns a list of
200 its immediate children terms.
201
202 Example :
203
204 my @children =
205 @{ $ot_adaptor->fetch_all_by_parent_term($term) };
206
207 Return type : listref of Bio::EnsEMBL::OntologyTerm
208
209 =cut
210
211 sub fetch_all_by_parent_term {
212 my ( $this, $term ) = @_;
213
214 assert_ref( $term, 'Bio::EnsEMBL::OntologyTerm' );
215
216 my @terms;
217
218 if ( !$term->{'child_terms_fetched'} ) {
219 my $statement = q(
220 SELECT child_term.term_id,
221 child_term.accession,
222 child_term.name,
223 child_term.definition,
224 child_term.subsets,
225 rt.name
226 FROM term child_term
227 JOIN relation ON (relation.child_term_id = child_term.term_id)
228 JOIN relation_type rt USING (relation_type_id)
229 WHERE relation.parent_term_id = ?);
230
231 my $sth = $this->prepare($statement);
232 $sth->bind_param( 1, $term->dbID(), SQL_INTEGER );
233
234 $sth->execute();
235
236 my ( $dbid, $accession, $name, $definition, $subsets, $relation );
237 $sth->bind_columns(
238 \( $dbid, $accession, $name, $definition, $subsets, $relation ) );
239
240 while ( $sth->fetch() ) {
241 $subsets ||= '';
242
243 my $child_term =
244 Bio::EnsEMBL::OntologyTerm->new(
245 '-dbid' => $dbid,
246 '-adaptor' => $this,
247 '-accession' => $accession,
248 '-ontology' => $term->{'ontology'},
249 '-namespace' => $term->{'namespace'},
250 '-subsets' => [ split( /,/, $subsets ) ],
251 '-name' => $name,
252 '-definition' => $definition, );
253
254 push( @terms, $child_term );
255 push( @{ $term->{'children'}{$relation} }, $child_term );
256 }
257
258 $term->{'child_terms_fetched'} = 1;
259 } else {
260 foreach my $relation ( values( %{ $term->{'children'} } ) ) {
261 push( @terms, @{$relation} );
262 }
263 }
264
265 return \@terms;
266 } ## end sub fetch_all_by_parent_term
267
268 =head2 fetch_all_by_ancestor_term
269
270 Arg [1] : Bio::EnsEMBL::OntologyTerm
271 The term whose descendant terms should be fetched.
272
273 Description : Given a parent ontology term, returns a list of
274 all its descendant terms, down to and including
275 any leaf terms. Relations of the type 'is_a' and
276 'part_of' are followed.
277
278 Example :
279
280 my @descendants =
281 @{ $ot_adaptor->fetch_all_by_ancestor_term($term) };
282
283 Return type : listref of Bio::EnsEMBL::OntologyTerm
284
285 =cut
286
287 sub fetch_all_by_ancestor_term {
288 my ( $this, $term ) = @_;
289
290 assert_ref( $term, 'Bio::EnsEMBL::OntologyTerm' );
291
292 my $statement = q(
293 SELECT DISTINCT
294 child_term.term_id,
295 child_term.accession,
296 child_term.name,
297 child_term.definition,
298 child_term.subsets
299 FROM term child_term
300 JOIN closure ON (closure.child_term_id = child_term.term_id)
301 WHERE closure.parent_term_id = ?
302 AND closure.distance > 0
303 ORDER BY closure.distance, child_term.accession);
304
305 my $sth = $this->prepare($statement);
306 $sth->bind_param( 1, $term->dbID(), SQL_INTEGER );
307
308 $sth->execute();
309
310 my ( $dbid, $accession, $name, $definition, $subsets );
311 $sth->bind_columns(
312 \( $dbid, $accession, $name, $definition, $subsets ) );
313
314 my @terms;
315
316 while ( $sth->fetch() ) {
317 $subsets ||= '';
318
319 push( @terms,
320 Bio::EnsEMBL::OntologyTerm->new(
321 '-dbid' => $dbid,
322 '-adaptor' => $this,
323 '-accession' => $accession,
324 '-ontology' => $term->{'ontology'},
325 '-namespace' => $term->{'namespace'},
326 '-subsets' => [ split( /,/, $subsets ) ],
327 '-name' => $name,
328 '-definition' => $definition, ) );
329 }
330
331 return \@terms;
332 } ## end sub fetch_all_by_ancestor_term
333
334 =head2 fetch_all_by_child_term
335
336 Arg [1] : Bio::EnsEMBL::OntologyTerm
337 The term whose parent terms should be fetched.
338
339 Description : Given a child ontology term, returns a list of
340 its immediate parent terms.
341
342 Example :
343
344 my @parents = @{ $ot_adaptor->fetch_all_by_child_term($term) };
345
346 Return type : listref of Bio::EnsEMBL::OntologyTerm
347
348 =cut
349
350 sub fetch_all_by_child_term {
351 my ( $this, $term ) = @_;
352
353 assert_ref( $term, 'Bio::EnsEMBL::OntologyTerm' );
354
355 my @terms;
356
357 if ( !$term->{'parent_terms_fetched'} ) {
358 my $statement = q(
359 SELECT parent_term.term_id,
360 parent_term.accession,
361 parent_term.name,
362 parent_term.definition,
363 parent_term.subsets,
364 rt.name
365 FROM term parent_term
366 JOIN relation ON (relation.parent_term_id = parent_term.term_id)
367 JOIN relation_type rt USING (relation_type_id)
368 WHERE relation.child_term_id = ?);
369
370 my $sth = $this->prepare($statement);
371 $sth->bind_param( 1, $term->dbID(), SQL_INTEGER );
372
373 $sth->execute();
374
375 my ( $dbid, $accession, $name, $definition, $subsets, $relation );
376 $sth->bind_columns(
377 \( $dbid, $accession, $name, $definition, $subsets, $relation ) );
378
379 while ( $sth->fetch() ) {
380 $subsets ||= '';
381
382 my $parent_term =
383 Bio::EnsEMBL::OntologyTerm->new(
384 '-dbid' => $dbid,
385 '-adaptor' => $this,
386 '-accession' => $accession,
387 '-ontology' => $term->{'ontology'},
388 '-namespace' => $term->{'namespace'},
389 '-subsets' => [ split( /,/, $subsets ) ],
390 '-name' => $name,
391 '-definition' => $definition, );
392
393 push( @terms, $parent_term );
394 push( @{ $term->{'parents'}{$relation} }, $parent_term );
395 }
396
397 $term->{'parent_terms_fetched'} = 1;
398 } else {
399 foreach my $relation ( values( %{ $term->{'parents'} } ) ) {
400 push( @terms, @{$relation} );
401 }
402 }
403
404 return \@terms;
405 } ## end sub fetch_all_by_child_term
406
407 =head2 fetch_all_by_descendant_term
408
409 Arg [1] : Bio::EnsEMBL::OntologyTerm
410 The term whose ancestor terms should be fetched.
411
412 Arg [2] : (optional) String
413 The subset within the ontolgy to which the query
414 should be restricted. The subset may be specified as
415 a SQL pattern, e.g., "%goslim%" (but "goslim%" might
416 not do what you expect), or as a specific subset name,
417 e.g., "goslim_generic".
418
419 Arg [3] : (optional) Boolean
420 If true (non-zero), only return the closest
421 term(s). If this argument is true, and the
422 previous argument is left undefined, this method
423 will return the parent(s) of the given term.
424
425 Arg [4] : (optional) Boolean
426 If true we will allow the retrieval of terms whose distance
427 to the current term is 0. If false then we will only return
428 those which are above the current term in the ontology
429
430 Description : Given a child ontology term, returns a list of
431 all its ancestor terms, up to and including any
432 root term. Relations of the type 'is_a' and
433 'part_of' are followed. Optionally, only terms in
434 a given subset of the ontology may be returned,
435 and additionally one may ask to only get the
436 closest term(s) to the given child term.
437
438 Example :
439
440 my @ancestors =
441 @{ $ot_adaptor->fetch_all_by_descendant_term($term) };
442
443 Return type : listref of Bio::EnsEMBL::OntologyTerm
444
445 =cut
446
447 sub fetch_all_by_descendant_term {
448 my ( $this, $term, $subset, $closest_only, $allow_zero_distance ) = @_;
449
450 assert_ref( $term, 'Bio::EnsEMBL::OntologyTerm' );
451
452 $closest_only ||= 0;
453
454 my $statement = q(
455 SELECT DISTINCT
456 parent_term.term_id,
457 parent_term.accession,
458 parent_term.name,
459 parent_term.definition,
460 parent_term.subsets,
461 closure.distance
462 FROM term parent_term
463 JOIN closure ON (closure.parent_term_id = parent_term.term_id)
464 WHERE closure.child_term_id = ?
465 AND closure.distance > ?);
466
467 if ( defined($subset) ) {
468 if ( index( $subset, '%' ) != -1 ) {
469 $statement .= q(
470 AND parent_term.subsets LIKE ?);
471 } else {
472 $statement .= q(
473 AND FIND_IN_SET(?, parent_term.subsets) > 0);
474 }
475 }
476
477 $statement .= q(
478 ORDER BY closure.distance, parent_term.accession);
479
480 my $sth = $this->prepare($statement);
481 $sth->bind_param( 1, $term->dbID(), SQL_INTEGER );
482 my $query_distance = ($allow_zero_distance) ? -1 : 0;
483 $sth->bind_param( 2, $query_distance, SQL_INTEGER );
484
485 if ( defined($subset) ) {
486 $sth->bind_param( 3, $subset, SQL_VARCHAR );
487 }
488
489 $sth->execute();
490
491 my ( $dbid, $accession, $name, $definition, $subsets, $distance );
492 $sth->bind_columns(
493 \( $dbid, $accession, $name, $definition, $subsets, $distance ) );
494
495 my @terms;
496 my $min_distance;
497
498 while ( $sth->fetch() ) {
499 $subsets ||= '';
500 $min_distance ||= $distance;
501
502 if ( !$closest_only || $distance == $min_distance ) {
503 push( @terms,
504 Bio::EnsEMBL::OntologyTerm->new(
505 '-dbid' => $dbid,
506 '-adaptor' => $this,
507 '-accession' => $accession,
508 '-ontology' => $term->{'ontology'},
509 '-namespace' => $term->{'namespace'},
510 '-subsets' => [ split( /,/, $subsets ) ],
511 '-name' => $name,
512 '-definition' => $definition, ) );
513 } else {
514 $sth->finish();
515 last;
516 }
517 }
518
519 return \@terms;
520 } ## end sub fetch_all_by_descendant_term
521
522 sub _fetch_synonyms_by_dbID {
523 my ( $this, $dbID ) = @_;
524
525 my $statement = q(
526 SELECT synonym.name
527 FROM synonym
528 WHERE synonym.term_id = ?);
529
530 my $sth = $this->prepare($statement);
531 $sth->bind_param( 1, $dbID, SQL_INTEGER );
532
533 $sth->execute();
534
535 my $synonym;
536 $sth->bind_col( 1, \$synonym );
537
538 my @synonyms;
539 while ( $sth->fetch() ) {
540 push( @synonyms, $synonym );
541 }
542
543 return \@synonyms;
544 }
545
546
547
548 =head2 _fetch_ancestor_chart
549
550 Arg [1] : Bio::EnsEMBL::OntologyTerm
551 The term whose ancestor terms should be fetched.
552
553 Description : Given a child ontology term, returns a hash
554 structure containing its ancestor terms, up to and
555 including any root term. Relations of the type
556 'is_a' and 'part_of' are included.
557
558 Example :
559
560 my %chart = %{ $ot_adaptor->_fetch_ancestor_chart($term) };
561
562 Return type : A reference to a hash structure like this:
563
564 {
565 'GO:XXXXXXX' => {
566 'term' => # ref to Bio::EnsEMBL::OntologyTerm object
567 'is_a' => [...], # listref of Bio::EnsEMBL::OntologyTerm
568 'part_of' => [...], # listref of Bio::EnsEMBL::OntologyTerm
569 },
570 'GO:YYYYYYY' => {
571 # Similarly for all ancestors,
572 # and including the query term itself.
573 }
574 }
575
576 =cut
577
578 sub _fetch_ancestor_chart {
579 my ( $this, $term ) = @_;
580
581 assert_ref( $term, 'Bio::EnsEMBL::OntologyTerm' );
582
583 my $statement = q(
584 SELECT subparent_term.term_id,
585 parent_term.term_id,
586 relation_type.name
587 FROM closure
588 JOIN relation
589 ON (relation.parent_term_id = closure.parent_term_id
590 AND relation.child_term_id = closure.subparent_term_id)
591 JOIN relation_type USING (relation_type_id)
592 JOIN term subparent_term
593 ON (subparent_term.term_id = closure.subparent_term_id)
594 JOIN term parent_term ON (parent_term.term_id = closure.parent_term_id)
595 WHERE closure.child_term_id = ?
596 ORDER BY closure.distance);
597
598 my $sth = $this->prepare($statement);
599 $sth->bind_param( 1, $term->dbID(), SQL_INTEGER );
600
601 $sth->execute();
602
603 my ( $subparent_id, $parent_id, $relation );
604 $sth->bind_columns( \( $subparent_id, $parent_id, $relation ) );
605
606 my %id_chart;
607 my %acc_chart;
608
609 while ( $sth->fetch() ) {
610 if ( !exists( $id_chart{$parent_id} ) ) {
611 $id_chart{$parent_id} = {};
612 }
613 push( @{ $id_chart{$subparent_id}{$relation} }, $parent_id );
614 }
615
616 my @terms = @{ $this->fetch_all_by_dbID_list( [ keys(%id_chart) ] ) };
617
618 foreach my $term (@terms) {
619 $id_chart{ $term->dbID() }{'term'} = $term;
620 $acc_chart{ $term->accession() }{'term'} = $term;
621 }
622
623 foreach my $term (@terms) {
624 my $accession = $term->accession();
625 my $dbID = $term->dbID();
626
627 foreach my $relation ( keys( %{ $id_chart{$dbID} } ) ) {
628 if ( $relation eq 'term' ) { next }
629
630 foreach my $id ( @{ $id_chart{$dbID}{$relation} } ) {
631 push( @{ $acc_chart{$accession}{$relation} },
632 $id_chart{$id}{'term'} );
633 }
634 }
635 }
636
637 return \%acc_chart;
638 } ## end sub _fetch_ancestor_chart
639
640 #-----------------------------------------------------------------------
641 # Useful public methods that implement functionality not properly
642 # provided by the parent class Bio::EnsEMBL::DBSQL::BaseAdaptor.
643
644 sub fetch_by_dbID {
645 my ( $this, $dbid ) = @_;
646
647 my $statement = q(
648 SELECT term.accession,
649 term.name,
650 term.definition,
651 term.subsets,
652 ontology.name,
653 ontology.namespace
654 FROM ontology
655 JOIN term USING (ontology_id)
656 WHERE term.term_id = ?);
657
658 my $sth = $this->prepare($statement);
659 $sth->bind_param( 1, $dbid, SQL_INTEGER );
660
661 $sth->execute();
662
663 my ( $accession, $name, $definition, $subsets, $ontology,
664 $namespace );
665 $sth->bind_columns(
666 \( $accession, $name, $definition, $subsets, $ontology, $namespace
667 ) );
668
669 $sth->fetch();
670 $subsets ||= '';
671
672 my $term =
673 Bio::EnsEMBL::OntologyTerm->new(
674 '-dbid' => $dbid,
675 '-adaptor' => $this,
676 '-accession' => $accession,
677 '-ontology' => $ontology,
678 '-namespace' => $namespace,
679 '-subsets' => [ split( /,/, $subsets ) ],
680 '-name' => $name,
681 '-definition' => $definition,
682 '-synonyms' => $this->_fetch_synonyms_by_dbID($dbid)
683 );
684 $sth->finish();
685
686 return $term;
687 } ## end sub fetch_by_dbID
688
689 sub fetch_all_by_dbID_list {
690 my ( $this, $dbids ) = @_;
691
692 if ( !@{$dbids} ) { return [] }
693
694 my $stmt = q(
695 SELECT term.term_id,
696 term.accession,
697 term.name,
698 term.definition,
699 term.subsets,
700 ontology.name,
701 ontology.namespace
702 FROM ontology
703 JOIN term USING (ontology_id)
704 WHERE term.term_id IN (%s));
705
706 my $statement = sprintf(
707 $stmt,
708 join(
709 ',',
710 map {
711 $this->dbc()->db_handle()->quote( $_, SQL_INTEGER )
712 } @{$dbids} ) );
713
714 my $sth = $this->prepare($statement);
715
716 $sth->execute();
717
718 my ( $dbid, $accession, $name, $definition, $subsets, $ontology,
719 $namespace );
720 $sth->bind_columns( \( $dbid, $accession, $name, $definition,
721 $subsets, $ontology, $namespace ) );
722
723 my @terms;
724
725 while ( $sth->fetch() ) {
726 $subsets ||= '';
727
728 push( @terms,
729 Bio::EnsEMBL::OntologyTerm->new(
730 '-dbid' => $dbid,
731 '-adaptor' => $this,
732 '-accession' => $accession,
733 '-ontology' => $ontology,
734 '-namespace' => $namespace,
735 '-subsets' => [ split( /,/, $subsets ) ],
736 '-name' => $name,
737 '-definition' => $definition, ) );
738 }
739
740 return \@terms;
741 } ## end sub fetch_all_by_dbID_list
742
743 sub fetch_all {
744 my ($this) = @_;
745
746 my $statement = q(
747 SELECT term.term_id,
748 term.accession,
749 term.name,
750 term.definition,
751 term.subsets,
752 ontology.name,
753 ontology.namespace
754 FROM ontology
755 JOIN term USING (ontology_id));
756
757 my $sth = $this->prepare($statement);
758 $sth->execute();
759
760 my ( $dbid, $accession, $name, $definition, $subsets, $ontology,
761 $namespace );
762 $sth->bind_columns( \( $dbid, $accession, $name, $definition,
763 $subsets, $ontology, $namespace ) );
764
765 my @terms;
766
767 while ( $sth->fetch() ) {
768 $subsets ||= '';
769
770 push( @terms,
771 Bio::EnsEMBL::OntologyTerm->new(
772 '-dbid' => $dbid,
773 '-adaptor' => $this,
774 '-accession' => $accession,
775 '-ontology' => $ontology,
776 '-namespace' => $namespace,
777 '-subsets' => [ split( /,/, $subsets ) ],
778 '-name' => $name,
779 '-definition' => $definition ) );
780 }
781
782 return \@terms;
783 } ## end sub fetch_all
784
785 1;