3 See the NOTICE file distributed with
this work
for additional information
4 regarding copyright ownership.
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
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.
23 Please email comments or questions to the
public Ensembl
24 developers list at <http:
26 Questions may also be sent to the Ensembl help desk at
34 storage of
exon objects
38 my $exon_adaptor = $registry->get_adaptor(
'Human',
'Core',
'Exon' );
40 my $exon = $exon_adaptor->fetch_by_dbID($dbID);
45 from an Ensembl database. Most of the
ExonAdaptor functionality is
46 inherited from the B<Bio::EnsEMBL::DBSQL::BaseFeatureAdaptor>
class.
52 package Bio::EnsEMBL::DBSQL::ExonAdaptor;
68 # Description: PROTECTED implementation of superclass abstract method
69 # returns the names, aliases of the tables to use for queries
70 # Returntype : list of listrefs of strings
77 # Allow the table definition to be overridden by certain methods.
78 if ( defined( $self->{
'tables'} ) ) {
79 return @{ $self->{
'tables'} };
82 return ( [
'exon',
'e' ] );
90 # Description: PROTECTED implementation of superclass abstract method
91 # returns a list of columns to use for queries
92 # Returntype : list of strings
100 $self->db->dbc->from_date_to_seconds(
"created_date");
102 $self->db->dbc->from_date_to_seconds(
"modified_date");
105 'e.exon_id',
'e.seq_region_id',
'e.seq_region_start',
106 'e.seq_region_end',
'e.seq_region_strand',
'e.phase',
107 'e.end_phase',
'e.is_current',
'e.is_constitutive',
108 'e.stable_id',
'e.version', $created_date,
119 # Description: PROTECTED implementation of superclass abstract method
120 # returns a default end for the SQL-query (ORDER BY)
121 # Returntype : string
127 return $self->{
'final_clause'} ||
'';
134 my $constraint =
'e.is_current = 1';
135 my @exons = @{ $self->generic_fetch($constraint) };
139 =head2 fetch_by_stable_id
141 Arg [1] :
string $stable_id
142 the stable
id of the
exon to retrieve
143 Example : $exon = $exon_adaptor->fetch_by_stable_id(
'ENSE0000988221');
144 Description: Retrieves an Exon from the database via its stable
id
152 sub fetch_by_stable_id {
153 my ($self, $stable_id) = @_;
155 my $constraint =
"e.stable_id = ? AND e.is_current = 1";
157 $self->bind_param_generic_fetch($stable_id,SQL_VARCHAR);
158 my ($exon) = @{ $self->generic_fetch($constraint) };
160 # If we didn't get anything back, desperately try to see if there's
161 # a version number in the stable_id
162 if(!defined($exon) && (my $vindex = rindex($stable_id,
'.'))) {
163 $exon = $self->fetch_by_stable_id_version(substr($stable_id,0,$vindex),
164 substr($stable_id,$vindex+1));
171 =head2 fetch_by_stable_id_version
174 The stable ID of the
exon to retrieve
175 Arg [2] : Integer $version
176 The version of the stable_id to retrieve
177 Example : $exon = $exon_adaptor->fetch_by_stable_id(
'ENSE0000988221', 3);
178 Description: Retrieves an
exon object from the database via its stable
id and version.
179 The
exon will be retrieved in its native coordinate system (i.e.
180 in the coordinate system it is stored in the database). It may
181 be converted to a different coordinate system through a call to
182 transform() or transfer(). If the
exon is not found
183 undef is returned instead.
185 Exceptions : if we cant get the
exon in given coord system
191 sub fetch_by_stable_id_version {
192 my ($self, $stable_id, $version) = @_;
194 # Enforce that version be numeric
195 return unless($version =~ /^\d+$/);
197 my $constraint =
"e.stable_id = ? AND e.version = ? AND e.is_current = 1";
198 $self->bind_param_generic_fetch($stable_id, SQL_VARCHAR);
199 $self->bind_param_generic_fetch($version, SQL_INTEGER);
200 my ($exon) = @{$self->generic_fetch($constraint)};
205 =head2 fetch_all_versions_by_stable_id
207 Arg [1] : String $stable_id
208 The stable ID of the
exon to retrieve
209 Example : my $exon = $exon_adaptor->fetch_all_version_by_stable_id
211 Description : Similar to fetch_by_stable_id, but retrieves all versions of an
212 exon stored in the database.
214 Exceptions :
if we cant get the gene in given coord system
220 sub fetch_all_versions_by_stable_id {
221 my ($self, $stable_id) = @_;
223 my $constraint =
"e.stable_id = ?";
225 $self->bind_param_generic_fetch($stable_id,SQL_VARCHAR);
227 return $self->generic_fetch($constraint);
231 =head2 fetch_all_by_Transcript
235 Description: Retrieves all Exons
for the Transcript in 5-3 order
237 Exceptions :
throws if transcript has no slice
238 Caller : Transcript->get_all_Exons()
243 sub fetch_all_by_Transcript {
244 my ( $self, $transcript ) = @_;
246 my $tslice = $transcript->slice();
249 if ( !defined($tslice) ) {
250 throw(
"Transcript must have attached slice to retrieve exons.");
253 # use a small slice the same size as the transcript
254 if ( !$tslice->is_circular() ) {
256 $self->db()->get_SliceAdaptor()->fetch_by_Feature($transcript);
262 # Override the tables definition to provide an additional join to the
263 # exon_transcript table. For efficiency we cannot afford to have this
264 # in as a left join every time.
265 my @tables = $self->_tables();
267 # Be extra cautious so that we do not add 'exon_transcript' twice.
269 foreach my $table (@tables) {
270 if ( $table->[0] eq
'exon_transcript' ) {
276 push @tables, [
'exon_transcript',
'et' ];
279 $self->{
'tables'} = \@tables;
280 $self->{
'final_clause'} =
"ORDER BY et.transcript_id, et.rank";
283 "et.transcript_id = "
284 . $transcript->dbID()
285 .
" AND e.exon_id = et.exon_id";
287 # fetch all of the exons
288 my $exons = $self->fetch_all_by_Slice_constraint($slice, $constraint);
290 # un-override the table definition
291 delete( $self->{
'tables'} );
292 delete( $self->{
'final_clause'} );
294 # remap exon coordinates if necessary
295 if($slice->name() ne $tslice->name()) {
297 foreach my $ex (@$exons) {
298 push @out, $ex->transfer($tslice);
310 the
exon to store in
this database
311 Example : $exon_adaptor->store($exon);
312 Description: Stores an
exon in the database
314 Exceptions : thrown
if exon (or component exons)
do not have a contig_id
315 or
if $exon->start, $exon->end, $exon->strand, or $exon->phase
323 my ($self, $exon) = @_;
325 if( ! $exon->isa(
'Bio::EnsEMBL::Exon') ) {
326 throw(
"$exon is not a EnsEMBL exon - not storing.");
329 my $db = $self->db();
331 if($exon->is_stored($db)) {
332 return $exon->
dbID();
335 if( ! $exon->start || ! $exon->end ||
336 ! $exon->strand || ! defined $exon->phase ) {
337 throw(
"Exon does not have all attributes to store");
340 # Default to is_current = 1 if this attribute is not set
341 my $is_current = $exon->is_current();
342 if ( !defined($is_current) ) { $is_current = 1 }
344 # Default to is_constitutive = 0 if this attribute is not set
345 my $is_constitutive = $exon->is_constitutive();
346 if ( !defined($is_constitutive) ) { $is_constitutive = 0 }
349 INSERT into
exon ( seq_region_id, seq_region_start,
350 seq_region_end, seq_region_strand, phase,
351 end_phase, is_current, is_constitutive
353 if ( defined($exon->stable_id) ) {
354 my $created = $self->db->dbc->from_seconds_to_date($exon->created_date());
355 my $modified = $self->db->dbc->from_seconds_to_date($exon->modified_date());
357 $exon_sql .= sprintf
", stable_id, version%s%s) VALUES ( ?,?,?,?,?,?,?,?,?,?%s%s)", $created?
", created_date":
'', $modified?
", modified_date":
'', $created?
",$created":
'', $modified?
",$modified":
'';
361 ) VALUES ( ?,?,?,?,?,?,?,?)
366 my $exonst = $self->prepare($exon_sql);
370 my $original = $exon;
372 ($exon, $seq_region_id) = $self->_pre_store($exon);
375 $exonst->bind_param( 1, $seq_region_id, SQL_INTEGER );
376 $exonst->bind_param( 2, $exon->start, SQL_INTEGER );
377 $exonst->bind_param( 3, $exon->end, SQL_INTEGER );
378 $exonst->bind_param( 4, $exon->strand, SQL_TINYINT );
379 $exonst->bind_param( 5, $exon->phase, SQL_TINYINT );
380 $exonst->bind_param( 6, $exon->end_phase, SQL_TINYINT );
381 $exonst->bind_param( 7, $is_current, SQL_TINYINT );
382 $exonst->bind_param( 8, $is_constitutive, SQL_TINYINT );
384 if ( defined($exon->stable_id) ) {
386 $exonst->bind_param( 9, $exon->stable_id, SQL_VARCHAR );
387 $exonst->bind_param( 10, $exon->version, SQL_INTEGER );
391 $exonId = $self->last_insert_id(
'exon_id', undef,
'exon');
393 # Now the supporting evidence
394 my $esf_adaptor = $db->get_SupportingFeatureAdaptor;
395 $esf_adaptor->store($exonId, $exon->get_all_supporting_features);
398 # Finally, update the dbID and adaptor of the exon (and any component exons)
399 # to point to the new database
402 $original->adaptor($self);
403 $original->dbID($exonId);
412 the
exon to remove from the database
413 Example : $exon_adaptor->remove($exon);
414 Description: Removes an
exon from the database. This method is generally
415 called by the TranscriptAdaptor::store method. Database
416 integrity will not be maintained
if this method is simply
417 called on its own without taking into account transcripts which
418 may refer to the
exon being removed.
430 if(!ref($exon) || !$exon->isa(
'Bio::EnsEMBL::Exon')) {
431 throw(
'Bio::EnsEMBL::Exon argument expected.');
434 if(!$exon->is_stored($self->db())) {
435 warning(
"Cannot remove exon " .$exon->dbID.
436 "Is not stored in this database.");
440 # sanity check: make sure nobdody tries to slip past a prediction exon
441 # which inherits from exon but actually uses different tables
442 if($exon->isa(
'Bio::EnsEMBL::PredictionExon')) {
443 throw(
"ExonAdaptor can only remove Exons not PredictionExons.");
446 # Remove the supporting features of this exon
448 my $prot_adp = $self->db->get_ProteinAlignFeatureAdaptor;
449 my $dna_adp = $self->db->get_DnaAlignFeatureAdaptor;
451 my $sth = $self->prepare(
"SELECT feature_type, feature_id " .
452 "FROM supporting_feature " .
453 "WHERE exon_id = ?");
454 $sth->bind_param(1, $exon->dbID, SQL_INTEGER);
457 # statements to check for shared align_features
458 my $sth1 = $self->prepare(
"SELECT count(*) FROM supporting_feature " .
459 "WHERE feature_type = ? AND feature_id = ?");
460 my $sth2 = $self->prepare(
"SELECT count(*) " .
461 "FROM transcript_supporting_feature " .
462 "WHERE feature_type = ? AND feature_id = ?");
465 while(my ($type, $feature_id) = $sth->fetchrow()){
467 # only remove align_feature if this is the last reference to it
468 $sth1->bind_param(1, $type, SQL_VARCHAR);
469 $sth1->bind_param(2, $feature_id, SQL_INTEGER);
471 $sth2->bind_param(1, $type, SQL_VARCHAR);
472 $sth2->bind_param(2, $feature_id, SQL_INTEGER);
474 my ($count1) = $sth1->fetchrow;
475 my ($count2) = $sth2->fetchrow;
476 if ($count1 + $count2 > 1) {
477 #warn "shared feature, not removing $type|$feature_id\n";
478 next SUPPORTING_FEATURE;
481 #warn "removing $type|$feature_id\n";
483 if($type eq
'protein_align_feature'){
484 my $f = $prot_adp->fetch_by_dbID($feature_id);
485 $prot_adp->remove($f);
487 elsif($type eq
'dna_align_feature'){
488 my $f = $dna_adp->fetch_by_dbID($feature_id);
489 $dna_adp->remove($f);
492 warning(
"Unknown supporting feature type $type. Not removing feature.");
499 # delete the association to supporting features
501 $sth = $self->prepare(
"DELETE FROM supporting_feature WHERE exon_id = ?");
502 $sth->bind_param(1, $exon->dbID, SQL_INTEGER);
509 $sth = $self->prepare(
"DELETE FROM exon WHERE exon_id = ?" );
510 $sth->bind_param(1, $exon->dbID, SQL_INTEGER);
515 $exon->adaptor(undef);
524 Example : @exon_ids = @{$exon_adaptor->list_dbIDs()};
525 Description: Gets an array of
internal ids
for all exons in the current db
526 Arg[1] : <optional>
int. not 0
for the ids to be sorted by the seq_region.
527 Returntype : list of ints
535 my ($self, $ordered) = @_;
537 return $self->_list_dbIDs(
"exon",undef, $ordered);
541 =head2 list_stable_ids
544 Example : @stable_exon_ids = @{$exon_adaptor->list_stable_dbIDs()};
545 Description: Gets an array of stable ids
for all exons in the current db
546 Returntype : list of ints
553 sub list_stable_ids {
556 return $self->_list_dbIDs(
"exon",
"stable_id");
561 # Arg [1] : StatementHandle $sth
563 # Description: PROTECTED implementation of abstract superclass method.
564 # responsible for the creation of Exons
565 # Returntype : listref of Bio::EnsEMBL::Exons in target coordinate system
570 my ( $self, $sth, $mapper, $dest_slice ) = @_;
573 # This code is ugly because an attempt has been made to remove as many
574 # function calls as possible for speed purposes. Thus many caches and
575 # a fair bit of gymnastics is used.
578 my $sa = $self->db()->get_SliceAdaptor();
585 my ( $exon_id, $seq_region_id, $seq_region_start,
586 $seq_region_end, $seq_region_strand, $phase,
587 $end_phase, $is_current, $is_constitutive,
588 $stable_id, $version, $created_date,
591 $sth->bind_columns( \( $exon_id, $seq_region_id, $seq_region_start,
592 $seq_region_end, $seq_region_strand, $phase,
593 $end_phase, $is_current, $is_constitutive,
594 $stable_id, $version, $created_date,
597 my $dest_slice_start;
599 my $dest_slice_strand;
600 my $dest_slice_length;
602 my $dest_slice_sr_name;
603 my $dest_slice_sr_id;
607 $dest_slice_start = $dest_slice->start();
608 $dest_slice_end = $dest_slice->end();
609 $dest_slice_strand = $dest_slice->strand();
610 $dest_slice_length = $dest_slice->length();
611 $dest_slice_cs = $dest_slice->coord_system();
612 $dest_slice_sr_name = $dest_slice->seq_region_name();
613 $dest_slice_sr_id = $dest_slice->get_seq_region_id();
614 $asma = $self->db->get_AssemblyMapperAdaptor();
617 FEATURE:
while($sth->fetch()) {
619 #need to get the internal_seq_region, if present
620 $seq_region_id = $self->get_seq_region_id_internal($seq_region_id);
621 my $slice = $slice_hash{
"ID:".$seq_region_id};
624 $slice = $sa->fetch_by_seq_region_id($seq_region_id);
625 $slice_hash{
"ID:".$seq_region_id} = $slice;
626 $sr_name_hash{$seq_region_id} = $slice->seq_region_name();
627 $sr_cs_hash{$seq_region_id} = $slice->coord_system();
630 #obtain a mapper if none was defined, but a dest_seq_region was
631 if(!$mapper && $dest_slice && !$dest_slice_cs->equals($slice->coord_system)) {
632 $mapper = $asma->fetch_by_CoordSystems($dest_slice_cs, $slice->coord_system);
635 my $sr_name = $sr_name_hash{$seq_region_id};
636 my $sr_cs = $sr_cs_hash{$seq_region_id};
639 # remap the feature coordinates to another coord system
640 # if a mapper was provided
645 if (defined $dest_slice && $mapper->isa(
'Bio::EnsEMBL::ChainedAssemblyMapper') ) {
646 ($seq_region_id, $seq_region_start, $seq_region_end, $seq_region_strand) =
647 $mapper->map($sr_name, $seq_region_start, $seq_region_end, $seq_region_strand, $sr_cs, 1, $dest_slice);
650 ($seq_region_id, $seq_region_start, $seq_region_end, $seq_region_strand) =
651 $mapper->fastmap($sr_name, $seq_region_start, $seq_region_end, $seq_region_strand, $sr_cs);
654 #skip features that map to gaps or coord system boundaries
655 next FEATURE
if (!defined($seq_region_id));
657 #get a slice in the coord system we just mapped to
658 $slice = $slice_hash{
"ID:".$seq_region_id} ||= $sa->fetch_by_seq_region_id($seq_region_id);
662 # If a destination slice was provided convert the coords.
664 if (defined($dest_slice)) {
665 my $seq_region_len = $dest_slice->seq_region_length();
667 if ( $dest_slice_strand == 1 ) {
668 $seq_region_start = $seq_region_start - $dest_slice_start + 1;
669 $seq_region_end = $seq_region_end - $dest_slice_start + 1;
671 if ( $dest_slice->is_circular ) {
672 # Handle circular chromosomes.
674 if ( $seq_region_start > $seq_region_end ) {
675 # Looking at a feature overlapping the chromosome origin.
677 if ( $seq_region_end > $dest_slice_start ) {
678 # Looking at the region in the beginning of the chromosome
679 $seq_region_start -= $seq_region_len;
681 if ( $seq_region_end < 0 ) {
682 $seq_region_end += $seq_region_len;
685 if ($dest_slice_start > $dest_slice_end && $seq_region_end < 0) {
686 # Looking at the region overlapping the chromosome
687 # origin and a feature which is at the beginning of the
689 $seq_region_start += $seq_region_len;
690 $seq_region_end += $seq_region_len;
696 my $start = $dest_slice_end - $seq_region_end + 1;
697 my $end = $dest_slice_end - $seq_region_start + 1;
699 if ($dest_slice->is_circular()) {
701 if ($dest_slice_start > $dest_slice_end) {
702 # slice spans origin or replication
704 if ($seq_region_start >= $dest_slice_start) {
705 $end += $seq_region_len;
706 $start += $seq_region_len
if $seq_region_end > $dest_slice_start;
708 } elsif ($seq_region_start <= $dest_slice_end) {
710 } elsif ($seq_region_end >= $dest_slice_start) {
711 $start += $seq_region_len;
712 $end += $seq_region_len;
714 } elsif ($seq_region_end <= $dest_slice_end) {
715 $end += $seq_region_len
if $end < 0;
717 } elsif ($seq_region_start > $seq_region_end) {
718 $end += $seq_region_len;
723 if ($seq_region_start <= $dest_slice_end and $seq_region_end >= $dest_slice_start) {
725 } elsif ($seq_region_start > $seq_region_end) {
726 if ($seq_region_start <= $dest_slice_end) {
727 $start -= $seq_region_len;
728 } elsif ($seq_region_end >= $dest_slice_start) {
729 $end += $seq_region_len;
735 $seq_region_start = $start;
736 $seq_region_end = $end;
737 $seq_region_strand *= -1;
739 } ## end
else [
if ( $dest_slice_strand...)]
741 # Throw away features off the end of the requested slice or on
742 # different seq_region.
743 if ($seq_region_end < 1
744 || $seq_region_start > $dest_slice_length
745 || ($dest_slice_sr_id != $seq_region_id)) {
748 $slice = $dest_slice;
751 # Finally, create the new exon.
753 $self->_create_feature_fast(
754 'Bio::EnsEMBL::Exon', {
755 'start' => $seq_region_start,
756 'end' => $seq_region_end,
757 'strand' => $seq_region_strand,
761 'stable_id' => $stable_id,
762 'version' => $version,
763 'created_date' => $created_date || undef,
764 'modified_date' => $modified_date || undef,
766 'end_phase' => $end_phase,
767 'is_current' => $is_current,
768 'is_constitutive' => $is_constitutive } )
771 } ## end
while ( $sth->fetch() )
774 } ## end sub _objs_from_sth