ensembl-hive  2.7.0
FullIdCache.pm
Go to the documentation of this file.
1 =head1 LICENSE
2 
3 See the NOTICE file distributed with this work for additional information
4 regarding copyright ownership.
5 
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
9 
10  http://www.apache.org/licenses/LICENSE-2.0
11 
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17 
18 =cut
19 
20 =head1 CONTACT
21 
22  Please email comments or questions to the public Ensembl
23  developers list at <http://lists.ensembl.org/mailman/listinfo/dev>.
24 
25  Questions may also be sent to the Ensembl help desk at
26  <http://www.ensembl.org/Help/Contact>.
27 
28 =cut
29 
30 =head1 NAME
31 
32 Bio::EnsEMBL::DBSQL::Support::FullIdCache - ID based caching using all available values
33 
34 =head1 SYNOPSIS
35 
36  my $cache = Bio::EnsEMBL::DBSQL::Support::FullIdCache->new($adaptor);
37  my $obj = $cache->get(21);
38 
39 =head1 DESCRIPTION
40 
41 An implementation of caching which uses a raw hash to hold all available
42 values from an adaptor. Useful for working with a controlled vocabulary
43 table where cardinality is low.
44 
45 Provides extra functionality to compute additional lookup keys.
46 
47 =head1 METHODS
48 
49 =cut
50 
51 package Bio::EnsEMBL::DBSQL::Support::FullIdCache;
52 
53 use strict;
54 use warnings;
56 use Bio::EnsEMBL::Utils::Exception qw/throw/;
57 
58 =head2 build_cache
59 
60  Description: Builds a cache keyed by dbID and populated from a call
61  using C<generic_fetch()>
62  Returntype : Hash
63  Exceptions : None
64  Caller : BaseAdaptors
65  Status : Beta
66 
67 =cut
68 
69 sub build_cache {
70  my ($self) = @_;
71  my $adaptor = $self->adaptor();
72  my %cache;
73  my $objects = $adaptor->generic_fetch();
74  foreach my $object (@{$objects}) {
75  my $key = $object->dbID();
76  $cache{$key} = $object;
77  #Add to additional lookup
78  $self->add_to_additional_lookups($key, $object);
79  }
80  return \%cache;
81 }
82 
83 ########### Additional lookup code
84 
85 sub put {
86  my ($self, $key, $object) = @_;
87  my $old = $self->SUPER::put($key, $object);
88  #Add to additional lookup
89  $self->remove_from_additional_lookup($key, $old) if $old;
90  $self->add_to_additional_lookups($key, $object);
91  return $old if $old;
92  return;
93 }
94 
95 sub remove {
96  my ($self, $key) = @_;
97  my $old = $self->SUPER::remove($key);
98  if($old) {
99  #Remove it from the additional lookup
100  $self->remove_from_additional_lookup($key, $old);
101  return $old;
102  }
103  return;
104 }
105 
106 sub clear_cache {
107  my ($self) = @_;
108  $self->delete_cache();
109  #Remove the additional lookup hash contents
110  delete $self->{_additional_lookup};
111  return;
112 }
113 
114 =head2 get_by_additional_lookup
115 
116  Arg [1] : String key of the lookup to search for the value in
117  Arg [2] : String value to search for. We expect exact lookups in the hash
118  Description : Returns the object linked to the value in the specified lookup.
119  Example : my $analysis = $cache->get_by_additional_lookup('logic_name', 'xrefchecksum');
120  Returntype : Object a single object
121  Exceptions : Throws an exception if there are more than one ID linked to the
122  value lookup. Also thrown if additional lookups are not supported
123  Caller : BaseAdaptors
124  Status : Beta
125 
126 =cut
127 
128 sub get_by_additional_lookup {
129  my ($self, $key, $value) = @_;
130  $self->cache(); # trigger cache building
131  my $additional_lookup = $self->_additional_lookup();
132  if(exists $additional_lookup->{$key}) {
133  if(exists $additional_lookup->{$key}->{$value}) {
134  my $ids = $additional_lookup->{$key}->{$value};
135  my $size = scalar(@{$ids});
136  if($size > 1) {
137  throw "The lookup $key and search value $value has more than one value attached. Use get_all_by_additional_lookup() instead to fetch";
138  }
139  elsif($size == 1) {
140  return $self->get($ids->[0]);
141  }
142  }
143  }
144  return;
145 }
146 
147 =head2 get_all_by_additional_lookup
148 
149  Arg [1] : String key of the lookup to search for the value in
150  Arg [2] : String value to search for. We expect exact lookups in the hash
151  Description : Returns an array of all the objects linked to the value
152  in the specified lookup.
153  Example : my $array = $cache->get_all_by_additional_lookup('logic_name', 'xrefchecksum');
154  Returntype : ArrayRef of objects keyed agains the second argument
155  Exceptions : Throws an exception if there are more than one ID linked to the
156  value lookup. Also thrown if additional lookups are not supported
157  Caller : BaseAdaptors
158  Status : Beta
159 
160 =cut
161 
162 sub get_all_by_additional_lookup {
163  my ($self, $key, $value) = @_;
164  $self->cache(); # trigger cache building
165  my $additional_lookup = $self->_additional_lookup();
166  if(exists $additional_lookup->{$key}) {
167  if(exists $additional_lookup->{$key}->{$value}) {
168  my $ids = $additional_lookup->{$key}->{$value};
169  return $self->get_by_list($ids);
170  }
171  }
172  return [];
173 }
174 
175 =head2 remove_from_additional_lookup
176 
177  Arg [1] : String The lookup key to remove from the additional lookup hash
178  Arg [2] : Object The object to remove from the additional lookup hash
179  Description : Re-computes the additional keys for this object
180  Example : $cache->remove_Object_from_additional_lookup($lookup_key, $object);
181  Returntype : None
182  Exceptions : Thrown if we do not support additional lookups
183  Caller : BaseAdaptors
184  Status : Beta
185 
186 =cut
187 
188 sub remove_from_additional_lookup {
189  my ($self, $lookup_key, $object) = @_;
190 
191  # Compute the keys
192  my $keys = $self->compute_keys($object);
193  return if scalar(keys %{$keys}) == 0;
194 
195  my $additional_lookup = $self->_additional_lookup();
196 
197  foreach my $key (keys %{$keys}) {
198  my $value = $keys->{$key};
199 
200  #Only remove if we had originally stored this as an
201  #additional lookup
202  if(exists $additional_lookup->{$key}) {
203  if(exists $additional_lookup->{$key}->{$value}) {
204 
205  #Get the object ID & lookup the array of DBIDs
206  my $lookup_keys = $additional_lookup->{$key}->{$value};
207  my $length = scalar(@{$lookup_keys});
208  for(my $i = 0; $i < $length; $i++) {
209  if($lookup_keys->[$i] == $lookup_key) {
210  #remove the 1 lookup key from the array and then terminate the
211  #loop as we found our value
212  splice(@{$lookup_keys}, $i, 1);
213  last;
214  }
215  }
216 
217  #If the size has hit 0 then delete the array
218  if(scalar(@{$lookup_keys}) == 0) {
219  delete $additional_lookup->{$key}->{$value};
220  }
221  }
222  }
223  }
224 
225  return;
226 }
227 
228 =head2 compute_keys
229 
230  Arg [1] : Object The object to compute keys from
231  Description : Override to provide support for additional key lookup. The
232  keys of the hash should represent the lookup name and the
233  value is the computed key.
234  Example : Example of returning hash not of its usage. Proposed Analysis encoding
235  { logic_name => 'xrefalignment', display_label => 'Xref Alignment'}
236  Returntype : HashRef key is the lookup name and value is the computed key
237  Exceptions : none
238  Caller : BaseAdaptors
239  Status : Beta
240 
241 =cut
242 
243 sub compute_keys {
244  my ($self, $object) = @_;
245  return {};
246 }
247 
248 =head2 add_to_additional_lookups
249 
250  Arg [1] : String The key used in the primary lookup hash. Normally
251  a DB identifier
252  Arg [2] : Object The object to add to the additional lookups
253  Description : Internally calls the C<compute_keys()> method and adds
254  the object to the C<_additional_lookup()> hash.
255  Returntype : None
256  Exceptions : Thrown if additional lookups are not supported
257  Caller : BaseAdaptors
258  Status : Beta
259 
260 =cut
261 
262 sub add_to_additional_lookups {
263  my ($self, $lookup_key, $object) = @_;
264  my $keys = $self->compute_keys($object);
265  return if scalar(keys %{$keys}) == 0;
266  my $additional_lookup = $self->_additional_lookup();
267  foreach my $key (keys %{$keys}) {
268  my $value = $keys->{$key};
269  push(@{$additional_lookup->{$key}->{$value}}, $lookup_key);
270  }
271  return;
272 }
273 
274 =head2 _additional_lookup
275 
276  Description : Returns the additional lookup hash
277  Example : Example of additional hash structure (key is
278  lookup name, second key is value to search for
279  and value is an array of dbIDs)
280  {
281  logic_name => {
282  xrefalignment => [1]
283  },
284  display_label => {
285  'Xref Alignment' => [1]
286  }
287  }
288  Returntype : HashRef
289  Exceptions : none
290  Caller : BaseAdaptors
291  Status : Beta
292 
293 =cut
294 
295 sub _additional_lookup {
296  my ($self) = @_;
297  $self->{_additional_lookup} ||= {};
298  return $self->{_additional_lookup};
299 }
300 
301 1;
usage
public usage()
Bio::EnsEMBL::DBSQL::Support::BaseCache
Definition: BaseCache.pm:55
Bio::EnsEMBL::DBSQL::Support::BaseCache::new
public Bio::EnsEMBL::DBSQL::Support::BaseCache new()
Bio::EnsEMBL::Utils::Exception
Definition: Exception.pm:68
Bio::EnsEMBL::DBSQL::Support::BaseCache::get
public Scalar get()
Bio::EnsEMBL::DBSQL::Support::FullIdCache
Definition: FullIdCache.pm:22