Archive Ensembl HomeArchive Ensembl Home
ExonAdaptor.pm
Go to the documentation of this file.
00001 =head1 LICENSE
00002 
00003   Copyright (c) 1999-2012 The European Bioinformatics Institute and
00004   Genome Research Limited.  All rights reserved.
00005 
00006   This software is distributed under a modified Apache license.
00007   For license details, please see
00008 
00009     http://www.ensembl.org/info/about/code_licence.html
00010 
00011 =head1 CONTACT
00012 
00013   Please email comments or questions to the public Ensembl
00014   developers list at <dev@ensembl.org>.
00015 
00016   Questions may also be sent to the Ensembl help desk at
00017   <helpdesk@ensembl.org>.
00018 
00019 =cut
00020 
00021 =head1 NAME
00022 
00023 Bio::EnsEMBL::DBSQL::ExonAdaptor - An adaptor responsible for the retrieval and
00024 storage of exon objects
00025 
00026 =head1 SYNOPSIS
00027 
00028   my $exon_adaptor = $registry->get_adaptor( 'Human', 'Core', 'Exon' );
00029 
00030   my $exon = $exon_adaptor->fetch_by_dbID($dbID);
00031 
00032 =head1 DESCRIPTION
00033 
00034 The ExonAdaptor is responsible for retrieving and storing Exon objects
00035 from an Ensembl database.  Most of the ExonAdaptor functionality is
00036 inherited from the B<Bio::EnsEMBL::DBSQL::BaseFeatureAdaptor> class.
00037 
00038 =head1 METHODS
00039 
00040 =cut
00041 
00042 package Bio::EnsEMBL::DBSQL::ExonAdaptor;
00043 
00044 use strict;
00045 
00046 use Bio::EnsEMBL::DBSQL::BaseFeatureAdaptor;
00047 use Bio::EnsEMBL::Exon;
00048 use Bio::EnsEMBL::Utils::Exception qw( warning throw deprecate );
00049  
00050 use vars qw( @ISA );
00051 @ISA = qw( Bio::EnsEMBL::DBSQL::BaseFeatureAdaptor );
00052 
00053 
00054 #_tables
00055 #
00056 #  Arg [1]    : none
00057 #  Example    : none
00058 #  Description: PROTECTED implementation of superclass abstract method
00059 #               returns the names, aliases of the tables to use for queries
00060 #  Returntype : list of listrefs of strings
00061 #  Exceptions : none
00062 #  Caller     : internal
00063 
00064 sub _tables {
00065   my $self = shift;
00066 
00067   # Allow the table definition to be overridden by certain methods.
00068   if ( defined( $self->{'tables'} ) ) {
00069     return @{ $self->{'tables'} };
00070   }
00071 
00072   return ( [ 'exon', 'e' ] );
00073 }
00074 
00075 
00076 # _columns
00077 #
00078 #  Arg [1]    : none
00079 #  Example    : none
00080 #  Description: PROTECTED implementation of superclass abstract method
00081 #               returns a list of columns to use for queries
00082 #  Returntype : list of strings
00083 #  Exceptions : none
00084 #  Caller     : internal
00085 
00086 sub _columns {
00087   my $self = shift;
00088 
00089   my $created_date =
00090     $self->db->dbc->from_date_to_seconds("created_date");
00091   my $modified_date =
00092     $self->db->dbc->from_date_to_seconds("modified_date");
00093 
00094   return (
00095     'e.exon_id',        'e.seq_region_id',     'e.seq_region_start',
00096     'e.seq_region_end', 'e.seq_region_strand', 'e.phase',
00097     'e.end_phase',      'e.is_current',        'e.is_constitutive',
00098     'e.stable_id',      'e.version',           $created_date,
00099     $modified_date
00100   );
00101 }
00102 
00103 
00104 
00105 # _final_clause
00106 #
00107 #  Arg [1]    : none
00108 #  Example    : none
00109 #  Description: PROTECTED implementation of superclass abstract method
00110 #               returns a default end for the SQL-query (ORDER BY)
00111 #  Returntype : string
00112 #  Exceptions : none
00113 #  Caller     : internal
00114 
00115 sub _final_clause {
00116   my $self = shift;
00117   return $self->{'final_clause'} || '';
00118 }
00119 
00120 
00121 sub fetch_all {
00122   my ($self) = @_;
00123 
00124   my $constraint = 'e.is_current = 1';
00125   my @exons  = @{ $self->generic_fetch($constraint) };
00126   return \@exons ;
00127 }
00128 
00129 =head2 fetch_by_stable_id
00130 
00131   Arg [1]    : string $stable_id
00132                the stable id of the exon to retrieve
00133   Example    : $exon = $exon_adaptor->fetch_by_stable_id('ENSE0000988221');
00134   Description: Retrieves an Exon from the database via its stable id
00135   Returntype : Bio::EnsEMBL::Exon in native coordinates.
00136   Exceptions : none
00137   Caller     : general
00138   Status     : Stable
00139 
00140 =cut
00141 
00142 sub fetch_by_stable_id {
00143   my ($self, $stable_id) = @_;
00144 
00145   my $constraint = "e.stable_id = ? AND e.is_current = 1";
00146 
00147   $self->bind_param_generic_fetch($stable_id,SQL_VARCHAR);
00148   my ($exon) = @{ $self->generic_fetch($constraint) };
00149 
00150   return $exon;
00151 }
00152 
00153 
00154 =head2 fetch_all_versions_by_stable_id 
00155 
00156   Arg [1]     : String $stable_id 
00157                 The stable ID of the exon to retrieve
00158   Example     : my $exon = $exon_adaptor->fetch_all_version_by_stable_id
00159                   ('ENSE00000309301');
00160   Description : Similar to fetch_by_stable_id, but retrieves all versions of an
00161                 exon stored in the database.
00162   Returntype  : listref of Bio::EnsEMBL::Exon objects
00163   Exceptions  : if we cant get the gene in given coord system
00164   Caller      : general
00165   Status      : At Risk
00166 
00167 =cut
00168 
00169 sub fetch_all_versions_by_stable_id {
00170   my ($self, $stable_id) = @_;
00171 
00172   my $constraint = "e.stable_id = ?";
00173 
00174   $self->bind_param_generic_fetch($stable_id,SQL_VARCHAR);
00175 
00176   return $self->generic_fetch($constraint);
00177 }
00178 
00179 
00180 =head2 fetch_all_by_Transcript
00181 
00182   Arg [1]    : Bio::EnsEMBL::Transcript $transcript
00183   Example    : none
00184   Description: Retrieves all Exons for the Transcript in 5-3 order
00185   Returntype : listref Bio::EnsEMBL::Exon on Transcript slice 
00186   Exceptions : throws if transcript has no slice
00187   Caller     : Transcript->get_all_Exons()
00188   Status     : Stable
00189 
00190 =cut
00191 
00192 sub fetch_all_by_Transcript {
00193   my ( $self, $transcript ) = @_;
00194 
00195   my $tslice = $transcript->slice();
00196   my $slice;
00197 
00198   if ( !defined($tslice) ) {
00199     throw("Transcript must have attached slice to retrieve exons.");
00200   }
00201 
00202   # use a small slice the same size as the transcript
00203   if ( !$tslice->is_circular() ) {
00204     $slice =
00205       $self->db()->get_SliceAdaptor()->fetch_by_Feature($transcript);
00206   } else {
00207     # Circular.
00208     $slice = $tslice;
00209   }
00210 
00211   # Override the tables definition to provide an additional join to the
00212   # exon_transcript table.  For efficiency we cannot afford to have this
00213   # in as a left join every time.
00214   my @tables = $self->_tables();
00215 
00216   # Be extra cautious so that we do not add 'exon_transcript' twice.
00217   my $found = 0;
00218   foreach my $table (@tables) {
00219     if ( $table->[0] eq 'exon_transcript' ) {
00220       $found = 1;
00221       last;
00222     }
00223   }
00224   if ( !$found ) {
00225     push @tables, [ 'exon_transcript', 'et' ];
00226   }
00227 
00228   $self->{'tables'}       = \@tables;
00229   $self->{'final_clause'} = "ORDER BY et.transcript_id, et.rank";
00230 
00231   my $constraint =
00232       "et.transcript_id = "
00233     . $transcript->dbID()
00234     . " AND e.exon_id = et.exon_id";
00235 
00236   # fetch all of the exons
00237   my $exons = $self->fetch_all_by_Slice_constraint($slice, $constraint);
00238 
00239   # un-override the table definition
00240   delete( $self->{'tables'} );
00241   delete( $self->{'final_clause'} );
00242 
00243   # remap exon coordinates if necessary
00244   if($slice->name() ne $tslice->name()) {
00245     my @out;
00246     foreach my $ex (@$exons) {
00247       push @out, $ex->transfer($tslice);
00248     }
00249     $exons = \@out;
00250   }
00251 
00252   return $exons;
00253 }
00254 
00255 
00256 =head2 store
00257 
00258   Arg [1]    : Bio::EnsEMBL::Exon $exon
00259                the exon to store in this database
00260   Example    : $exon_adaptor->store($exon);
00261   Description: Stores an exon in the database
00262   Returntype : none
00263   Exceptions : thrown if exon (or component exons) do not have a contig_id
00264                or if $exon->start, $exon->end, $exon->strand, or $exon->phase 
00265                are not defined or if $exon is not a Bio::EnsEMBL::Exon
00266   Caller     : general
00267   Status     : Stable
00268 
00269 =cut
00270 
00271 sub store {
00272   my ($self, $exon) = @_;
00273 
00274   if( ! $exon->isa('Bio::EnsEMBL::Exon') ) {
00275     throw("$exon is not a EnsEMBL exon - not storing.");
00276   }
00277 
00278   my $db = $self->db();
00279 
00280   if($exon->is_stored($db)) {
00281     return $exon->dbID();
00282   }
00283 
00284   if( ! $exon->start || ! $exon->end ||
00285       ! $exon->strand || ! defined $exon->phase ) {
00286     throw("Exon does not have all attributes to store");
00287   }
00288 
00289   # Default to is_current = 1 if this attribute is not set
00290   my $is_current = $exon->is_current();
00291   if ( !defined($is_current) ) { $is_current = 1 }
00292 
00293   # Default to is_constitutive = 0 if this attribute is not set
00294   my $is_constitutive = $exon->is_constitutive();
00295   if ( !defined($is_constitutive) ) { $is_constitutive = 0 }
00296 
00297   my $exon_sql = q{
00298     INSERT into exon ( seq_region_id, seq_region_start,
00299                seq_region_end, seq_region_strand, phase,
00300                end_phase, is_current, is_constitutive                      
00301   };
00302   if ( defined($exon->stable_id) ) {
00303       my $created = $self->db->dbc->from_seconds_to_date($exon->created_date());
00304       my $modified = $self->db->dbc->from_seconds_to_date($exon->modified_date());
00305       $exon_sql .= ", stable_id, version, created_date, modified_date) VALUES ( ?,?,?,?,?,?,?,?,?,?,". $created . ",". $modified ." )";
00306      
00307   } else {
00308       $exon_sql .= q{
00309          ) VALUES ( ?,?,?,?,?,?,?,?)
00310       };
00311   }
00312 
00313 
00314   my $exonst = $self->prepare($exon_sql);
00315 
00316   my $exonId = undef;
00317 
00318   my $original = $exon;
00319   my $seq_region_id;
00320   ($exon, $seq_region_id) = $self->_pre_store($exon);
00321 
00322   #store the exon
00323   $exonst->bind_param( 1, $seq_region_id,   SQL_INTEGER );
00324   $exonst->bind_param( 2, $exon->start,     SQL_INTEGER );
00325   $exonst->bind_param( 3, $exon->end,       SQL_INTEGER );
00326   $exonst->bind_param( 4, $exon->strand,    SQL_TINYINT );
00327   $exonst->bind_param( 5, $exon->phase,     SQL_TINYINT );
00328   $exonst->bind_param( 6, $exon->end_phase, SQL_TINYINT );
00329   $exonst->bind_param( 7, $is_current,      SQL_TINYINT );
00330   $exonst->bind_param( 8, $is_constitutive, SQL_TINYINT );
00331 
00332   if ( defined($exon->stable_id) ) {
00333 
00334      $exonst->bind_param( 9, $exon->stable_id, SQL_VARCHAR );
00335      my $version = ($exon->version()) ? $exon->version() : 1;
00336      $exonst->bind_param( 10, $version, SQL_INTEGER ); 
00337   }
00338 
00339   $exonst->execute();
00340   $exonId = $exonst->{'mysql_insertid'};
00341 
00342   # Now the supporting evidence
00343   my $esf_adaptor = $db->get_SupportingFeatureAdaptor;
00344   $esf_adaptor->store($exonId, $exon->get_all_supporting_features);
00345 
00346   #
00347   # Finally, update the dbID and adaptor of the exon (and any component exons)
00348   # to point to the new database
00349   #
00350 
00351   $original->adaptor($self);
00352   $original->dbID($exonId);
00353 
00354   return $exonId;
00355 }
00356 
00357 
00358 =head2 remove
00359 
00360   Arg [1]    : Bio::EnsEMBL::Exon $exon
00361                the exon to remove from the database
00362   Example    : $exon_adaptor->remove($exon);
00363   Description: Removes an exon from the database.  This method is generally
00364                called by the TranscriptAdaptor::store method. Database
00365                integrity will not be maintained if this method is simply
00366                called on its own without taking into account transcripts which
00367                may refer to the exon being removed.
00368   Returntype : none
00369   Exceptions : none
00370   Caller     : general
00371   Status     : Stable
00372 
00373 =cut
00374 
00375 sub remove {
00376   my $self = shift;
00377   my $exon = shift;
00378 
00379   if(!ref($exon) || !$exon->isa('Bio::EnsEMBL::Exon')) {
00380     throw('Bio::EnsEMBL::Exon argument expected.');
00381   }
00382 
00383   if(!$exon->is_stored($self->db())) {
00384     warning("Cannot remove exon " .$exon->dbID.
00385             "Is not stored in this database.");
00386     return;
00387   }
00388 
00389   # sanity check: make sure nobdody tries to slip past a prediction exon
00390   # which inherits from exon but actually uses different tables
00391   if($exon->isa('Bio::EnsEMBL::PredictionExon')) {
00392     throw("ExonAdaptor can only remove Exons not PredictionExons.");
00393   }
00394 
00395   # Remove the supporting features of this exon
00396 
00397   my $prot_adp = $self->db->get_ProteinAlignFeatureAdaptor;
00398   my $dna_adp = $self->db->get_DnaAlignFeatureAdaptor;
00399 
00400   my $sth = $self->prepare("SELECT feature_type, feature_id  " .
00401                            "FROM supporting_feature " .            
00402                "WHERE exon_id = ?");
00403   $sth->bind_param(1, $exon->dbID, SQL_INTEGER);
00404   $sth->execute();
00405 
00406   # statements to check for shared align_features
00407   my $sth1 = $self->prepare("SELECT count(*) FROM supporting_feature " .
00408                 "WHERE feature_type = ? AND feature_id = ?");
00409   my $sth2 = $self->prepare("SELECT count(*) " .
00410                             "FROM transcript_supporting_feature " .
00411                 "WHERE feature_type = ? AND feature_id = ?");
00412 
00413   SUPPORTING_FEATURE:
00414   while(my ($type, $feature_id) = $sth->fetchrow()){
00415     
00416     # only remove align_feature if this is the last reference to it
00417     $sth1->bind_param(1, $type, SQL_VARCHAR);
00418     $sth1->bind_param(2, $feature_id, SQL_INTEGER);
00419     $sth1->execute;
00420     $sth2->bind_param(1, $type, SQL_VARCHAR);
00421     $sth2->bind_param(2, $feature_id, SQL_INTEGER);
00422     $sth2->execute;
00423     my ($count1) = $sth1->fetchrow;
00424     my ($count2) = $sth2->fetchrow;
00425     if ($count1 + $count2 > 1) {
00426       #warn "shared feature, not removing $type|$feature_id\n";
00427       next SUPPORTING_FEATURE;
00428     }
00429     
00430     #warn "removing $type|$feature_id\n";
00431   
00432     if($type eq 'protein_align_feature'){
00433       my $f = $prot_adp->fetch_by_dbID($feature_id);
00434       $prot_adp->remove($f);
00435     }
00436     elsif($type eq 'dna_align_feature'){
00437       my $f = $dna_adp->fetch_by_dbID($feature_id);
00438       $dna_adp->remove($f);
00439     }
00440     else {
00441       warning("Unknown supporting feature type $type. Not removing feature.");
00442     }
00443   }
00444   $sth->finish();
00445   $sth1->finish();
00446   $sth2->finish();
00447 
00448   # delete the association to supporting features
00449 
00450   $sth = $self->prepare("DELETE FROM supporting_feature WHERE exon_id = ?");
00451   $sth->bind_param(1, $exon->dbID, SQL_INTEGER);
00452   $sth->execute();
00453   $sth->finish();
00454 
00455 
00456   # delete the exon
00457 
00458   $sth = $self->prepare( "DELETE FROM exon WHERE exon_id = ?" );
00459   $sth->bind_param(1, $exon->dbID, SQL_INTEGER);
00460   $sth->execute();
00461   $sth->finish();
00462 
00463   $exon->dbID(undef);
00464   $exon->adaptor(undef);
00465 
00466   return;
00467 }
00468 
00469 
00470 =head2 list_dbIDs
00471 
00472   Arg [1]    : none
00473   Example    : @exon_ids = @{$exon_adaptor->list_dbIDs()};
00474   Description: Gets an array of internal ids for all exons in the current db
00475   Arg[1]     : <optional> int. not 0 for the ids to be sorted by the seq_region.
00476   Returntype : list of ints
00477   Exceptions : none
00478   Caller     : ?
00479   Status     : Stable
00480 
00481 =cut
00482 
00483 sub list_dbIDs {
00484    my ($self, $ordered) = @_;
00485 
00486    return $self->_list_dbIDs("exon",undef, $ordered);
00487 }
00488 
00489 
00490 =head2 list_stable_ids
00491 
00492   Arg [1]    : none
00493   Example    : @stable_exon_ids = @{$exon_adaptor->list_stable_dbIDs()};
00494   Description: Gets an array of stable ids for all exons in the current db
00495   Returntype : list of ints
00496   Exceptions : none
00497   Caller     : ?
00498   Status     : Stable
00499 
00500 =cut
00501 
00502 sub list_stable_ids {
00503    my ($self) = @_;
00504 
00505    return $self->_list_dbIDs("exon", "stable_id");
00506 }
00507 
00508 #_objs_from_sth
00509 #
00510 #  Arg [1]    : StatementHandle $sth
00511 #  Example    : none 
00512 #  Description: PROTECTED implementation of abstract superclass method.
00513 #               responsible for the creation of Exons
00514 #  Returntype : listref of Bio::EnsEMBL::Exons in target coordinate system
00515 #  Exceptions : none
00516 #  Caller     : internal
00517 
00518 sub _objs_from_sth {
00519   my ( $self, $sth, $mapper, $dest_slice ) = @_;
00520 
00521   #
00522   # This code is ugly because an attempt has been made to remove as many
00523   # function calls as possible for speed purposes.  Thus many caches and
00524   # a fair bit of gymnastics is used.
00525   #
00526 
00527   my $sa = $self->db()->get_SliceAdaptor();
00528 
00529   my @exons;
00530   my %slice_hash;
00531   my %sr_name_hash;
00532   my %sr_cs_hash;
00533 
00534   my ( $exon_id,        $seq_region_id,     $seq_region_start,
00535        $seq_region_end, $seq_region_strand, $phase,
00536        $end_phase,      $is_current,        $is_constitutive,
00537        $stable_id,      $version,           $created_date,
00538        $modified_date );
00539 
00540   $sth->bind_columns( \( $exon_id, $seq_region_id, $seq_region_start,
00541                          $seq_region_end, $seq_region_strand, $phase,
00542                          $end_phase, $is_current, $is_constitutive,
00543                          $stable_id, $version,    $created_date,
00544                          $modified_date ) );
00545 
00546   my $asm_cs;
00547   my $cmp_cs;
00548   my $asm_cs_vers;
00549   my $asm_cs_name;
00550   my $cmp_cs_vers;
00551   my $cmp_cs_name;
00552 
00553   if ($mapper) {
00554     $asm_cs      = $mapper->assembled_CoordSystem();
00555     $cmp_cs      = $mapper->component_CoordSystem();
00556     $asm_cs_name = $asm_cs->name();
00557     $asm_cs_vers = $asm_cs->version();
00558     $cmp_cs_name = $cmp_cs->name();
00559     $cmp_cs_vers = $cmp_cs->version();
00560   }
00561 
00562   my $dest_slice_start;
00563   my $dest_slice_end;
00564   my $dest_slice_strand;
00565   my $dest_slice_length;
00566   my $dest_slice_cs;
00567   my $dest_slice_sr_name;
00568   my $dest_slice_sr_id;
00569   my $asma;
00570 
00571   if ($dest_slice) {
00572     $dest_slice_start   = $dest_slice->start();
00573     $dest_slice_end     = $dest_slice->end();
00574     $dest_slice_strand  = $dest_slice->strand();
00575     $dest_slice_length  = $dest_slice->length();
00576     $dest_slice_cs      = $dest_slice->coord_system();
00577     $dest_slice_sr_name = $dest_slice->seq_region_name();
00578     $dest_slice_sr_id   = $dest_slice->get_seq_region_id();
00579     $asma               = $self->db->get_AssemblyMapperAdaptor();
00580   }
00581 
00582 FEATURE: while ( $sth->fetch() ) {
00583     #need to get the internal_seq_region, if present
00584     $seq_region_id = $self->get_seq_region_id_internal($seq_region_id);
00585 
00586     my $slice       = $slice_hash{ "ID:" . $seq_region_id };
00587     my $dest_mapper = $mapper;
00588 
00589     if ( !$slice ) {
00590       $slice = $sa->fetch_by_seq_region_id($seq_region_id);
00591       $slice_hash{ "ID:" . $seq_region_id } = $slice;
00592       $sr_name_hash{$seq_region_id}         = $slice->seq_region_name();
00593       $sr_cs_hash{$seq_region_id}           = $slice->coord_system();
00594     }
00595 
00596     #obtain a mapper if none was defined, but a dest_seq_region was
00597     if (   !$dest_mapper
00598          && $dest_slice
00599          && !$dest_slice_cs->equals( $slice->coord_system ) )
00600     {
00601       $dest_mapper =
00602         $asma->fetch_by_CoordSystems( $dest_slice_cs,
00603                                       $slice->coord_system );
00604       $asm_cs      = $dest_mapper->assembled_CoordSystem();
00605       $cmp_cs      = $dest_mapper->component_CoordSystem();
00606       $asm_cs_name = $asm_cs->name();
00607       $asm_cs_vers = $asm_cs->version();
00608       $cmp_cs_name = $cmp_cs->name();
00609       $cmp_cs_vers = $cmp_cs->version();
00610     }
00611 
00612     my $sr_name = $sr_name_hash{$seq_region_id};
00613     my $sr_cs   = $sr_cs_hash{$seq_region_id};
00614 
00615     #
00616     # Remap the feature coordinates to another coord system if a mapper
00617     # was provided.
00618     #
00619     if ( defined($dest_mapper) ) {
00620       ( $seq_region_id,  $seq_region_start,
00621         $seq_region_end, $seq_region_strand )
00622         = $dest_mapper->fastmap( $sr_name, $seq_region_start,
00623                                  $seq_region_end, $seq_region_strand,
00624                                  $sr_cs );
00625 
00626       # Skip features that map to gaps or coord system boundaries.
00627       if ( !defined($seq_region_id) ) { next FEATURE }
00628 
00629       # Get a slice in the coord system we just mapped to
00630       $slice = $slice_hash{ "ID:" . $seq_region_id } ||=
00631         $sa->fetch_by_seq_region_id($seq_region_id);
00632     }
00633 
00634     #
00635     # If a destination slice was provided convert the coords.
00636     #
00637     if ( defined($dest_slice) ) {
00638       if ( $dest_slice_strand == 1 ) {
00639         # On the positive strand.
00640 
00641         $seq_region_start = $seq_region_start - $dest_slice_start + 1;
00642         $seq_region_end   = $seq_region_end - $dest_slice_start + 1;
00643 
00644     if ( ( $seq_region_end > $dest_slice_start || $seq_region_end < 0 || ( $dest_slice_start > $dest_slice_end
00645                  && $seq_region_end < 0 ) )  && $dest_slice->is_circular() ) {
00646           # Handle circular chromosomes.
00647 
00648           if ( $seq_region_start > $seq_region_end ) {
00649             # Looking at a feature overlapping the chromsome origin.
00650 
00651             if ( $seq_region_end > $dest_slice_start ) {
00652               # Looking at the region in the beginning of the
00653               # chromosome.
00654               $seq_region_start -= $dest_slice->seq_region_length();
00655             }
00656 
00657             if ( $seq_region_end < 0 ) {
00658               $seq_region_end += $dest_slice->seq_region_length();
00659             }
00660 
00661           } else {
00662             if (    $dest_slice_start > $dest_slice_end
00663                  && $seq_region_end < 0 )
00664             {
00665               # Looking at the region overlapping the chromosome
00666               # origin and a feature which is at the beginning of the
00667               # chromosome.
00668               $seq_region_start += $dest_slice->seq_region_length();
00669               $seq_region_end   += $dest_slice->seq_region_length();
00670             }
00671           }
00672         } 
00673 
00674       } else {
00675         # On the negative strand.
00676 
00677         if ( $seq_region_start > $seq_region_end && $dest_slice->is_circular() )
00678         {
00679           # Handle circular chromosomes.
00680 
00681           if ( $dest_slice_start > $dest_slice_end ) {
00682             my $tmp_seq_region_start = $seq_region_start;
00683             $seq_region_start = $dest_slice_end - $seq_region_end + 1;
00684             $seq_region_end =
00685               $dest_slice_end +
00686               $dest_slice->seq_region_length() -
00687               $tmp_seq_region_start + 1;
00688           } else {
00689 
00690             if ( $seq_region_end > $dest_slice_start ) {
00691               # Looking at the region in the beginning of the
00692               # chromosome.
00693               $seq_region_start = $dest_slice_end - $seq_region_end + 1;
00694               $seq_region_end =
00695                 $seq_region_end -
00696                 $dest_slice->seq_region_length() -
00697                 $dest_slice_start + 1;
00698             } else {
00699               my $tmp_seq_region_start = $seq_region_start;
00700               $seq_region_start =
00701                 $dest_slice_end -
00702                 $seq_region_end -
00703                 $dest_slice->seq_region_length() + 1;
00704               $seq_region_end =
00705                 $dest_slice_end - $tmp_seq_region_start + 1;
00706             }
00707 
00708           }
00709 
00710         } else {
00711           # Non-circular chromosome.
00712 
00713           my $tmp_seq_region_start = $seq_region_start;
00714           $seq_region_start = $dest_slice_end - $seq_region_end + 1;
00715           $seq_region_end = $dest_slice_end - $tmp_seq_region_start + 1;
00716         }
00717 
00718         $seq_region_strand = -$seq_region_strand;
00719 
00720       } ## end else [ if ( $dest_slice_strand...)]
00721 
00722       # Throw away features off the end of the requested slice.
00723       if (    $seq_region_end < 1
00724            || $seq_region_start > $dest_slice_length
00725            || ( $dest_slice_sr_id != $seq_region_id ) )
00726       {
00727         next FEATURE;
00728       }
00729 
00730       $slice = $dest_slice;
00731     } ## end if ( defined($dest_slice...))
00732 
00733     # Finally, create the new exon.
00734     push( @exons,
00735           $self->_create_feature_fast(
00736                            'Bio::EnsEMBL::Exon', {
00737                              'start'         => $seq_region_start,
00738                              'end'           => $seq_region_end,
00739                              'strand'        => $seq_region_strand,
00740                              'adaptor'       => $self,
00741                              'slice'         => $slice,
00742                              'dbID'          => $exon_id,
00743                              'stable_id'     => $stable_id,
00744                              'version'       => $version,
00745                              'created_date'  => $created_date || undef,
00746                              'modified_date' => $modified_date || undef,
00747                              'phase'         => $phase,
00748                              'end_phase'     => $end_phase,
00749                              'is_current'    => $is_current,
00750                              'is_constitutive' => $is_constitutive } )
00751     );
00752 
00753   } ## end while ( $sth->fetch() )
00754 
00755   return \@exons;
00756 } ## end sub _objs_from_sth
00757 
00758 =head1 DEPRECATED METHODS
00759 
00760 =cut
00761 
00762 
00763 =head2 get_stable_entry_info
00764 
00765   Description: DEPRECATED. This method is no longer necessary.  Exons are
00766                always fetched with their stable identifiers (if they exist) and
00767                no lazy loading is necessary.
00768 
00769 =cut
00770 
00771 sub get_stable_entry_info {
00772   my ($self,$exon) = @_;
00773 
00774   deprecated( "This method call shouldnt be necessary" );
00775 
00776   if( !$exon || !ref $exon || !$exon->isa('Bio::EnsEMBL::Exon') ) {
00777      $self->throw("Needs a exon object, not a $exon");
00778   }
00779   if(!$exon->dbID){
00780     #$self->throw("can't fetch stable info with no dbID");
00781     return;
00782   }
00783 
00784   my $created_date = $self->db->dbc->from_date_to_seconds("created_date");
00785   my $modified_date = $self->db->dbc->from_date_to_seconds("modified_date");
00786   my $sth = $self->prepare("SELECT stable_id, " . $created_date . ",
00787                                    " . $modified_date . ", version 
00788                             FROM   exon
00789                             WHERE  exon_id = ");
00790 
00791   $sth->bind_param(1, $exon->dbID, SQL_INTEGER);
00792   $sth->execute();
00793 
00794   # my @array = $sth->fetchrow_array();
00795   if( my $aref = $sth->fetchrow_arrayref() ) {
00796     $exon->{'_stable_id'} = $aref->[0];
00797     $exon->{'_created'}   = $aref->[1];
00798     $exon->{'_modified'}  = $aref->[2];
00799     $exon->{'_version'}   = $aref->[3];
00800   }
00801 
00802   return 1;
00803 }
00804 
00805 
00806 =head2 fetch_all_by_gene_id
00807 
00808   Description: DEPRECATED. This method should not be needed - Exons can
00809                be fetched by Transcript.
00810 
00811 =cut
00812 
00813 sub fetch_all_by_gene_id {
00814   my ( $self, $gene_id ) = @_;
00815   my %exons;
00816   my $hashRef;
00817   my ( $currentId, $currentTranscript );
00818 
00819   deprecated( "Hopefully this method is not needed any more. Exons should be fetched by Transcript" );
00820 
00821   if( !$gene_id ) {
00822       $self->throw("Gene dbID not defined");
00823   }
00824   
00825   $self->{rchash} = {};
00826   
00827   my $query = qq {
00828     SELECT 
00829       STRAIGHT_JOIN 
00830     e.exon_id
00831       , e.contig_id
00832       , e.contig_start
00833       , e.contig_end
00834       , e.contig_strand
00835       , e.phase
00836       , e.end_phase
00837       , e.sticky_rank
00838     FROM transcript t
00839       , exon_transcript et
00840       , exon e
00841     WHERE t.gene_id = ?
00842       AND et.transcript_id = t.transcript_id
00843       AND e.exon_id = et.exon_id
00844     ORDER BY t.transcript_id,e.exon_id
00845       , e.sticky_rank DESC
00846   };
00847 
00848   my $sth = $self->prepare( $query );
00849   $sth->bind_param(1,$gene_id,SQL_INTEGER);
00850   $sth->execute();
00851 
00852   while( $hashRef = $sth->fetchrow_hashref() ) {
00853     if( ! exists $exons{ $hashRef->{exon_id} } ) {
00854 
00855       my $exon = $self->_exon_from_sth( $sth, $hashRef );
00856 
00857       $exons{$exon->dbID} = $exon;
00858     }
00859   }
00860   delete $self->{rchash};
00861   
00862   my @out = ();
00863 
00864   push @out, values %exons;
00865 
00866   return \@out;
00867 }
00868 
00869 
00870 1;
00871 
00872