File Coverage

blib/lib/Bio/Tools/EUtilities/EUtilParameters.pm
Criterion Covered Total %
statement 147 368 39.9
branch 57 218 26.1
condition 43 237 18.1
subroutine 26 56 46.4
pod 16 46 34.7
total 289 925 31.2


line stmt bran cond sub pod time code
1             package Bio::Tools::EUtilities::EUtilParameters;
2             $Bio::Tools::EUtilities::EUtilParameters::VERSION = '1.77';
3 5     5   106468 use utf8;
  5         41  
  5         32  
4 5     5   162 use strict;
  5         10  
  5         103  
5 5     5   25 use warnings;
  5         11  
  5         153  
6 5     5   25 use base qw(Bio::Root::Root Bio::ParameterBaseI);
  5         11  
  5         2996  
7 5     5   54643 use URI;
  5         23855  
  5         184  
8 5     5   2413 use HTTP::Request;
  5         60541  
  5         258  
9 5     5   42 use Bio::Root::IO;
  5         12  
  5         1312  
10              
11             # ABSTRACT: Manipulation of NCBI eutil-based parameters for remote database requests.
12             # AUTHOR: Chris Fields
13             # OWNER: 2006-2013 Chris Fields
14             # LICENSE: Perl_5
15              
16              
17             # eutils only has one hostbase URL
18              
19             # mode : GET or POST (HTTP::Request)
20             # location : CGI location
21             # params : allowed parameters for that eutil
22             my %MODE = (
23             'einfo' => {
24             'mode' => ['GET'],
25             'location' => 'einfo.fcgi',
26             'params' => [qw(db tool email api_key)],
27             },
28             'epost' => {
29             'mode' => ['POST','GET'],
30             'location' => 'epost.fcgi',
31             'params' => [qw(db retmode id tool email api_key idtype WebEnv query_key)],
32             },
33             'efetch' => {
34             'mode' => ['GET','POST'],
35             'location' => 'efetch.fcgi',
36             'params' => [qw(db retmode id retmax retstart rettype strand seq_start
37             seq_stop complexity report tool email api_key idtype WebEnv query_key)],
38             },
39             'esearch' => {
40             'mode' => ['GET','POST'],
41             'location' => 'esearch.fcgi',
42             'params' => [qw(db retmode usehistory term field reldate mindate
43             maxdate datetype retmax retstart rettype sort tool email api_key idtype
44             WebEnv query_key)],
45             },
46             'esummary' => {
47             'mode' => ['GET','POST'],
48             'location' => 'esummary.fcgi',
49             'params' => [qw(db retmode id retmax retstart rettype tool email api_key idtype
50             version WebEnv query_key)],
51             },
52             'elink' => {
53             'mode' => ['GET','POST'],
54             'location' => 'elink.fcgi',
55             'params' => [qw(db retmode id reldate mindate maxdate datetype term
56             dbfrom holding cmd version tool email api_key idtype linkname WebEnv
57             query_key)],
58             },
59             'egquery' => {
60             'mode' => ['GET','POST'],
61             'location' => 'egquery.fcgi',
62             'params' => [qw(term retmode tool email api_key)],
63             },
64             'espell' => {
65             'mode' => ['GET','POST'],
66             'location' => 'espell.fcgi',
67             'params' => [qw(db retmode term tool email api_key )],
68             }
69             );
70              
71             my @PARAMS;
72              
73             # generate getter/setters (will move this into individual ones at some point)
74              
75             BEGIN {
76 5     5   72 @PARAMS = qw(db id email api_key retmode rettype usehistory term field tool
77             reldate mindate maxdate datetype retstart retmax sort seq_start seq_stop
78             strand complexity report dbfrom cmd holding version linkname WebEnv
79             query_key idtype);
80 5         22 for my $method (@PARAMS) {
81 150 0 0 0 0 27323 eval <
  0 0 0 0 0 0  
  0 0 0 0 0 0  
  0 0 0 0 0 0  
  0 0 0 0 0 0  
  0 0 0 15 0 0  
  0 0 0 0 0 0  
  0 0 0 2 0 0  
  0 0 0 0 0 0  
  0 0 0 0 0 0  
  0 100 33 9 0 0  
  0 100 66 0 0 0  
  0 0 0 0 0 0  
  0 0 0 0 0 0  
  0 100 33 0 0 0  
  0 50 66 0 0 0  
  0 0 0 0 0 0  
  0 0 0 0 0 0  
  0 0 0 0 0 0  
  0 0 0 9 0 0  
  0 100 33 0 0 0  
  0 100 66 0 0 0  
  0 0 0 0 0 0  
  0 0 0 0 0 0  
  0 0 0 0 0 0  
  0 0 0 0 0 0  
  0 0 0 4 0 0  
  0 0 0 12 0 0  
  0 0 0 0 0 0  
  0 0 0 0 0 0  
  0 0 0     0  
  15 0 0     1213  
  15 0 0     49  
  7 0 0     54  
  6 0 0     15  
  6 0 0     20  
  15 0 0     92  
  0 0 0     0  
  0 100 66     0  
  0 50 100     0  
  0 0 0     0  
  0 0 0     0  
  0 0 0     0  
  2 0 0     100  
  2 0 0     7  
  2 0 0     15  
  1 0 0     2  
  1 0 0     3  
  2 0 0     9  
  0 0 0     0  
  0 0 0     0  
  0 0 0     0  
  0 50 0     0  
  0 100 33     0  
  0 50 0     0  
  0 100 33     0  
  0 0 0     0  
  0 0 0     0  
  0 0 0     0  
  0 0 0     0  
  0         0  
  9         661  
  9         28  
  4         33  
  3         10  
  3         10  
  9         61  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  9         95  
  9         40  
  9         60  
  7         16  
  7         17  
  9         27  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  4         93  
  4         15  
  2         12  
  2         7  
  2         6  
  4         23  
  12         43  
  12         41  
  6         36  
  6         14  
  6         17  
  12         176  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
82             sub $method {
83             my (\$self, \$val) = \@_;
84             if (defined \$val) {
85             if ((!defined \$self->{'_$method'}) ||
86             (defined \$self->{'_$method'} && \$self->{'_$method'} ne \$val)) {
87             \$self->{'_statechange'} = 1;
88             \$self->{'_$method'} = \$val;
89             }
90             }
91             return \$self->{'_$method'};
92             }
93             END
94             }
95             }
96              
97             sub new {
98 6     6 1 183 my ($class, @args) = @_;
99 6         70 my $self = $class->SUPER::new(@args);
100 6         302 my ($retmode) = $self->_rearrange(["RETMODE"],@args);
101             # order is important here, eutil must be set first so that proper error
102             # checking occurs for the later attributes
103 6         320 $self->_set_from_args(\@args,
104             -methods => [@PARAMS, qw(eutil history correspondence id_file request_mode)]);
105 6 50       82 $self->eutil() || $self->eutil('efetch');
106 6 50       160 $self->tool() || $self->tool('BioPerl');
107             # set default retmode if not explicitly set
108 6 100       49 $self->set_default_retmode if (!$retmode);
109 6         17 $self->{'_statechange'} = 1;
110 6         33 return $self;
111             }
112              
113              
114             sub set_parameters {
115 1     1 1 5 my ($self, @args) = @_;
116             # allow automated resetting; must check to ensure that retmode isn't explicitly passed
117 1         6 my ($newmode,$file) = $self->_rearrange([qw(RETMODE ID_FILE)],@args);
118 1         66 $self->_set_from_args(\@args, -methods => [@PARAMS, qw(eutil correspondence history)]);
119             # set default retmode if not explicitly passed
120 1 50       13 $self->set_default_retmode unless $newmode;
121 1 50       5 $file && $self->id_file($file);
122 1         3 return;
123             }
124              
125              
126             sub reset_parameters {
127 0     0 1 0 my ($self, @args) = @_;
128             # is there a better way of doing this? probably, but this works...
129 0         0 my ($retmode,$file) = $self->_rearrange([qw(RETMODE ID_FILE)],@args);
130 0 0       0 map { defined $self->{"_$_"} && undef $self->{"_$_"} } (@PARAMS, qw(eutil correspondence history_cache request_cache));
  0         0  
131 0         0 $self->_set_from_args(\@args, -methods => [@PARAMS, qw(eutil correspondence history)]);
132 0 0       0 $self->eutil() || $self->eutil('efetch');
133 0 0       0 $self->set_default_retmode unless $retmode;
134 0 0       0 $file && $self->id_file($file);
135 0         0 $self->{'_statechange'} = 1;
136             }
137              
138              
139             sub carryover {
140 0     0 1 0 my ($self, $params, $mode) = @_;
141 0         0 my %allowed = map {$_ => 1} (@PARAMS, qw(eutil history correspondence));
  0         0  
142 0 0       0 if ($params) {
143 0 0       0 $self->throw("Must pass in an array ref of parameters") unless
144             ref($params) eq 'ARRAY';
145 0   0     0 my $mode ||= 'add';
146 0 0 0     0 $self->throw("Mode must be 'add' or 'delete'") unless $mode eq 'add' || $mode eq 'delete';
147 0 0       0 if (!scalar(@$params)) { # empty array ref
148 0         0 $self->{_carryover} = {};
149             } else {
150 0         0 for my $p (@$params) {
151 0 0       0 if (!exists $allowed{$p}) {
152 0         0 $self->warn("$p is not a recognized eutil parameter");
153 0         0 next;
154             }
155 0 0       0 if ($mode eq 'add') {
156 0         0 $self->{_carryover}->{$p} = 1;
157             } else {
158             delete $self->{_carryover}->{$p} if exists
159 0 0       0 $self->{_carryover}->{$p};
160             }
161             }
162             }
163             }
164 0   0     0 sort keys %{$self->{_carryover}} || ();
165             }
166              
167             sub _reset_except_carryover {
168 0     0   0 my $self = shift;
169             #for my $p (@PARAMS, qw(eutil correspondence history_cache request_cache)) {
170             # undef $self->{"_$p"} if defined $self->{"_$p"};
171             #}
172             }
173              
174              
175             sub request_mode {
176 1     1 1 3 my ($self, $mode) = @_;
177 1 50       3 $mode = uc $mode if defined $mode;
178 1         4 my $eutil = $self->eutil;
179 1 50       3 if ($mode) {
180 0         0 my %valid = map {$_ => 1} @{$MODE{$eutil}{mode}};
  0         0  
  0         0  
181             $self->throw("Mode $mode not supported for $eutil") unless
182 0 0       0 exists $valid{$mode};
183 0         0 $self->{_request_mode} = $mode;
184             }
185 1 50       5 return $self->{_request_mode} if $self->{_request_mode};
186             # let's try to make this a bit smarter...
187              
188             # If not explicitly set, in cases where
189             # the number of IDs is greater than 200, or the search term is longer than
190             # 200, use POST when available
191              
192 1 50       2 if (scalar(@{$MODE{$eutil}{mode}}) > 1) { # allows both GET and POST
  1         5  
193 1   50     31 my ($id, $term) = ($self->id || [], $self->term || '');
      50        
194 1 50 33     12 if (ref $id eq 'ARRAY' && scalar(@$id) > 200 || CORE::length($term) > 300) {
      33        
195 0         0 return 'POST'
196             }
197             }
198             # otherwise, fallback to default
199 1         4 $MODE{$eutil}{mode}[0]; # first is default
200             }
201              
202              
203             sub parameters_changed {
204 8     8 1 24 my ($self) = @_;
205 8         42 $self->{'_statechange'};
206             }
207              
208              
209             sub available_parameters {
210 4     4 1 12 my ($self, $type) = @_;
211 4   100     13 $type ||= 'all';
212 4 100       12 if ($type eq 'all') {
213 1         8 return @PARAMS;
214             } else {
215 3 50       8 $self->throw("$type parameters not supported") if !exists $MODE{$type};
216 3         7 return @{$MODE{$type}->{params}};
  3         27  
217             }
218             }
219              
220              
221             sub get_parameters {
222 2     2 1 6 my ($self, @args) = @_;
223 2         11 my ($type, $list, $join) = $self->_rearrange([qw(TYPE LIST JOIN_IDS)], @args);
224 2 50 33     42 $self->throw("Parameter list not an array ref") if $list && ref $list ne 'ARRAY';
225 2   100     9 $type ||= '';
226 2 50       9 my @final = $list ? grep {$self->can($_)} @{$list} : $self->available_parameters($type);
  0         0  
  0         0  
227 2         4 my @p;
228 2         6 for my $param (@final) {
229 47 100 66     256 if ($param eq 'id' && $self->id && $join) {
    100 100        
      66        
      100        
230 1         25 my $id = $self->id;
231 1 50 33     4 if ($self->correspondence && $self->eutil eq 'elink') {
232 0         0 for my $id_group (@{ $id }) {
  0         0  
233 0 0       0 if (ref($id_group) eq 'ARRAY') {
    0          
234 0         0 push @p, ('id' => join(q(,), @{ $id_group }));
  0         0  
235             }
236             elsif (!ref($id_group)) {
237 0         0 push @p, ('id' => $id_group);
238             }
239             else {
240 0         0 $self->throw("Unknown ID type: $id_group");
241             }
242             }
243             } else {
244             # add a check for undef
245             push @p, ref $id eq 'ARRAY' ?
246 1 50       6 ($param => join(',', grep {defined($_)} @{ $id })):
  20         40  
  1         4  
247             ($param => $id);
248             }
249             }
250             elsif ($param eq 'db' && $self->db && $join) {
251 1         24 my $db = $self->db;
252             push @p, (ref $db eq 'ARRAY') ?
253 1 50       7 ($param => join(',', @{ $db })) :
  0         0  
254             ($param => $db) ;
255             }
256             else {
257 45 100       122 push @p, ($param => $self->{"_$param"}) if defined $self->{"_$param"};
258             }
259             }
260 2         20 return @p;
261             }
262              
263              
264             sub to_string {
265 1     1 1 1048 my ($self, @args) = @_;
266             # calling to_uri changes the state
267 1 50 33     4 if ($self->parameters_changed || !defined $self->{'_string_cache'}) {
268 1         4 my $string = $self->to_request(@args)->uri->as_string;
269 1         21 $self->{'_statechange'} = 0;
270 1         4 $self->{'_string_cache'} = $string;
271             }
272 1         5 return $self->{'_string_cache'};
273             }
274              
275              
276             sub to_request {
277 2     2 1 6 my ($self, $type) = @_;
278 2 100 66     6 if ($self->parameters_changed || !defined $self->{'_request_cache'}) {
279 1         3 my $eutil = $self->eutil;
280 1 50       4 $self->throw("No eutil set") if !$eutil;
281             #set default retmode
282 1   33     8 $type ||= $eutil;
283 1         5 my ($location, $mode) = ($MODE{$eutil}->{location}, $self->request_mode);
284 1         2 my $request;
285 1         4 my $uri = URI->new($self->url_base_address . $location);
286 1 50       8173 if ($mode eq 'GET') {
    0          
287 1         6 $uri->query_form($self->get_parameters(-type => $type, -join_ids => 1) );
288 1         384 $request = HTTP::Request->new($mode => $uri);
289 1         122 $self->{'_request_cache'} = $request;
290             } elsif ($mode eq 'POST') {
291 0         0 $request = HTTP::Request->new($mode => $uri->as_string);
292 0         0 $uri->query_form($self->get_parameters(-type => $type, -join_ids => 1) );
293 0         0 $request->content_type('application/x-www-form-urlencoded');
294 0         0 $request->content($uri->query);
295 0         0 $self->{'_request_cache'} = $request;
296             } else {
297 0         0 $self->throw("Unrecognized request mode: $mode");
298             }
299 1         4 $self->{'_statechange'} = 0;
300 1         6 $self->{'_request_cache'} = $request;
301             }
302 2         9 return $self->{'_request_cache'};
303             }
304              
305              
306             sub eutil {
307 25     25 1 2289 my ($self, $eutil) = @_;
308 25 100       69 if ($eutil) {
309 7 50       35 $self->throw("$eutil not supported") if !exists $MODE{$eutil};
310 7 100 33     52 if (!defined $self->{'_eutil'} || ($self->{'_eutil'} && $self->{'_eutil'} ne $eutil)) {
      66        
311 6         19 $self->{'_eutil'} = $eutil;
312 6         21 $self->{'_statechange'} = 1;
313             }
314             }
315 25         99 return $self->{'_eutil'};
316             }
317              
318              
319             sub history {
320 0     0 1 0 my ($self, $history) = @_;
321 0 0       0 if ($history) {
322 0 0       0 $self->throw('Not a Bio::Tools::EUtilities::HistoryI object!') if
323             !$history->isa('Bio::Tools::EUtilities::HistoryI');
324 0         0 my ($webenv, $qkey) = $history->history;
325 0         0 $self->WebEnv($webenv);
326 0         0 $self->query_key($qkey);
327 0         0 $self->{'_statechange'} = 1;
328 0         0 $self->{'_history_cache'} = $history;
329             }
330 0         0 return $self->{'_history_cache'};
331             }
332              
333              
334             sub correspondence {
335 1     1 1 4 my ($self, $corr) = @_;
336 1 50       4 if (defined $corr) {
337 0         0 $self->{'_correspondence'} = $corr;
338 0         0 $self->{'_statechange'} = 1;
339             }
340 1         6 return $self->{'_correspondence'};
341             }
342              
343              
344             sub id_file {
345 0     0 1 0 my ($self, $file) = @_;
346 0 0       0 if ($file) {
347             # do this in a way that allows file, fh, IO::Handle
348 0         0 my $io = $self->_io;
349 0         0 $io->_initialize_io(-input => $file);
350 0         0 my @ids;
351 0         0 while (my $line = $io->_readline) {
352 0         0 chomp $line;
353 0         0 push @ids, $line;
354             }
355 0         0 $self->_io->close;
356 0         0 $self->id(\@ids);
357             }
358             }
359              
360              
361             {
362             my $HOSTBASE = 'https://eutils.ncbi.nlm.nih.gov/entrez/eutils/';
363              
364             sub url_base_address {
365 1     1 1 3 my ($self, $address) = @_;
366 1         8 return $HOSTBASE;
367             }
368             }
369              
370              
371             {
372             # default retmode if one is not supplied
373             my %NCBI_DATABASE = (
374             'protein' => 'text',
375             'nucleotide' => 'text',
376             'nuccore' => 'text',
377             'nucgss' => 'text',
378             'nucest' => 'text',
379             'structure' => 'text',
380             'genome' => 'text',
381             'gene' => 'asn1',
382             'journals' => 'text',
383             );
384              
385             sub set_default_retmode {
386 5     5 1 15 my $self = shift;
387 5 50       19 if ($self->eutil eq 'efetch') {
388 0   0     0 my $db = $self->db || return; # assume retmode will be set along with db
389 0 0       0 my $mode = exists $NCBI_DATABASE{$db} ? $NCBI_DATABASE{$db} : 'xml';
390 0         0 $self->retmode($mode);
391             } else {
392 5         127 $self->retmode('xml');
393             }
394             }
395             }
396              
397             sub _io {
398 0     0     my $self = shift;
399 0 0         if (!defined $self->{'_io'}) {
400 0           $self->{'_io'} = Bio::Root::IO->new();
401             }
402 0           return $self->{'_io'};
403             }
404              
405             1;
406              
407             __END__