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;