Mercurial > repos > mahtabm > ensembl
comparison variant_effect_predictor/Bio/EnsEMBL/Funcgen/Storable.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 # | |
2 # Ensembl module for Bio::EnsEMBL::Funcgen::Storable | |
3 # | |
4 | |
5 =head1 LICENSE | |
6 | |
7 Copyright (c) 1999-2011 The European Bioinformatics Institute and | |
8 Genome Research Limited. All rights reserved. | |
9 | |
10 This software is distributed under a modified Apache license. | |
11 For license details, please see | |
12 | |
13 http://www.ensembl.org/info/about/code_licence.html | |
14 | |
15 =head1 CONTACT | |
16 | |
17 Please email comments or questions to the public Ensembl | |
18 developers list at <ensembl-dev@ebi.ac.uk>. | |
19 | |
20 Questions may also be sent to the Ensembl help desk at | |
21 <helpdesk@ensembl.org>. | |
22 | |
23 =head1 NAME | |
24 | |
25 Bio::EnsEMBL::Funcgen::Storable | |
26 | |
27 =head1 SYNOPSIS | |
28 | |
29 my $dbID = $storable_object->dbID(); | |
30 my $adaptor = $storable_object->adaptor(); | |
31 if($storable_object->is_stored($db_adaptor))) { | |
32 | |
33 } | |
34 =head1 DESCRIPTION | |
35 | |
36 This is a simple wrapper class to provide convenience methods for the StorableAdaptor. | |
37 Only get type methods have been implemented here to avoid obfuscating DB writes which | |
38 should only be done by the specific 'Storable'Adaptors. | |
39 | |
40 =head1 SEE ALSO | |
41 | |
42 Bio::EnsEMBL::Funcgen::DBSQL::BaseAdaptor | |
43 | |
44 =cut | |
45 | |
46 use strict; | |
47 use warnings; | |
48 | |
49 package Bio::EnsEMBL::Funcgen::Storable; | |
50 | |
51 | |
52 use Bio::EnsEMBL::Registry; | |
53 use Bio::EnsEMBL::Utils::Exception qw(throw warning); | |
54 use Bio::EnsEMBL::Utils::Argument qw(rearrange); | |
55 use Bio::EnsEMBL::Storable; | |
56 | |
57 use vars qw(@ISA); | |
58 | |
59 @ISA = qw(Bio::EnsEMBL::Storable); | |
60 | |
61 =head2 new | |
62 | |
63 Arg [-STATES] : Arrayref of states | |
64 Arg [-dbID] : database internal id | |
65 Example : none | |
66 Caller : internal calls | |
67 Description : create a new Storable object | |
68 Returntype : Bio::EnsEMBL::Storable | |
69 Exceptions : Adaptor not a Bio::EnsEMBL::Funcgen::DBSQL::BaseAdaptor | |
70 Status : Stable | |
71 | |
72 =cut | |
73 | |
74 sub new { | |
75 my $caller = shift; | |
76 | |
77 my $class = ref($caller) || $caller; | |
78 | |
79 my $self = $class->SUPER::new(@_); | |
80 | |
81 | |
82 my ($states, $assoc_ftypes) = rearrange(['STATES', 'ASSOCIATED_FEATURE_TYPES'] ,@_); | |
83 | |
84 if ($self->adaptor() && (! $self->adaptor->isa("Bio::EnsEMBL::Funcgen::DBSQL::BaseAdaptor"))){ | |
85 throw("Adaptor muct be a valid Bio::EnsEMBL::Funcgen::DBSQL::BaseAdaptor"); | |
86 } | |
87 | |
88 #will these break using _new_fast | |
89 #THerefore ResultFeature, Probe and ProbeFeature should not be Funcgen::Storables | |
90 | |
91 @{$self->{'states'}} = @$states if $states; | |
92 $self->associated_feature_types($assoc_ftypes) if(defined $assoc_ftypes); | |
93 | |
94 | |
95 return $self; | |
96 } | |
97 | |
98 | |
99 | |
100 | |
101 | |
102 | |
103 =head2 has_status | |
104 | |
105 Arg [1] : string - status e.g. IMPORTED, DISPLAYABLE | |
106 Example : if($experimental_chip->has_status('IMPORTED'){ ... skip import ... }; | |
107 Description: Tests whether storable has a given status | |
108 Returntype : BOOLEAN | |
109 Exceptions : Throws if not status is provided | |
110 Caller : general | |
111 Status : At risk | |
112 | |
113 =cut | |
114 | |
115 | |
116 | |
117 sub has_status{ | |
118 my ($self, $status) = @_; | |
119 | |
120 throw("Must provide a status to check") if ! $status; | |
121 | |
122 my @state = grep(/$status/, @{$self->get_all_states()}); | |
123 my $boolean = scalar(@state);#will be 0 or 1 due to table contraints | |
124 | |
125 return $boolean; | |
126 } | |
127 | |
128 | |
129 | |
130 #There is a potential to create an obj from scratch which may already exist in the db | |
131 #If we add a state to this (obj has not dbID so will not retrieve stored states) | |
132 # and then try and store it, this will result in adding the state to the previously stored obj. | |
133 #The behaviour is silent and could cause problems. | |
134 | |
135 #To resolve this the adaptor implementations must throw if we find a matching object | |
136 #We must force the user to generate the obj from the db(use recover) rather than from scratch | |
137 #to make them aware of the situation. This is useful to protect objects where we do not want to overwrite previous data | |
138 #e.g. experiment, experimental_chip, channel | |
139 #For objects which are routinely resued, we must make sure we always try the db first(not just when recover is set) | |
140 #Then warn/throw if there are differing attributes | |
141 | |
142 #This is not possible for set objects, but is not a problem as it will just create another set entry rather than overwriting | |
143 #All update/store_states methods should be okay so long as we have a dbID first. | |
144 | |
145 | |
146 | |
147 | |
148 =head2 get_all_states | |
149 | |
150 Example : my @ec_states = @{$experimental_chip->get_all_states()}; | |
151 Description: Retrieves all states from DB and merges with current states array | |
152 Returntype : LISTREF | |
153 Exceptions : None | |
154 Caller : general | |
155 Status : At risk | |
156 | |
157 =cut | |
158 | |
159 | |
160 | |
161 sub get_all_states{ | |
162 my ($self) = @_; | |
163 | |
164 my %states; | |
165 | |
166 #This could miss states in the DB for storables which have been created and had states added | |
167 #but already exist with states in the DB | |
168 #The way to get around this is to throw if we try and store an object without a dbID which matches | |
169 #something in the DB. | |
170 #Remove func in adaptors(ec and channel only?) to automatically use prestored objects, throw instead if no dbID and matches. | |
171 #force use of recover to retrieve object from DB and then skip to relevant step based on states. | |
172 #Have states => next method hash in Importer/ArrayDefs? | |
173 | |
174 | |
175 | |
176 if($self->is_stored($self->adaptor->db()) && ! $self->{'states'}){ | |
177 @{$self->{'states'}} = @{$self->adaptor->fetch_all_states($self)}; | |
178 } | |
179 | |
180 return $self->{'states'}; | |
181 } | |
182 | |
183 | |
184 =head2 add_status | |
185 | |
186 Example : $ec->add_state('DISPLAYABLE'); | |
187 Description: Adds a state to a new or previously stored Storable | |
188 Returntype : None | |
189 Exceptions : Throws if no status supplied | |
190 Caller : general | |
191 Status : At risk | |
192 | |
193 =cut | |
194 | |
195 | |
196 | |
197 sub add_status{ | |
198 my ($self, $status) = @_; | |
199 | |
200 throw("Must pass a status to add e.g. 'DISPLAYABLE'") if ! $status; | |
201 | |
202 | |
203 | |
204 #this does not resolve the problem!!??? | |
205 #can add a status to an unstored object which | |
206 | |
207 if($self->adaptor && $self->is_stored($self->adaptor->db()) && ! $self->{'states'}){ | |
208 @{$self->{'states'}} = @{$self->adaptor->fetch_all_states($self)}; | |
209 } | |
210 | |
211 push @{$self->{'states'}}, $status; | |
212 | |
213 return; | |
214 } | |
215 | |
216 sub is_displayable{ | |
217 my $self = shift; | |
218 | |
219 return $self->has_status('DISPLAYABLE'); | |
220 } | |
221 | |
222 #These DBEntry methods are here to enable xrefs to FeatureType, Probe, ProbeSet & ProbeFeature | |
223 #They only work as SetFeature has Storable as the second element of @ISA and Bio::EnsEMBL::Feature | |
224 #get_all_DBEntries be incorporated into Bio::EnsEMBL::Storable as generic method | |
225 #With the other wrapper methods in the Storables of the non-core APIs? | |
226 #Or can these be moved to core as a supra core class? | |
227 #i.e. Is common to all non-core APIs but not relevant for core? | |
228 #Can we bring these together to stop code propogation? | |
229 | |
230 | |
231 =head2 get_all_Gene_DBEntries | |
232 | |
233 Example : my @gene_dbentries = @{ $storable->get_all_Gene_DBEntries }; | |
234 Description: Retrieves Ensembl Gene DBEntries (xrefs) for this Storable. | |
235 This does _not_ include the corresponding translations | |
236 DBEntries (see get_all_DBLinks). | |
237 | |
238 This method will attempt to lazy-load DBEntries from a | |
239 database if an adaptor is available and no DBEntries are present | |
240 on the transcript (i.e. they have not already been added or | |
241 loaded). | |
242 Returntype : Listref of Bio::EnsEMBL::DBEntry objects | |
243 Exceptions : none | |
244 Caller : general | |
245 Status : at risk | |
246 | |
247 =cut | |
248 | |
249 #Need to add optional Transcript/Gene param so we can filter | |
250 #Filter here or would be better to restrict in sql query ni DBEntryAdaptor? | |
251 | |
252 sub get_all_Gene_DBEntries { | |
253 my $self = shift; | |
254 | |
255 | |
256 #We wouldn't need this if we made the xref schema multi species | |
257 #my $species = $self->adaptor->db->species; | |
258 my $species = Bio::EnsEMBL::Registry->get_alias($self->adaptor->db->species); | |
259 | |
260 if(!$species){ | |
261 throw('You must specify a DBAdaptor -species to retrieve DBEntries based on the external_db.db_name'); | |
262 } | |
263 | |
264 #safety in case we get Homo sapiens | |
265 ($species = lc($species)) =~ s/ /_/; | |
266 | |
267 | |
268 | |
269 return $self->get_all_DBEntries($species.'_core_Gene'); | |
270 } | |
271 | |
272 =head2 get_all_Transcript_DBEntries | |
273 | |
274 Arg[0] : optional - Bio::EnsEMBL::Transcript to filter DBEntries on. | |
275 Example : my @transc_dbentries = @{ $set_feature->get_all_Transcript_DBEntries }; | |
276 Description: Retrieves ensembl Transcript DBEntries (xrefs) for this Storable. | |
277 This does _not_ include the corresponding translations | |
278 DBEntries (see get_all_DBLinks). | |
279 | |
280 This method will attempt to lazy-load DBEntries from a | |
281 database if an adaptor is available and no DBEntries are present | |
282 on the Storable (i.e. they have not already been added or | |
283 loaded). | |
284 Returntype : Listref of Bio::EnsEMBL::DBEntry objects | |
285 Exceptions : none | |
286 Caller : general | |
287 Status : at risk | |
288 | |
289 =cut | |
290 | |
291 #change the to ensembl_core when we implement Gene/Transcript/Protein|Translation links on the same external_db | |
292 | |
293 sub get_all_Transcript_DBEntries { | |
294 my ($self, $transcript) = @_; | |
295 | |
296 #We wouldn't need this if we made the xref schema multi species | |
297 my $species = Bio::EnsEMBL::Registry->get_alias($self->adaptor->db->species); | |
298 #Need to make sure this is latin name | |
299 | |
300 | |
301 if(!$species){ | |
302 throw('You must specify a DBAdaptor -species to retrieve DBEntries based on the external_db.db_name'); | |
303 } | |
304 | |
305 #safety in case we get Homo sapiens | |
306 #($species = lc($species)) =~ s/ /_/; | |
307 | |
308 my $dbes = $self->get_all_DBEntries($species.'_core_Transcript'); | |
309 | |
310 #This needs to be moved to the DBEntryAdaptor and restrict the query using the | |
311 #dbprimary_acc | |
312 | |
313 if($transcript){ | |
314 my $sid = $transcript->stable_id; | |
315 | |
316 #Test for sid here? | |
317 | |
318 if(ref($transcript) && $transcript->isa('Bio::EnsEMBL::Transcript')){ | |
319 my @dbes; | |
320 | |
321 foreach my $dbe(@$dbes){ | |
322 if($dbe->primary_id eq $sid){ | |
323 push @dbes, $dbe; | |
324 } | |
325 } | |
326 $dbes = \@dbes; | |
327 } | |
328 else{ | |
329 throw('Transcript argument must be a valid Bio::EnsEMBL::Transcript'); | |
330 } | |
331 } | |
332 | |
333 | |
334 return $dbes; | |
335 } | |
336 | |
337 | |
338 =head2 get_all_UnmappedObjects | |
339 | |
340 Example : my @uos = @{$storable->get_all_UnmappedObjects }; | |
341 Description: Retrieves UnamappedObjects for this Storable. | |
342 Returntype : arrayref of Bio::EnsEMBL::UnmappedObject objects | |
343 Exceptions : none | |
344 Caller : general | |
345 Status : At risk - move to Bio::Ensembl::Storable? | |
346 | |
347 =cut | |
348 | |
349 sub get_all_UnmappedObjects{ | |
350 my $self = shift; | |
351 #Do we want to add external_db or analysis param here? | |
352 | |
353 my $class = ref($self); | |
354 $class =~ s/.*:://; | |
355 | |
356 return $self->adaptor->db->get_UnmappedObjectAdaptor->fetch_all_by_object_type_id($class, $self->dbID); | |
357 } | |
358 | |
359 | |
360 =head2 get_all_DBEntries | |
361 | |
362 Arg[1] : string - External DB name e.g. ensembl_core_Gene | |
363 Arg[2] : string - External DB type | |
364 Example : my @dbentries = @{ $set_feature->get_all_DBEntries }; | |
365 Description: Retrieves DBEntries (xrefs) for this SetFeature. | |
366 This does _not_ include the corresponding translations | |
367 DBEntries (see get_all_DBLinks). | |
368 | |
369 This method will attempt to lazy-load DBEntries from a | |
370 database if an adaptor is available and no DBEntries are present | |
371 on the SetFeature (i.e. they have not already been added or | |
372 loaded). | |
373 Returntype : Listref of Bio::EnsEMBL::DBEntry objects | |
374 Exceptions : none | |
375 Caller : general, get_all_DBLinks | |
376 Status : Stable - at risk move to storable | |
377 | |
378 =cut | |
379 | |
380 | |
381 #We could add 3rd arg here which would be xref(info_)type e.g. Gene/Transcript etc. | |
382 #Move info_type to ox.linkage_type to sit along side linkage_annotated | |
383 | |
384 | |
385 sub get_all_DBEntries { | |
386 my $self = shift; | |
387 my $ex_db_exp = shift; | |
388 my $ex_db_type = shift; | |
389 | |
390 my $cache_name = "dbentries"; | |
391 | |
392 if(defined($ex_db_exp)){ | |
393 $cache_name .= $ex_db_exp; | |
394 } | |
395 if(defined($ex_db_type)){ | |
396 $cache_name .= $ex_db_type; | |
397 } | |
398 | |
399 #Need to add tests for valid objects for xrefs | |
400 | |
401 # if not cached, retrieve all of the xrefs for this gene | |
402 | |
403 #This is not using the caching optimally | |
404 #It seems for naive(ex_db_exp,ex_db_type) queries we create a naive cache | |
405 #This means that further more specific queries will make another query and not use the cache | |
406 | |
407 | |
408 if( (! defined $self->{$cache_name}) && $self->adaptor() ){ | |
409 | |
410 my @tables = $self->adaptor->_tables; | |
411 @tables = split/_/, $tables[0]->[0];#split annotated_feature | |
412 my $object_type = join('', (map ucfirst($_), @tables));#change to AnnotatedFeature | |
413 | |
414 $self->{$cache_name} = | |
415 $self->adaptor->db->get_DBEntryAdaptor->_fetch_by_object_type($self->dbID(), $object_type, $ex_db_exp, $ex_db_type); | |
416 } | |
417 elsif( ! defined $self->{$cache_name} ){ | |
418 throw('You must have set and adaptor to be able to get_all_DBEntries'); | |
419 } | |
420 | |
421 | |
422 $self->{$cache_name} ||= []; | |
423 | |
424 return $self->{$cache_name}; | |
425 } | |
426 | |
427 | |
428 =head2 add_DBEntry | |
429 | |
430 Arg [1] : Bio::EnsEMBL::DBEntry $dbe | |
431 The dbEntry to be added | |
432 Example : my $dbe = Bio::EnsEMBL::DBEntry->new(...); | |
433 $transcript->add_DBEntry($dbe); | |
434 Description: Associates a DBEntry with this object. Note that adding | |
435 DBEntries will prevent future lazy-loading of DBEntries for this | |
436 storable (see get_all_DBEntries). | |
437 Returntype : none | |
438 Exceptions : thrown on incorrect argument type | |
439 Caller : general | |
440 Status : Stable | |
441 | |
442 =cut | |
443 | |
444 sub add_DBEntry { | |
445 my $self = shift; | |
446 my $dbe = shift; | |
447 | |
448 unless($dbe && ref($dbe) && $dbe->isa('Bio::EnsEMBL::DBEntry')) { | |
449 throw('Expected DBEntry argument'); | |
450 } | |
451 | |
452 $self->{'dbentries'} ||= []; | |
453 push @{$self->{'dbentries'}}, $dbe; | |
454 } | |
455 | |
456 | |
457 =head2 associated_feature_types | |
458 | |
459 Example : my @associated_ftypes = @{$feature->associated_feature_types()}; | |
460 Description: Getter/Setter for other associated FeatureTypes. | |
461 Returntype : ARRAYREF of Bio::EnsEMBL::Funcgen:FeatureType objects | |
462 Exceptions : None | |
463 Caller : General | |
464 Status : At risk | |
465 | |
466 =cut | |
467 | |
468 sub associated_feature_types{ | |
469 my ($self, $ftypes) = @_; | |
470 | |
471 #Lazy load as we don't want to have to do a join on all features when most will not have any | |
472 | |
473 | |
474 if(defined $ftypes){ | |
475 | |
476 if(ref($ftypes) eq 'ARRAY'){ | |
477 | |
478 foreach my $ftype(@$ftypes){ | |
479 | |
480 if( ! $ftype->isa('Bio::EnsEMBL::Funcgen::FeatureType') ){ | |
481 throw('You must pass and ARRAYREF of stored Bio::EnsEMBL::Funcgen::FeatureType objects'); | |
482 } | |
483 #test is stored in adaptor | |
484 } | |
485 | |
486 if(defined $self->{'associated_feature_types'}){ | |
487 warn('You are overwriting associated feature types'); | |
488 #we could simply add the new ones and make them NR. | |
489 } | |
490 | |
491 $self->{'associated_feature_types'} = $ftypes; | |
492 } | |
493 else{ | |
494 throw('You must pass and ARRAYREF of stored Bio::EnsEMBL::Funcgen::FeatureType objects'); | |
495 } | |
496 } | |
497 | |
498 | |
499 if(! defined $self->{'associated_feature_types'}){ | |
500 #This will fail if we have not stored yet | |
501 | |
502 if(defined $self->adaptor){ | |
503 $self->{'associated_feature_types'} = $self->adaptor->db->get_FeatureTypeAdaptor->fetch_all_by_association($self); | |
504 } | |
505 | |
506 } | |
507 | |
508 | |
509 #This has the potential to return undef, or an arrayref which may be empty. | |
510 return $self->{'associated_feature_types'}; | |
511 } | |
512 | |
513 | |
514 | |
515 | |
516 | |
517 | |
518 | |
519 1; |