<commit_before>#EnsEMBL Exon reading writing adaptor for mySQL
#
# Copyright EMBL-EBI 2001
#
# Author: <NAME>
# based on
# Elia Stupkas Gene_Obj
#
# Date : 20.02.2001
#

=head1 NAME

Bio::EnsEMBL::DBSQL::ExonAdaptor - An adaptor responsible for the retrieval and
storage of exon objects

=head1 SYNOPSIS

  $exon_adaptor = $database_adaptor->get_ExonAdaptor();
  $exon = $exon_adaptor->fetch_by_dbID($dbID);

=head1 DESCRIPTION

The ExonAdaptor is responsible for retrieving and storing Exon objects from an
Ensembl database.  Most of the ExonAdaptor functionality is inherited from the
B<Bio::EnsEMBL::DBSQL::BaseFeatureAdaptor> class.

=head1 CONTACT

Post questions/comments to the Ensembl dev list: <EMAIL>

=head1 METHODS

=cut

package Bio::EnsEMBL::DBSQL::ExonAdaptor;

use vars qw( @ISA );
use strict;


use Bio::EnsEMBL::DBSQL::BaseFeatureAdaptor;
use Bio::EnsEMBL::Exon;
use Bio::EnsEMBL::Utils::Exception qw( warning throw deprecate );
 
@ISA = qw( Bio::EnsEMBL::DBSQL::BaseFeatureAdaptor );



#_tables
#
#  Arg [1]    : none
#  Example    : none
#  Description: PROTECTED implementation of superclass abstract method
#               returns the names, aliases of the tables to use for queries
#  Returntype : list of listrefs of strings
#  Exceptions : none
#  Caller     : internal

sub _tables {
  my $self = shift;

  ##allow the table definition to be overridden by certain methods
  return ($self->{'tables'}) ? 
           @{$self->{'tables'}} :
           ([ 'exon', 'e' ], [ 'exon_stable_id', 'esi' ] );
}


# _columns
#
#  Arg [1]    : none
#  Example    : none
#  Description: PROTECTED implementation of superclass abstract method
#               returns a list of columns to use for queries
#  Returntype : list of strings
#  Exceptions : none
#  Caller     : internal

sub _columns {
  my $self = shift;

  return qw( e.exon_id e.seq_region_id e.seq_region_start e.seq_region_end 
	     e.seq_region_strand e.phase e.end_phase
	     esi.stable_id esi.version );
}


sub _left_join {
  return ( [ 'exon_stable_id', "esi.exon_id = e.exon_id" ]);
}



# _final_clause
#
#  Arg [1]    : none
#  Example    : none
#  Description: PROTECTED implementation of superclass abstract method
#               returns a default end for the SQL-query (ORDER BY)
#  Returntype : string
#  Exceptions : none
#  Caller     : internal

sub _final_clause {
  my $self = shift;
  return $self->{'final_clause'} || '';
}



=head2 fetch_by_stable_id

  Arg [1]    : string $stable_id
               the stable id of the exon to retrieve
  Example    : $exon = $exon_adaptor->fetch_by_stable_id('ENSE0000988221');
  Description: Retrieves an Exon from the database via its stable id
  Returntype : Bio::EnsEMBL::Exon in contig coordinates
  Exceptions : none
  Caller     : general

=cut

sub fetch_by_stable_id {
  my ( $self, $stable_id ) = @_;

  my $constraint = "esi.stable_id = \"$stable_id\"";

  # should be only one :-)
  my $exons = $self->SUPER::generic_fetch( $constraint );

  if( ! @$exons ) { return undef }

  return $exons->[0];
}


=head2 fetch_all_by_Transcript

  Arg [1]    : Bio::EnsEMBL::Transcript $transcript
  Example    : none
  Description: Retrieves all Exons for the Transcript in 5-3 order
  Returntype : listref Bio::EnsEMBL::Exon on Transcript slice 
  Exceptions : none
  Caller     : Transcript->get_all_Exons()

=cut

