0
|
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::ExonAdaptor - An adaptor responsible for the retrieval and
|
|
24 storage of exon objects
|
|
25
|
|
26 =head1 SYNOPSIS
|
|
27
|
|
28 my $exon_adaptor = $registry->get_adaptor( 'Human', 'Core', 'Exon' );
|
|
29
|
|
30 my $exon = $exon_adaptor->fetch_by_dbID($dbID);
|
|
31
|
|
32 =head1 DESCRIPTION
|
|
33
|
|
34 The ExonAdaptor is responsible for retrieving and storing Exon objects
|
|
35 from an Ensembl database. Most of the ExonAdaptor functionality is
|
|
36 inherited from the B<Bio::EnsEMBL::DBSQL::BaseFeatureAdaptor> class.
|
|
37
|
|
38 =head1 METHODS
|
|
39
|
|
40 =cut
|
|
41
|
|
42 package Bio::EnsEMBL::DBSQL::ExonAdaptor;
|
|
43
|
|
44 use strict;
|
|
45
|
|
46 use Bio::EnsEMBL::DBSQL::BaseFeatureAdaptor;
|
|
47 use Bio::EnsEMBL::Exon;
|
|
48 use Bio::EnsEMBL::Utils::Exception qw( warning throw deprecate );
|
|
49
|
|
50 use vars qw( @ISA );
|
|
51 @ISA = qw( Bio::EnsEMBL::DBSQL::BaseFeatureAdaptor );
|
|
52
|
|
53
|
|
54 #_tables
|
|
55 #
|
|
56 # Arg [1] : none
|
|
57 # Example : none
|
|
58 # Description: PROTECTED implementation of superclass abstract method
|
|
59 # returns the names, aliases of the tables to use for queries
|
|
60 # Returntype : list of listrefs of strings
|
|
61 # Exceptions : none
|
|
62 # Caller : internal
|
|
63
|
|
64 sub _tables {
|
|
65 my $self = shift;
|
|
66
|
|
67 # Allow the table definition to be overridden by certain methods.
|
|
68 if ( defined( $self->{'tables'} ) ) {
|
|
69 return @{ $self->{'tables'} };
|
|
70 }
|
|
71
|
|
72 return ( [ 'exon', 'e' ] );
|
|
73 }
|
|
74
|
|
75
|
|
76 # _columns
|
|
77 #
|
|
78 # Arg [1] : none
|
|
79 # Example : none
|
|
80 # Description: PROTECTED implementation of superclass abstract method
|
|
81 # returns a list of columns to use for queries
|
|
82 # Returntype : list of strings
|
|
83 # Exceptions : none
|
|
84 # Caller : internal
|
|
85
|
|
86 sub _columns {
|
|
87 my $self = shift;
|
|
88
|
|
89 my $created_date =
|
|
90 $self->db->dbc->from_date_to_seconds("created_date");
|
|
91 my $modified_date =
|
|
92 $self->db->dbc->from_date_to_seconds("modified_date");
|
|
93
|
|
94 return (
|
|
95 'e.exon_id', 'e.seq_region_id', 'e.seq_region_start',
|
|
96 'e.seq_region_end', 'e.seq_region_strand', 'e.phase',
|
|
97 'e.end_phase', 'e.is_current', 'e.is_constitutive',
|
|
98 'e.stable_id', 'e.version', $created_date,
|
|
99 $modified_date
|
|
100 );
|
|
101 }
|
|
102
|
|
103
|
|
104
|
|
105 # _final_clause
|
|
106 #
|
|
107 # Arg [1] : none
|
|
108 # Example : none
|
|
109 # Description: PROTECTED implementation of superclass abstract method
|
|
110 # returns a default end for the SQL-query (ORDER BY)
|
|
111 # Returntype : string
|
|
112 # Exceptions : none
|
|
113 # Caller : internal
|
|
114
|
|
115 sub _final_clause {
|
|
116 my $self = shift;
|
|
117 return $self->{'final_clause'} || '';
|
|
118 }
|
|
119
|
|
120
|
|
121 sub fetch_all {
|
|
122 my ($self) = @_;
|
|
123
|
|
124 my $constraint = 'e.is_current = 1';
|
|
125 my @exons = @{ $self->generic_fetch($constraint) };
|
|
126 return \@exons ;
|
|
127 }
|
|
128
|
|
129 =head2 fetch_by_stable_id
|
|
130
|
|
131 Arg [1] : string $stable_id
|
|
132 the stable id of the exon to retrieve
|
|
133 Example : $exon = $exon_adaptor->fetch_by_stable_id('ENSE0000988221');
|
|
134 Description: Retrieves an Exon from the database via its stable id
|
|
135 Returntype : Bio::EnsEMBL::Exon in native coordinates.
|
|
136 Exceptions : none
|
|
137 Caller : general
|
|
138 Status : Stable
|
|
139
|
|
140 =cut
|
|
141
|
|
142 sub fetch_by_stable_id {
|
|
143 my ($self, $stable_id) = @_;
|
|
144
|
|
145 my $constraint = "e.stable_id = ? AND e.is_current = 1";
|
|
146
|
|
147 $self->bind_param_generic_fetch($stable_id,SQL_VARCHAR);
|
|
148 my ($exon) = @{ $self->generic_fetch($constraint) };
|
|
149
|
|
150 return $exon;
|
|
151 }
|
|
152
|
|
153
|
|
154 =head2 fetch_all_versions_by_stable_id
|
|
155
|
|
156 Arg [1] : String $stable_id
|
|
157 The stable ID of the exon to retrieve
|
|
158 Example : my $exon = $exon_adaptor->fetch_all_version_by_stable_id
|
|
159 ('ENSE00000309301');
|
|
160 Description : Similar to fetch_by_stable_id, but retrieves all versions of an
|
|
161 exon stored in the database.
|
|
162 Returntype : listref of Bio::EnsEMBL::Exon objects
|
|
163 Exceptions : if we cant get the gene in given coord system
|
|
164 Caller : general
|
|
165 Status : At Risk
|
|
166
|
|
167 =cut
|
|
168
|
|
169 sub fetch_all_versions_by_stable_id {
|
|
170 my ($self, $stable_id) = @_;
|
|
171
|
|
172 my $constraint = "e.stable_id = ?";
|
|
173
|
|
174 $self->bind_param_generic_fetch($stable_id,SQL_VARCHAR);
|
|
175
|
|
176 return $self->generic_fetch($constraint);
|
|
177 }
|
|
178
|
|
179
|
|
180 =head2 fetch_all_by_Transcript
|
|
181
|
|
182 Arg [1] : Bio::EnsEMBL::Transcript $transcript
|
|
183 Example : none
|
|
184 Description: Retrieves all Exons for the Transcript in 5-3 order
|
|
185 Returntype : listref Bio::EnsEMBL::Exon on Transcript slice
|
|
186 Exceptions : throws if transcript has no slice
|
|
187 Caller : Transcript->get_all_Exons()
|
|
188 Status : Stable
|
|
189
|
|
190 =cut
|
|
191
|
|
192 sub fetch_all_by_Transcript {
|
|
193 my ( $self, $transcript ) = @_;
|
|
194
|
|
195 my $tslice = $transcript->slice();
|
|
196 my $slice;
|
|
197
|
|
198 if ( !defined($tslice) ) {
|
|
199 throw("Transcript must have attached slice to retrieve exons.");
|
|
200 }
|
|
201
|
|
202 # use a small slice the same size as the transcript
|
|
203 if ( !$tslice->is_circular() ) {
|
|
204 $slice =
|
|
205 $self->db()->get_SliceAdaptor()->fetch_by_Feature($transcript);
|
|
206 } else {
|
|
207 # Circular.
|
|
208 $slice = $tslice;
|
|
209 }
|
|
210
|
|
211 # Override the tables definition to provide an additional join to the
|
|
212 # exon_transcript table. For efficiency we cannot afford to have this
|
|
213 # in as a left join every time.
|
|
214 my @tables = $self->_tables();
|
|
215
|
|
216 # Be extra cautious so that we do not add 'exon_transcript' twice.
|
|
217 my $found = 0;
|
|
218 foreach my $table (@tables) {
|
|
219 if ( $table->[0] eq 'exon_transcript' ) {
|
|
220 $found = 1;
|
|
221 last;
|
|
222 }
|
|
223 }
|
|
224 if ( !$found ) {
|
|
225 push @tables, [ 'exon_transcript', 'et' ];
|
|
226 }
|
|
227
|
|
228 $self->{'tables'} = \@tables;
|
|
229 $self->{'final_clause'} = "ORDER BY et.transcript_id, et.rank";
|
|
230
|
|
231 my $constraint =
|
|
232 "et.transcript_id = "
|
|
233 . $transcript->dbID()
|
|
234 . " AND e.exon_id = et.exon_id";
|
|
235
|
|
236 # fetch all of the exons
|
|
237 my $exons = $self->fetch_all_by_Slice_constraint($slice, $constraint);
|
|
238
|
|
239 # un-override the table definition
|
|
240 delete( $self->{'tables'} );
|
|
241 delete( $self->{'final_clause'} );
|
|
242
|
|
243 # remap exon coordinates if necessary
|
|
244 if($slice->name() ne $tslice->name()) {
|
|
245 my @out;
|
|
246 foreach my $ex (@$exons) {
|
|
247 push @out, $ex->transfer($tslice);
|
|
248 }
|
|
249 $exons = \@out;
|
|
250 }
|
|
251
|
|
252 return $exons;
|
|
253 }
|
|
254
|
|
255
|
|
256 =head2 store
|
|
257
|
|
258 Arg [1] : Bio::EnsEMBL::Exon $exon
|
|
259 the exon to store in this database
|
|
260 Example : $exon_adaptor->store($exon);
|
|
261 Description: Stores an exon in the database
|
|
262 Returntype : none
|
|
263 Exceptions : thrown if exon (or component exons) do not have a contig_id
|
|
264 or if $exon->start, $exon->end, $exon->strand, or $exon->phase
|
|
265 are not defined or if $exon is not a Bio::EnsEMBL::Exon
|
|
266 Caller : general
|
|
267 Status : Stable
|
|
268
|
|
269 =cut
|
|
270
|
|
271 sub store {
|
|
272 my ($self, $exon) = @_;
|
|
273
|
|
274 if( ! $exon->isa('Bio::EnsEMBL::Exon') ) {
|
|
275 throw("$exon is not a EnsEMBL exon - not storing.");
|
|
276 }
|
|
277
|
|
278 my $db = $self->db();
|
|
279
|
|
280 if($exon->is_stored($db)) {
|
|
281 return $exon->dbID();
|
|
282 }
|
|
283
|
|
284 if( ! $exon->start || ! $exon->end ||
|
|
285 ! $exon->strand || ! defined $exon->phase ) {
|
|
286 throw("Exon does not have all attributes to store");
|
|
287 }
|
|
288
|
|
289 # Default to is_current = 1 if this attribute is not set
|
|
290 my $is_current = $exon->is_current();
|
|
291 if ( !defined($is_current) ) { $is_current = 1 }
|
|
292
|
|
293 # Default to is_constitutive = 0 if this attribute is not set
|
|
294 my $is_constitutive = $exon->is_constitutive();
|
|
295 if ( !defined($is_constitutive) ) { $is_constitutive = 0 }
|
|
296
|
|
297 my $exon_sql = q{
|
|
298 INSERT into exon ( seq_region_id, seq_region_start,
|
|
299 seq_region_end, seq_region_strand, phase,
|
|
300 end_phase, is_current, is_constitutive
|
|
301 };
|
|
302 if ( defined($exon->stable_id) ) {
|
|
303 my $created = $self->db->dbc->from_seconds_to_date($exon->created_date());
|
|
304 my $modified = $self->db->dbc->from_seconds_to_date($exon->modified_date());
|
|
305 $exon_sql .= ", stable_id, version, created_date, modified_date) VALUES ( ?,?,?,?,?,?,?,?,?,?,". $created . ",". $modified ." )";
|
|
306
|
|
307 } else {
|
|
308 $exon_sql .= q{
|
|
309 ) VALUES ( ?,?,?,?,?,?,?,?)
|
|
310 };
|
|
311 }
|
|
312
|
|
313
|
|
314 my $exonst = $self->prepare($exon_sql);
|
|
315
|
|
316 my $exonId = undef;
|
|
317
|
|
318 my $original = $exon;
|
|
319 my $seq_region_id;
|
|
320 ($exon, $seq_region_id) = $self->_pre_store($exon);
|
|
321
|
|
322 #store the exon
|
|
323 $exonst->bind_param( 1, $seq_region_id, SQL_INTEGER );
|
|
324 $exonst->bind_param( 2, $exon->start, SQL_INTEGER );
|
|
325 $exonst->bind_param( 3, $exon->end, SQL_INTEGER );
|
|
326 $exonst->bind_param( 4, $exon->strand, SQL_TINYINT );
|
|
327 $exonst->bind_param( 5, $exon->phase, SQL_TINYINT );
|
|
328 $exonst->bind_param( 6, $exon->end_phase, SQL_TINYINT );
|
|
329 $exonst->bind_param( 7, $is_current, SQL_TINYINT );
|
|
330 $exonst->bind_param( 8, $is_constitutive, SQL_TINYINT );
|
|
331
|
|
332 if ( defined($exon->stable_id) ) {
|
|
333
|
|
334 $exonst->bind_param( 9, $exon->stable_id, SQL_VARCHAR );
|
|
335 my $version = ($exon->version()) ? $exon->version() : 1;
|
|
336 $exonst->bind_param( 10, $version, SQL_INTEGER );
|
|
337 }
|
|
338
|
|
339 $exonst->execute();
|
|
340 $exonId = $exonst->{'mysql_insertid'};
|
|
341
|
|
342 # Now the supporting evidence
|
|
343 my $esf_adaptor = $db->get_SupportingFeatureAdaptor;
|
|
344 $esf_adaptor->store($exonId, $exon->get_all_supporting_features);
|
|
345
|
|
346 #
|
|
347 # Finally, update the dbID and adaptor of the exon (and any component exons)
|
|
348 # to point to the new database
|
|
349 #
|
|
350
|
|
351 $original->adaptor($self);
|
|
352 $original->dbID($exonId);
|
|
353
|
|
354 return $exonId;
|
|
355 }
|
|
356
|
|
357
|
|
358 =head2 remove
|
|
359
|
|
360 Arg [1] : Bio::EnsEMBL::Exon $exon
|
|
361 the exon to remove from the database
|
|
362 Example : $exon_adaptor->remove($exon);
|
|
363 Description: Removes an exon from the database. This method is generally
|
|
364 called by the TranscriptAdaptor::store method. Database
|
|
365 integrity will not be maintained if this method is simply
|
|
366 called on its own without taking into account transcripts which
|
|
367 may refer to the exon being removed.
|
|
368 Returntype : none
|
|
369 Exceptions : none
|
|
370 Caller : general
|
|
371 Status : Stable
|
|
372
|
|
373 =cut
|
|
374
|
|
375 sub remove {
|
|
376 my $self = shift;
|
|
377 my $exon = shift;
|
|
378
|
|
379 if(!ref($exon) || !$exon->isa('Bio::EnsEMBL::Exon')) {
|
|
380 throw('Bio::EnsEMBL::Exon argument expected.');
|
|
381 }
|
|
382
|
|
383 if(!$exon->is_stored($self->db())) {
|
|
384 warning("Cannot remove exon " .$exon->dbID.
|
|
385 "Is not stored in this database.");
|
|
386 return;
|
|
387 }
|
|
388
|
|
389 # sanity check: make sure nobdody tries to slip past a prediction exon
|
|
390 # which inherits from exon but actually uses different tables
|
|
391 if($exon->isa('Bio::EnsEMBL::PredictionExon')) {
|
|
392 throw("ExonAdaptor can only remove Exons not PredictionExons.");
|
|
393 }
|
|
394
|
|
395 # Remove the supporting features of this exon
|
|
396
|
|
397 my $prot_adp = $self->db->get_ProteinAlignFeatureAdaptor;
|
|
398 my $dna_adp = $self->db->get_DnaAlignFeatureAdaptor;
|
|
399
|
|
400 my $sth = $self->prepare("SELECT feature_type, feature_id " .
|
|
401 "FROM supporting_feature " .
|
|
402 "WHERE exon_id = ?");
|
|
403 $sth->bind_param(1, $exon->dbID, SQL_INTEGER);
|
|
404 $sth->execute();
|
|
405
|
|
406 # statements to check for shared align_features
|
|
407 my $sth1 = $self->prepare("SELECT count(*) FROM supporting_feature " .
|
|
408 "WHERE feature_type = ? AND feature_id = ?");
|
|
409 my $sth2 = $self->prepare("SELECT count(*) " .
|
|
410 "FROM transcript_supporting_feature " .
|
|
411 "WHERE feature_type = ? AND feature_id = ?");
|
|
412
|
|
413 SUPPORTING_FEATURE:
|
|
414 while(my ($type, $feature_id) = $sth->fetchrow()){
|
|
415
|
|
416 # only remove align_feature if this is the last reference to it
|
|
417 $sth1->bind_param(1, $type, SQL_VARCHAR);
|
|
418 $sth1->bind_param(2, $feature_id, SQL_INTEGER);
|
|
419 $sth1->execute;
|
|
420 $sth2->bind_param(1, $type, SQL_VARCHAR);
|
|
421 $sth2->bind_param(2, $feature_id, SQL_INTEGER);
|
|
422 $sth2->execute;
|
|
423 my ($count1) = $sth1->fetchrow;
|
|
424 my ($count2) = $sth2->fetchrow;
|
|
425 if ($count1 + $count2 > 1) {
|
|
426 #warn "shared feature, not removing $type|$feature_id\n";
|
|
427 next SUPPORTING_FEATURE;
|
|
428 }
|
|
429
|
|
430 #warn "removing $type|$feature_id\n";
|
|
431
|
|
432 if($type eq 'protein_align_feature'){
|
|
433 my $f = $prot_adp->fetch_by_dbID($feature_id);
|
|
434 $prot_adp->remove($f);
|
|
435 }
|
|
436 elsif($type eq 'dna_align_feature'){
|
|
437 my $f = $dna_adp->fetch_by_dbID($feature_id);
|
|
438 $dna_adp->remove($f);
|
|
439 }
|
|
440 else {
|
|
441 warning("Unknown supporting feature type $type. Not removing feature.");
|
|
442 }
|
|
443 }
|
|
444 $sth->finish();
|
|
445 $sth1->finish();
|
|
446 $sth2->finish();
|
|
447
|
|
448 # delete the association to supporting features
|
|
449
|
|
450 $sth = $self->prepare("DELETE FROM supporting_feature WHERE exon_id = ?");
|
|
451 $sth->bind_param(1, $exon->dbID, SQL_INTEGER);
|
|
452 $sth->execute();
|
|
453 $sth->finish();
|
|
454
|
|
455
|
|
456 # delete the exon
|
|
457
|
|
458 $sth = $self->prepare( "DELETE FROM exon WHERE exon_id = ?" );
|
|
459 $sth->bind_param(1, $exon->dbID, SQL_INTEGER);
|
|
460 $sth->execute();
|
|
461 $sth->finish();
|
|
462
|
|
463 $exon->dbID(undef);
|
|
464 $exon->adaptor(undef);
|
|
465
|
|
466 return;
|
|
467 }
|
|
468
|
|
469
|
|
470 =head2 list_dbIDs
|
|
471
|
|
472 Arg [1] : none
|
|
473 Example : @exon_ids = @{$exon_adaptor->list_dbIDs()};
|
|
474 Description: Gets an array of internal ids for all exons in the current db
|
|
475 Arg[1] : <optional> int. not 0 for the ids to be sorted by the seq_region.
|
|
476 Returntype : list of ints
|
|
477 Exceptions : none
|
|
478 Caller : ?
|
|
479 Status : Stable
|
|
480
|
|
481 =cut
|
|
482
|
|
483 sub list_dbIDs {
|
|
484 my ($self, $ordered) = @_;
|
|
485
|
|
486 return $self->_list_dbIDs("exon",undef, $ordered);
|
|
487 }
|
|
488
|
|
489
|
|
490 =head2 list_stable_ids
|
|
491
|
|
492 Arg [1] : none
|
|
493 Example : @stable_exon_ids = @{$exon_adaptor->list_stable_dbIDs()};
|
|
494 Description: Gets an array of stable ids for all exons in the current db
|
|
495 Returntype : list of ints
|
|
496 Exceptions : none
|
|
497 Caller : ?
|
|
498 Status : Stable
|
|
499
|
|
500 =cut
|
|
501
|
|
502 sub list_stable_ids {
|
|
503 my ($self) = @_;
|
|
504
|
|
505 return $self->_list_dbIDs("exon", "stable_id");
|
|
506 }
|
|
507
|
|
508 #_objs_from_sth
|
|
509 #
|
|
510 # Arg [1] : StatementHandle $sth
|
|
511 # Example : none
|
|
512 # Description: PROTECTED implementation of abstract superclass method.
|
|
513 # responsible for the creation of Exons
|
|
514 # Returntype : listref of Bio::EnsEMBL::Exons in target coordinate system
|
|
515 # Exceptions : none
|
|
516 # Caller : internal
|
|
517
|
|
518 sub _objs_from_sth {
|
|
519 my ( $self, $sth, $mapper, $dest_slice ) = @_;
|
|
520
|
|
521 #
|
|
522 # This code is ugly because an attempt has been made to remove as many
|
|
523 # function calls as possible for speed purposes. Thus many caches and
|
|
524 # a fair bit of gymnastics is used.
|
|
525 #
|
|
526
|
|
527 my $sa = $self->db()->get_SliceAdaptor();
|
|
528
|
|
529 my @exons;
|
|
530 my %slice_hash;
|
|
531 my %sr_name_hash;
|
|
532 my %sr_cs_hash;
|
|
533
|
|
534 my ( $exon_id, $seq_region_id, $seq_region_start,
|
|
535 $seq_region_end, $seq_region_strand, $phase,
|
|
536 $end_phase, $is_current, $is_constitutive,
|
|
537 $stable_id, $version, $created_date,
|
|
538 $modified_date );
|
|
539
|
|
540 $sth->bind_columns( \( $exon_id, $seq_region_id, $seq_region_start,
|
|
541 $seq_region_end, $seq_region_strand, $phase,
|
|
542 $end_phase, $is_current, $is_constitutive,
|
|
543 $stable_id, $version, $created_date,
|
|
544 $modified_date ) );
|
|
545
|
|
546 my $asm_cs;
|
|
547 my $cmp_cs;
|
|
548 my $asm_cs_vers;
|
|
549 my $asm_cs_name;
|
|
550 my $cmp_cs_vers;
|
|
551 my $cmp_cs_name;
|
|
552
|
|
553 if ($mapper) {
|
|
554 $asm_cs = $mapper->assembled_CoordSystem();
|
|
555 $cmp_cs = $mapper->component_CoordSystem();
|
|
556 $asm_cs_name = $asm_cs->name();
|
|
557 $asm_cs_vers = $asm_cs->version();
|
|
558 $cmp_cs_name = $cmp_cs->name();
|
|
559 $cmp_cs_vers = $cmp_cs->version();
|
|
560 }
|
|
561
|
|
562 my $dest_slice_start;
|
|
563 my $dest_slice_end;
|
|
564 my $dest_slice_strand;
|
|
565 my $dest_slice_length;
|
|
566 my $dest_slice_cs;
|
|
567 my $dest_slice_sr_name;
|
|
568 my $dest_slice_sr_id;
|
|
569 my $asma;
|
|
570
|
|
571 if ($dest_slice) {
|
|
572 $dest_slice_start = $dest_slice->start();
|
|
573 $dest_slice_end = $dest_slice->end();
|
|
574 $dest_slice_strand = $dest_slice->strand();
|
|
575 $dest_slice_length = $dest_slice->length();
|
|
576 $dest_slice_cs = $dest_slice->coord_system();
|
|
577 $dest_slice_sr_name = $dest_slice->seq_region_name();
|
|
578 $dest_slice_sr_id = $dest_slice->get_seq_region_id();
|
|
579 $asma = $self->db->get_AssemblyMapperAdaptor();
|
|
580 }
|
|
581
|
|
582 FEATURE: while ( $sth->fetch() ) {
|
|
583 #need to get the internal_seq_region, if present
|
|
584 $seq_region_id = $self->get_seq_region_id_internal($seq_region_id);
|
|
585
|
|
586 my $slice = $slice_hash{ "ID:" . $seq_region_id };
|
|
587 my $dest_mapper = $mapper;
|
|
588
|
|
589 if ( !$slice ) {
|
|
590 $slice = $sa->fetch_by_seq_region_id($seq_region_id);
|
|
591 $slice_hash{ "ID:" . $seq_region_id } = $slice;
|
|
592 $sr_name_hash{$seq_region_id} = $slice->seq_region_name();
|
|
593 $sr_cs_hash{$seq_region_id} = $slice->coord_system();
|
|
594 }
|
|
595
|
|
596 #obtain a mapper if none was defined, but a dest_seq_region was
|
|
597 if ( !$dest_mapper
|
|
598 && $dest_slice
|
|
599 && !$dest_slice_cs->equals( $slice->coord_system ) )
|
|
600 {
|
|
601 $dest_mapper =
|
|
602 $asma->fetch_by_CoordSystems( $dest_slice_cs,
|
|
603 $slice->coord_system );
|
|
604 $asm_cs = $dest_mapper->assembled_CoordSystem();
|
|
605 $cmp_cs = $dest_mapper->component_CoordSystem();
|
|
606 $asm_cs_name = $asm_cs->name();
|
|
607 $asm_cs_vers = $asm_cs->version();
|
|
608 $cmp_cs_name = $cmp_cs->name();
|
|
609 $cmp_cs_vers = $cmp_cs->version();
|
|
610 }
|
|
611
|
|
612 my $sr_name = $sr_name_hash{$seq_region_id};
|
|
613 my $sr_cs = $sr_cs_hash{$seq_region_id};
|
|
614
|
|
615 #
|
|
616 # Remap the feature coordinates to another coord system if a mapper
|
|
617 # was provided.
|
|
618 #
|
|
619 if ( defined($dest_mapper) ) {
|
|
620
|
|
621 if (defined $dest_slice && $dest_mapper->isa('Bio::EnsEMBL::ChainedAssemblyMapper') ) {
|
|
622 ( $seq_region_id, $seq_region_start,
|
|
623 $seq_region_end, $seq_region_strand )
|
|
624 =
|
|
625 $dest_mapper->map( $sr_name, $seq_region_start, $seq_region_end,
|
|
626 $seq_region_strand, $sr_cs, 1, $dest_slice);
|
|
627
|
|
628 } else {
|
|
629
|
|
630 ( $seq_region_id, $seq_region_start,
|
|
631 $seq_region_end, $seq_region_strand )
|
|
632 = $dest_mapper->fastmap( $sr_name, $seq_region_start,
|
|
633 $seq_region_end, $seq_region_strand,
|
|
634 $sr_cs );
|
|
635 }
|
|
636
|
|
637 # Skip features that map to gaps or coord system boundaries.
|
|
638 if ( !defined($seq_region_id) ) { next FEATURE }
|
|
639
|
|
640 # Get a slice in the coord system we just mapped to
|
|
641 $slice = $slice_hash{ "ID:" . $seq_region_id } ||=
|
|
642 $sa->fetch_by_seq_region_id($seq_region_id);
|
|
643 }
|
|
644
|
|
645 #
|
|
646 # If a destination slice was provided convert the coords.
|
|
647 #
|
|
648 if ( defined($dest_slice) ) {
|
|
649 if ( $dest_slice_strand == 1 ) {
|
|
650 # On the positive strand.
|
|
651
|
|
652 $seq_region_start = $seq_region_start - $dest_slice_start + 1;
|
|
653 $seq_region_end = $seq_region_end - $dest_slice_start + 1;
|
|
654
|
|
655 if ( ( $seq_region_end > $dest_slice_start || $seq_region_end < 0 || ( $dest_slice_start > $dest_slice_end
|
|
656 && $seq_region_end < 0 ) ) && $dest_slice->is_circular() ) {
|
|
657 # Handle circular chromosomes.
|
|
658
|
|
659 if ( $seq_region_start > $seq_region_end ) {
|
|
660 # Looking at a feature overlapping the chromsome origin.
|
|
661
|
|
662 if ( $seq_region_end > $dest_slice_start ) {
|
|
663 # Looking at the region in the beginning of the
|
|
664 # chromosome.
|
|
665 $seq_region_start -= $dest_slice->seq_region_length();
|
|
666 }
|
|
667
|
|
668 if ( $seq_region_end < 0 ) {
|
|
669 $seq_region_end += $dest_slice->seq_region_length();
|
|
670 }
|
|
671
|
|
672 } else {
|
|
673 if ( $dest_slice_start > $dest_slice_end
|
|
674 && $seq_region_end < 0 )
|
|
675 {
|
|
676 # Looking at the region overlapping the chromosome
|
|
677 # origin and a feature which is at the beginning of the
|
|
678 # chromosome.
|
|
679 $seq_region_start += $dest_slice->seq_region_length();
|
|
680 $seq_region_end += $dest_slice->seq_region_length();
|
|
681 }
|
|
682 }
|
|
683 }
|
|
684
|
|
685 } else {
|
|
686 # On the negative strand.
|
|
687
|
|
688 if ( $seq_region_start > $seq_region_end && $dest_slice->is_circular() )
|
|
689 {
|
|
690 # Handle circular chromosomes.
|
|
691
|
|
692 if ( $dest_slice_start > $dest_slice_end ) {
|
|
693 my $tmp_seq_region_start = $seq_region_start;
|
|
694 $seq_region_start = $dest_slice_end - $seq_region_end + 1;
|
|
695 $seq_region_end =
|
|
696 $dest_slice_end +
|
|
697 $dest_slice->seq_region_length() -
|
|
698 $tmp_seq_region_start + 1;
|
|
699 } else {
|
|
700
|
|
701 if ( $seq_region_end > $dest_slice_start ) {
|
|
702 # Looking at the region in the beginning of the
|
|
703 # chromosome.
|
|
704 $seq_region_start = $dest_slice_end - $seq_region_end + 1;
|
|
705 $seq_region_end =
|
|
706 $seq_region_end -
|
|
707 $dest_slice->seq_region_length() -
|
|
708 $dest_slice_start + 1;
|
|
709 } else {
|
|
710 my $tmp_seq_region_start = $seq_region_start;
|
|
711 $seq_region_start =
|
|
712 $dest_slice_end -
|
|
713 $seq_region_end -
|
|
714 $dest_slice->seq_region_length() + 1;
|
|
715 $seq_region_end =
|
|
716 $dest_slice_end - $tmp_seq_region_start + 1;
|
|
717 }
|
|
718
|
|
719 }
|
|
720
|
|
721 } else {
|
|
722 # Non-circular chromosome.
|
|
723
|
|
724 my $tmp_seq_region_start = $seq_region_start;
|
|
725 $seq_region_start = $dest_slice_end - $seq_region_end + 1;
|
|
726 $seq_region_end = $dest_slice_end - $tmp_seq_region_start + 1;
|
|
727 }
|
|
728
|
|
729 $seq_region_strand = -$seq_region_strand;
|
|
730
|
|
731 } ## end else [ if ( $dest_slice_strand...)]
|
|
732
|
|
733 # Throw away features off the end of the requested slice.
|
|
734 if ( $seq_region_end < 1
|
|
735 || $seq_region_start > $dest_slice_length
|
|
736 || ( $dest_slice_sr_id != $seq_region_id ) )
|
|
737 {
|
|
738 next FEATURE;
|
|
739 }
|
|
740
|
|
741 $slice = $dest_slice;
|
|
742 } ## end if ( defined($dest_slice...))
|
|
743
|
|
744 # Finally, create the new exon.
|
|
745 push( @exons,
|
|
746 $self->_create_feature_fast(
|
|
747 'Bio::EnsEMBL::Exon', {
|
|
748 'start' => $seq_region_start,
|
|
749 'end' => $seq_region_end,
|
|
750 'strand' => $seq_region_strand,
|
|
751 'adaptor' => $self,
|
|
752 'slice' => $slice,
|
|
753 'dbID' => $exon_id,
|
|
754 'stable_id' => $stable_id,
|
|
755 'version' => $version,
|
|
756 'created_date' => $created_date || undef,
|
|
757 'modified_date' => $modified_date || undef,
|
|
758 'phase' => $phase,
|
|
759 'end_phase' => $end_phase,
|
|
760 'is_current' => $is_current,
|
|
761 'is_constitutive' => $is_constitutive } )
|
|
762 );
|
|
763
|
|
764 } ## end while ( $sth->fetch() )
|
|
765
|
|
766 return \@exons;
|
|
767 } ## end sub _objs_from_sth
|
|
768
|
|
769 =head1 DEPRECATED METHODS
|
|
770
|
|
771 =cut
|
|
772
|
|
773
|
|
774 =head2 get_stable_entry_info
|
|
775
|
|
776 Description: DEPRECATED. This method is no longer necessary. Exons are
|
|
777 always fetched with their stable identifiers (if they exist) and
|
|
778 no lazy loading is necessary.
|
|
779
|
|
780 =cut
|
|
781
|
|
782 sub get_stable_entry_info {
|
|
783 my ($self,$exon) = @_;
|
|
784
|
|
785 deprecated( "This method call shouldnt be necessary" );
|
|
786
|
|
787 if( !$exon || !ref $exon || !$exon->isa('Bio::EnsEMBL::Exon') ) {
|
|
788 $self->throw("Needs a exon object, not a $exon");
|
|
789 }
|
|
790 if(!$exon->dbID){
|
|
791 #$self->throw("can't fetch stable info with no dbID");
|
|
792 return;
|
|
793 }
|
|
794
|
|
795 my $created_date = $self->db->dbc->from_date_to_seconds("created_date");
|
|
796 my $modified_date = $self->db->dbc->from_date_to_seconds("modified_date");
|
|
797 my $sth = $self->prepare("SELECT stable_id, " . $created_date . ",
|
|
798 " . $modified_date . ", version
|
|
799 FROM exon
|
|
800 WHERE exon_id = ");
|
|
801
|
|
802 $sth->bind_param(1, $exon->dbID, SQL_INTEGER);
|
|
803 $sth->execute();
|
|
804
|
|
805 # my @array = $sth->fetchrow_array();
|
|
806 if( my $aref = $sth->fetchrow_arrayref() ) {
|
|
807 $exon->{'_stable_id'} = $aref->[0];
|
|
808 $exon->{'_created'} = $aref->[1];
|
|
809 $exon->{'_modified'} = $aref->[2];
|
|
810 $exon->{'_version'} = $aref->[3];
|
|
811 }
|
|
812
|
|
813 return 1;
|
|
814 }
|
|
815
|
|
816
|
|
817 =head2 fetch_all_by_gene_id
|
|
818
|
|
819 Description: DEPRECATED. This method should not be needed - Exons can
|
|
820 be fetched by Transcript.
|
|
821
|
|
822 =cut
|
|
823
|
|
824 sub fetch_all_by_gene_id {
|
|
825 my ( $self, $gene_id ) = @_;
|
|
826 my %exons;
|
|
827 my $hashRef;
|
|
828 my ( $currentId, $currentTranscript );
|
|
829
|
|
830 deprecated( "Hopefully this method is not needed any more. Exons should be fetched by Transcript" );
|
|
831
|
|
832 if( !$gene_id ) {
|
|
833 $self->throw("Gene dbID not defined");
|
|
834 }
|
|
835
|
|
836 $self->{rchash} = {};
|
|
837
|
|
838 my $query = qq {
|
|
839 SELECT
|
|
840 STRAIGHT_JOIN
|
|
841 e.exon_id
|
|
842 , e.contig_id
|
|
843 , e.contig_start
|
|
844 , e.contig_end
|
|
845 , e.contig_strand
|
|
846 , e.phase
|
|
847 , e.end_phase
|
|
848 , e.sticky_rank
|
|
849 FROM transcript t
|
|
850 , exon_transcript et
|
|
851 , exon e
|
|
852 WHERE t.gene_id = ?
|
|
853 AND et.transcript_id = t.transcript_id
|
|
854 AND e.exon_id = et.exon_id
|
|
855 ORDER BY t.transcript_id,e.exon_id
|
|
856 , e.sticky_rank DESC
|
|
857 };
|
|
858
|
|
859 my $sth = $self->prepare( $query );
|
|
860 $sth->bind_param(1,$gene_id,SQL_INTEGER);
|
|
861 $sth->execute();
|
|
862
|
|
863 while( $hashRef = $sth->fetchrow_hashref() ) {
|
|
864 if( ! exists $exons{ $hashRef->{exon_id} } ) {
|
|
865
|
|
866 my $exon = $self->_exon_from_sth( $sth, $hashRef );
|
|
867
|
|
868 $exons{$exon->dbID} = $exon;
|
|
869 }
|
|
870 }
|
|
871 delete $self->{rchash};
|
|
872
|
|
873 my @out = ();
|
|
874
|
|
875 push @out, values %exons;
|
|
876
|
|
877 return \@out;
|
|
878 }
|
|
879
|
|
880
|
|
881 1;
|
|
882
|
|
883
|