sub fetch_all_by_Transcript {
  my ( $self, $transcript ) = @_;

  ##override the tables definition to provide an additional join to
  # the exon_transcript table.  For efficiency we cannot afford to have
  # this in as a left join every time.
  my @tables = $self->_tables();
  push @tables, ['exon_transcript', 'et'];
  $self->{'tables'} = \@tables;
  $self->{'final_clause'} = "ORDER BY et.transcript_id, et.rank";


  my $constraint = "et.transcript_id = ".$transcript->dbID() .
                   " AND e.exon_id = et.exon_id";

  #fetch exons, remap them to the transcripts slice, and
  # keep even exons which fall off end of slice
  my $keep_all = 1;
  my $exons = $self->generic_fetch( $constraint, undef,
                                    $transcript->slice(), $keep_all);

  #un-override the table definition
  $self->{'tables'} = undef;
  $self->{'final_clause'} = undef;

  return $exons;
}



=head2 store

  Arg [1]    : Bio::EnsEMBL::Exon $exon
               the exon to store in this database
  Example    : $exon_adaptor->store($exon);
  Description: Stores an exon in the database
  Returntype : none
  Exceptions : thrown if exon (or component exons) do not have a contig_id
               or if $exon->start, $exon->end, $exon->strand, or $exon->phase 
               are not defined or if $exon is not a Bio::EnsEMBL::Exon
  Caller     : general

=cut

sub store {
  my ( $self, $exon ) = @_;

  if( ! $exon->isa('Bio::EnsEMBL::Exon') ) {
    throw("$exon is not a EnsEMBL exon - not storing.");
  }

  my $db = $self->db();

  if($exon->is_stored($db)) {
    return $exon->dbID();
  }

  if( ! $exon->start || ! $exon->end ||
      ! $exon->strand || ! defined $exon->phase ) {
    throw("Exon does not have all attributes to store");
  }

  my $exon_sql = q{
    INSERT into exon ( seq_region_id, seq_region_start,
		       seq_region_end, seq_region_strand, phase,
		       end_phase )
    VALUES ( ?, ?, ?, ?, ?, ? )
  };

  my $exonst = $self->prepare($exon_sql);

  my $exonId = undef;

  my $original = $exon;
  my $seq_region_id;
  ($exon, $seq_region_id) = $self->_pre_store($exon);

  #store the exon
  $exonst->execute( $seq_region_id,
                    $exon->start(),
                    $exon->end(),
                    $exon->strand(),
                    $exon->phase(),
                    $exon->end_phase());
  $exonId = $exonst->{'mysql_insertid'};

  #store any stable_id information
  if ($exon->stable_id && $exon->version()) {
    my $sth = $self->prepare(
      "INSERT INTO exon_stable_id " .
      "SET version = ?, " .
          "stable_id = ?, " .
          "exon_id = ?");

    $sth->execute( $exon->version, $exon->stable_id, $exonId );
  }

  # Now the supporting evidence
  # should be stored from featureAdaptor
  my $sql = "insert into supporting_feature (exon_id, feature_id, feature_type)
             values(?, ?, ?)";

  my $sf_sth = $self->prepare($sql);

  my $anaAdaptor = $self->db->get_AnalysisAdaptor();
  my $dna_adaptor = $self->db->get_DnaAlignFeatureAdaptor();
  my $pep_adaptor = $self->db->get_ProteinAlignFeatureAdaptor();
  my $type;

  foreach my $sf (@{$exon->get_all_supporting_features}) {
    if(!$sf->isa("Bio::EnsEMBL::BaseAlignFeature")){
      throw("$sf must be an align feature otherwise" .
            "it can't be stored");
    }

    if($sf->isa("Bio::EnsEMBL::DnaDnaAlignFeature")){
      $dna_adaptor->store($sf);
      $type = 'dna_align_feature';
    }elsif($sf->isa("Bio::EnsEMBL::DnaPepAlignFeature")){
      $pep_adaptor->store($sf);
      $type = 'protein_align_feature';
    } else {
      warning("Supporting feature of unknown type. Skipping : [$sf]\n");
      next;
    }

    $sf_sth->execute($exonId, $sf->dbID, $type);
  }

  #
  # Finally, update the dbID and adaptor of the exon (and any component exons)
  # to point to the new database
  #

  $original->adaptor($self);
  $original->dbID($exonId);

  return $exonId;
}


=head2 remove

  Arg [1]    : Bio::EnsEMBL::Exon $exon
               the exon to remove from the database
  Example    : $exon_adaptor->remove($exon);
  Description: Removes an exon from the database.  This method is generally
               called by the TranscriptAdaptor::store method. Database
               integrity will not be maintained if this method is simply
               called on its own without taking into account transcripts which
               may refer to the exon being removed.
  Returntype : none
  Exceptions : none
  Caller     : general

=cut

sub remove {
  my $self = shift;
  my $exon = shift;

  if(!ref($exon) || !$exon->isa('Bio::EnsEMBL::Exon')) {
    throw('Bio::EnsEMBL::Exon argument expected.');
  }

  if(!$exon->is_stored($self->db())) {
    warning("Cannot remove exon " .$exon->dbID.
            "Is not stored in this database.");
    return;
  }

  # sanity check: make sure nobdody tries to slip past a prediction exon
  # which inherits from exon but actually uses different tables
  if($exon->isa('Bio::EnsEMBL::PredictionExon')) {
    throw("ExonAdaptor can only remove Exons not PredictionExons.");
  }

  # delete the association to supporting features, but not the alignment
  # features themselves.

  my $sth = $self->prepare("DELETE FROM supporting_feature WHERE exon_id = ?");
  $sth->execute( $exon->dbID );

  # delete the exon stable identifier

  $sth = $self->prepare( "DELETE FROM exon_stable_id WHERE exon_id = ?" );
  $sth->execute( $exon->dbID );
  $sth->finish();

  # delete the exon

  $sth = $self->prepare( "DELETE FROM exon WHERE exon_id = ?" );
  $sth->execute( $exon->dbID );
  $sth->finish();

  $exon->dbID(undef);
  $exon->adaptor(undef);

  return;
}


=head2 list_dbIDs

  Arg [1]    : none
  Example    : @exon_ids = @{$exon_adaptor->list_dbIDs()};
  Description: Gets an array of internal ids for all exons in the current db
  Returntype : list of ints
  Exceptions : none
  Caller     : ?<commit_msg>remove method now removes supporting align features just as it used to<commit_after>#EnsEMBL Exon reading writing adaptor for mySQL
#
# Copyright EMBL-EBI 2001
#
# Author: <NAME>
# based on
# Elia Stupkas Gene_Obj
#
# Date : 20.02.2001
#

=head1 NAME

Bio::EnsEMBL::DBSQL::ExonAdaptor - An adaptor responsible for the retrieval and
storage of exon objects

=head1 SYNOPSIS

  $exon_adaptor = $database_adaptor->get_ExonAdaptor();
  $exon = $exon_adaptor->fetch_by_dbID($dbID);

=head1 DESCRIPTION

The ExonAdaptor is responsible for retrieving and storing Exon objects from an
Ensembl database.  Most of the ExonAdaptor functionality is inherited from the
B<Bio::EnsEMBL::DBSQL::BaseFeatureAdaptor> class.

=head1 CONTACT

Post questions/comments to the Ensembl dev list: <EMAIL>

=head1 METHODS

=cut

package Bio::EnsEMBL::DBSQL::ExonAdaptor;

use vars qw( @ISA );
use strict;


use Bio::EnsEMBL::DBSQL::BaseFeatureAdaptor;
use Bio::EnsEMBL::Exon;
use Bio::EnsEMBL::Utils::Exception qw( warning throw deprecate );
 
@ISA = qw( Bio::EnsEMBL::DBSQL::BaseFeatureAdaptor );



#_tables
#
#  Arg [1]    : none
#  Example    : none
#  Description: PROTECTED implementation of superclass abstract method
#               returns the names, aliases of the tables to use for queries
#  Returntype : list of listrefs of strings
#  Exceptions : none
#  Caller     : internal

sub _tables {
  my $self = shift;

  ##allow the table definition to be overridden by certain methods
  return ($self->{'tables'}) ? 
           @{$self->{'tables'}} :
           ([ 'exon', 'e' ], [ 'exon_stable_id', 'esi' ] );
}


# _columns
#
#  Arg [1]    : none
#  Example    : none
#  Description: PROTECTED implementation of superclass abstract method
#               returns a list of columns to use for queries
#  Returntype : list of strings
#  Exceptions : none
#  Caller     : internal

sub _columns {
  my $self = shift;

  return qw( e.exon_id e.seq_region_id e.seq_region_start e.seq_region_end 
	     e.seq_region_strand e.phase e.end_phase
	     esi.stable_id esi.version );
}


sub _left_join {
  return ( [ 'exon_stable_id', "esi.exon_id = e.exon_id" ]);
}



# _final_clause
#
#  Arg [1]    : none
#  Example    : none
#  Description: PROTECTED implementation of superclass abstract method
#               returns a default end for the SQL-query (ORDER BY)
#  Returntype : string
#  Exceptions : none
#  Caller     : internal

sub _final_clause {
  my $self = shift;
  return $self->{'final_clause'} || '';
}



=head2 fetch_by_stable_id

  Arg [1]    : string $stable_id
               the stable id of the exon to retrieve
  Example    : $exon = $exon_adaptor->fetch_by_stable_id('ENSE0000988221');
  Description: Retrieves an Exon from the database via its stable id
  Returntype : Bio::EnsEMBL::Exon in contig coordinates
  Exceptions : none
  Caller     : general

=cut

sub fetch_by_stable_id {
  my ( $self, $stable_id ) = @_;

  my $constraint = "esi.stable_id = \"$stable_id\"";

  # should be only one :-)
  my $exons = $self->SUPER::generic_fetch( $constraint );

  if( ! @$exons ) { return undef }

  return $exons->[0];
}


=head2 fetch_all_by_Transcript

  Arg [1]    : Bio::EnsEMBL::Transcript $transcript
  Example    : none
  Description: Retrieves all Exons for the Transcript in 5-3 order
  Returntype : listref Bio::EnsEMBL::Exon on Transcript slice 
  Exceptions : none
  Caller     : Transcript->get_all_Exons()

=cut

sub fetch_all_by_Transcript {
  my ( $self, $transcript ) = @_;

  ##override the tables definition to provide an additional join to
  # the exon_transcript table.  For efficiency we cannot afford to have
  # this in as a left join every time.
  my @tables = $self->_tables();
  push @tables, ['exon_transcript', 'et'];
  $self->{'tables'} = \@tables;
  $self->{'final_clause'} = "ORDER BY et.transcript_id, et.rank";


  my $constraint = "et.transcript_id = ".$transcript->dbID() .
                   " AND e.exon_id = et.exon_id";

  #fetch exons, remap them to the transcripts slice, and
  # keep even exons which fall off end of slice
  my $keep_all = 1;
  my $exons = $self->generic_fetch( $constraint, undef,
                                    $transcript->slice(), $keep_all);

  #un-override the table definition
  $self->{'tables'} = undef;
  $self->{'final_clause'} = undef;

  return $exons;
}



=head2 store

  Arg [1]    : Bio::EnsEMBL::Exon $exon
               the exon to store in this database
  Example    : $exon_adaptor->store($exon);
  Description: Stores an exon in the database
  Returntype : none
  Exceptions : thrown if exon (or component exons) do not have a contig_id
               or if $exon->start, $exon->end, $exon->strand, or $exon->phase 
               are not defined or if $exon is not a Bio::EnsEMBL::Exon
  Caller     : general

=cut

sub store {
  my ( $self, $exon ) = @_;

  if( ! $exon->isa('Bio::EnsEMBL::Exon') ) {
    throw("$exon is not a EnsEMBL exon - not storing.");
  }

  my $db = $self->db();

  if($exon->is_stored($db)) {
    return $exon->dbID();
  }

  if( ! $exon->start || ! $exon->end ||
      ! $exon->strand || ! defined $exon->phase ) {
    throw("Exon does not have all attributes to store");
  }

  my $exon_sql = q{
    INSERT into exon ( seq_region_id, seq_region_start,
		       seq_region_end, seq_region_strand, phase,
		       end_phase )
    VALUES ( ?, ?, ?, ?, ?, ? )
  };

  my $exonst = $self->prepare($exon_sql);

  my $exonId = undef;

  my $original = $exon;
  my $seq_region_id;
  ($exon, $seq_region_id) = $self->_pre_store($exon);

  #store the exon
  $exonst->execute( $seq_region_id,
                    $exon->start(),
                    $exon->end(),
                    $exon->strand(),
                    $exon->phase(),
                    $exon->end_phase());
  $exonId = $exonst->{'mysql_insertid'};

  #store any stable_id information
  if ($exon->stable_id && $exon->version()) {
    my $sth = $self->prepare(
      "INSERT INTO exon_stable_id " .
      "SET version = ?, " .
          "stable_id = ?, " .
          "exon_id = ?");

    $sth->execute( $exon->version, $exon->stable_id, $exonId );
  }

  # Now the supporting evidence
  # should be stored from featureAdaptor
  my $sql = "insert into supporting_feature (exon_id, feature_id, feature_type)
             values(?, ?, ?)";

  my $sf_sth = $self->prepare($sql);

  my $anaAdaptor = $self->db->get_AnalysisAdaptor();
  my $dna_adaptor = $self->db->get_DnaAlignFeatureAdaptor();
  my $pep_adaptor = $self->db->get_ProteinAlignFeatureAdaptor();
  my $type;

  foreach my $sf (@{$exon->get_all_supporting_features}) {
    if(!$sf->isa("Bio::EnsEMBL::BaseAlignFeature")){
      throw("$sf must be an align feature otherwise" .
            "it can't be stored");
    }

    if($sf->isa("Bio::EnsEMBL::DnaDnaAlignFeature")){
      $dna_adaptor->store($sf);
      $type = 'dna_align_feature';
    }elsif($sf->isa("Bio::EnsEMBL::DnaPepAlignFeature")){
      $pep_adaptor->store($sf);
      $type = 'protein_align_feature';
    } else {
      warning("Supporting feature of unknown type. Skipping : [$sf]\n");
      next;
    }

    $sf_sth->execute($exonId, $sf->dbID, $type);
  }

  #
  # Finally, update the dbID and adaptor of the exon (and any component exons)
  # to point to the new database
  #

  $original->adaptor($self);
  $original->dbID($exonId);

  return $exonId;
}


=head2 remove

  Arg [1]    : Bio::EnsEMBL::Exon $exon
               the exon to remove from the database
  Example    : $exon_adaptor->remove($exon);
  Description: Removes an exon from the database.  This method is generally
               called by the TranscriptAdaptor::store method. Database
               integrity will not be maintained if this method is simply
               called on its own without taking into account transcripts which
               may refer to the exon being removed.
  Returntype : none
  Exceptions : none
  Caller     : general

=cut

sub remove {
  my $self = shift;
  my $exon = shift;

  if(!ref($exon) || !$exon->isa('Bio::EnsEMBL::Exon')) {
    throw('Bio::EnsEMBL::Exon argument expected.');
  }

  if(!$exon->is_stored($self->db())) {
    warning("Cannot remove exon " .$exon->dbID.
            "Is not stored in this database.");
    return;
  }

  # sanity check: make sure nobdody tries to slip past a prediction exon
  # which inherits from exon but actually uses different tables
  if($exon->isa('Bio::EnsEMBL::PredictionExon')) {
    throw("ExonAdaptor can only remove Exons not PredictionExons.");
  }

  # Remove the supporting features of this exon

  my $prot_adp = $self->db->get_ProteinAlignFeatureAdaptor;
  my $dna_adp = $self->db->get_DnaAlignFeatureAdaptor;

  my $sth = $self->prepare("SELECT feature_type, feature_id  " .
                           "FROM supporting_feature " .
                           "WHERE exon_id = ?");
  $sth->execute($exon->dbID);

  while(my ($type, $feature_id) = $sth->fetchrow()){
    if($type eq 'protein_align_feature'){
      my $f = $prot_adp->fetch_by_dbID($feature_id);
      $prot_adp->remove($f);
    }
    elsif($type eq 'dna_align_feature'){
      my $f = $dna_adp->fetch_by_dbID($feature_id);
      $dna_adp->remove($f);
    }
    else {
      warning("Unknown supporting feature type $type. Not removing feature.");
    }
  }
  $sth->finish();

  # delete the association to supporting features

  $sth = $self->prepare("DELETE FROM supporting_feature WHERE exon_id = ?");
  $sth->execute( $exon->dbID );
  $sth->finish();

  # delete the exon stable identifier

  $sth = $self->prepare( "DELETE FROM exon_stable_id WHERE exon_id = ?" );
  $sth->execute( $exon->dbID );
  $sth->finish();

  # delete the exon

  $sth = $self->prepare( "DELETE FROM exon WHERE exon_id = ?" );
  $sth->execute( $exon->dbID );
  $sth->finish();

  $exon->dbID(undef);
  $exon->adaptor(undef);

  return;
}


=head2 list_dbIDs

  Arg [1]    : none
  Example    : @exon_ids = @{$exon_adaptor->list_dbIDs()};
  Description: Gets an array of internal ids for all exons in the current db
  Returntype : list of ints
  Exceptions : none
  Caller     : ?
{'fraction_non_alphanumeric': 0.13151236639644756, 'fraction_numerical': 0.004543811638353901, 'mean_word_length': 3.036681950812839, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 187, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7045875', 'n_tokens_mistral': 7045, 'n_tokens_neox': 6548, 'n_words': 1794}