Raw content of Bio::EnsEMBL::DBSQL::AssemblyExceptionFeatureAdaptor
=head1 LICENSE
Copyright (c) 1999-2009 The European Bioinformatics Institute and
Genome Research Limited. All rights reserved.
This software is distributed under a modified Apache license.
For license details, please see
/info/about/code_licence.html
=head1 CONTACT
Please email comments or questions to the public Ensembl
developers list at .
Questions may also be sent to the Ensembl help desk at
.
=cut
=head1 NAME
Bio::EnsEMBL::DBSQL::AssemblyExceptionFeatureAdaptor
=head1 SYNOPSIS
my $assembly_exception_feature_adaptor =
$database_adaptor->get_AssemblyExceptionFeatureAdaptor();
@assembly_exception_features =
$assembly_exception_feature_adaptor->fetch_all_by_Slice($slice);
=head1 DESCRIPTION
Assembly Exception Feature Adaptor - database access for assembly
exception features.
=head1 METHODS
=cut
package Bio::EnsEMBL::DBSQL::AssemblyExceptionFeatureAdaptor;
use strict;
use warnings;
no warnings qw(uninitialized);
use Bio::EnsEMBL::DBSQL::BaseAdaptor;
use Bio::EnsEMBL::DBSQL::BaseFeatureAdaptor;
use Bio::EnsEMBL::AssemblyExceptionFeature;
use Bio::EnsEMBL::Utils::Exception qw(throw warning);
use Bio::EnsEMBL::Utils::Cache;
our @ISA = qw(Bio::EnsEMBL::DBSQL::BaseAdaptor);
# set the number of slices you'd like to cache
our $ASSEMBLY_EXCEPTION_FEATURE_CACHE_SIZE = 100;
=head2 new
Arg [1] : list of args @args
Superclass constructor arguments
Example : none
Description: Constructor which just initializes internal cache structures
Returntype : Bio::EnsEMBL::DBSQL::AssemblyExceptionFeatureAdaptor
Exceptions : none
Caller : implementing subclass constructors
Status : Stable
=cut
sub new {
my $caller = shift;
my $class = ref($caller) || $caller;
my $self = $class->SUPER::new(@_);
# initialize an LRU cache for slices
my %cache;
tie(%cache, 'Bio::EnsEMBL::Utils::Cache',
$ASSEMBLY_EXCEPTION_FEATURE_CACHE_SIZE);
$self->{'_aexc_slice_cache'} = \%cache;
return $self;
}
=head2 fetch_all
Arg [1] : none
Example : my @axfs = @{$axfa->fetch_all()};
Description: Retrieves all assembly exception features which are in the
database and builds internal caches of the features.
Returntype : reference to list of Bio::EnsEMBL::AssemblyExceptionFeatures
Exceptions : none
Caller : fetch_by_dbID, fetch_by_Slice
Status : Stable
=cut
sub fetch_all {
my $self = shift;
# this is the "global" cache for all assembly exception features in the db
if(defined($self->{'_aexc_cache'})) {
return $self->{'_aexc_cache'};
}
my $statement = qq(
SELECT ae.assembly_exception_id,
ae.seq_region_id,
ae.seq_region_start,
ae.seq_region_end,
ae.exc_type,
ae.exc_seq_region_id,
ae.exc_seq_region_start,
ae.exc_seq_region_end,
ae.ori
FROM assembly_exception ae,
coord_system cs,
seq_region sr
WHERE cs.species_id = ?
AND sr.coord_system_id = cs.coord_system_id
AND sr.seq_region_id = ae.seq_region_id);
my $sth = $self->prepare($statement);
$sth->bind_param( 1, $self->species_id(), SQL_INTEGER );
$sth->execute();
my ($ax_id, $sr_id, $sr_start, $sr_end,
$x_type, $x_sr_id, $x_sr_start, $x_sr_end, $ori);
$sth->bind_columns(\$ax_id, \$sr_id, \$sr_start, \$sr_end,
\$x_type, \$x_sr_id, \$x_sr_start, \$x_sr_end, \$ori);
my @features;
my $sa = $self->db()->get_SliceAdaptor();
$self->{'_aexc_dbID_cache'} = {};
while($sth->fetch()) {
my $slice = $sa->fetch_by_seq_region_id($sr_id);
my $x_slice = $sa->fetch_by_seq_region_id($x_sr_id);
# each row creates TWO features, each of which has alternate_slice
# pointing to the "other" one
my $a = Bio::EnsEMBL::AssemblyExceptionFeature->new
('-dbID' => $ax_id,
'-start' => $sr_start,
'-end' => $sr_end,
'-strand' => 1,
'-adaptor' => $self,
'-slice' => $slice,
'-alternate_slice' => $x_slice->sub_Slice($x_sr_start, $x_sr_end),
'-type' => $x_type);
push @features, $a;
$self->{'_aexc_dbID_cache'}->{$ax_id} = $a;
push @features, Bio::EnsEMBL::AssemblyExceptionFeature->new
('-dbID' => $ax_id,
'-start' => $x_sr_start,
'-end' => $x_sr_end,
'-strand' => 1,
'-adaptor' => $self,
'-slice' => $x_slice,
'-alternate_slice' => $slice->sub_Slice($sr_start, $sr_end),
'-type' => "$x_type REF" );
}
$sth->finish();
$self->{'_aexc_cache'} = \@features;
return \@features;
}
=head2 fetch_by_dbID
Arg [1] : int $dbID
Example : my $axf = $axfa->fetch_by_dbID(3);
Description: Retrieves a single assembly exception feature via its internal
identifier. Note that this only retrieves one of the two
assembly exception features which are represented by a single
row in the assembly_exception table.
Returntype : Bio::EnsEMBL::AssemblyExceptionFeature
Exceptions : none
Caller : general
Status : Stable
=cut
sub fetch_by_dbID {
my $self = shift;
my $dbID = shift;
if(!exists($self->{'_aexc_dbID_cache'})) {
# force loading of cache
$self->fetch_all();
}
return $self->{'_aexc_dbID_cache'}->{$dbID};
}
=head2 fetch_all_by_Slice
Arg [1] : Bio::EnsEMBL::Slice $slice
Example : my @axfs = @{$axfa->fetch_all_by_Slice($slice)};
Description: Retrieves all assembly exception features which overlap the
provided slice. The returned features will be in coordinate
system of the slice.
Returntype : reference to list of Bio::EnsEMBL::AssemblyException features
Exceptions : none
Caller : Feature::get_all_alt_locations, general
Status : Stable
=cut
sub fetch_all_by_Slice {
my $self = shift;
my $slice = shift;
my $key= uc($slice->name());
# return features from the slice cache if present
if(exists($self->{'_aexc_slice_cache'}->{$key})) {
return $self->{'_aexc_slice_cache'}->{$key};
}
my $all_features = $self->fetch_all();
my $mcc = $self->db()->get_MetaCoordContainer();
my $css = $mcc->fetch_all_CoordSystems_by_feature_type('assembly_exception');
my @features;
my $ma = $self->db()->get_AssemblyMapperAdaptor();
foreach my $cs (@$css) {
my $mapper;
if($cs->equals($slice->coord_system)) {
$mapper = undef;
} else {
$mapper = $ma->fetch_by_CoordSystems($cs,$slice->coord_system());
}
push @features, @{ $self->_remap($all_features, $mapper, $slice) };
}
$self->{'_aexc_slice_cache'}->{$key} = \@features;
return \@features;
}
#
# Given a list of features checks if they are in the correct coord system
# by looking at the first features slice. If they are not then they are
# converted and placed on the slice.
#
# Note that this is a re-implementation of a method with the same name in
# BaseFeatureAdaptor, and in contrast to the latter which maps features in
# place, this method returns a remapped copy of each feature. The reason for
# this is to get around conflicts with caching.
#
sub _remap {
my ($self, $features, $mapper, $slice) = @_;
# check if any remapping is actually needed
if(@$features && (!$features->[0]->isa('Bio::EnsEMBL::Feature') ||
$features->[0]->slice == $slice)) {
return $features;
}
# remapping has not been done, we have to do our own conversion from
# to slice coords
my @out;
my $slice_start = $slice->start();
my $slice_end = $slice->end();
my $slice_strand = $slice->strand();
my $slice_cs = $slice->coord_system();
my ($seq_region, $start, $end, $strand);
my $slice_seq_region = $slice->seq_region_name();
foreach my $f (@$features) {
# since feats were obtained in contig coords, attached seq is a contig
my $fslice = $f->slice();
if(!$fslice) {
throw("Feature does not have attached slice.\n");
}
my $fseq_region = $fslice->seq_region_name();
my $fcs = $fslice->coord_system();
if(!$slice_cs->equals($fcs)) {
# slice of feature in different coord system, mapping required
($seq_region, $start, $end, $strand) =
$mapper->fastmap($fseq_region,$f->start(),$f->end(),$f->strand(),$fcs);
# undefined start means gap
next if(!defined $start);
} else {
$start = $f->start();
$end = $f->end();
$strand = $f->strand();
$seq_region = $f->slice->seq_region_name();
}
# maps to region outside desired area
next if ($start > $slice_end) || ($end < $slice_start) ||
($slice_seq_region ne $seq_region);
# create new copies of successfully mapped feaatures with shifted start,
# end and strand
my ($new_start, $new_end);
if($slice_strand == -1) {
$new_start = $slice_end - $end + 1;
$new_end = $slice_end - $start + 1;
} else {
$new_start = $start - $slice_start + 1;
$new_end = $end - $slice_start + 1;
}
push @out, Bio::EnsEMBL::AssemblyExceptionFeature->new(
'-dbID' => $f->dbID,
'-start' => $new_start,
'-end' => $new_end,
'-strand' => $strand * $slice_strand,
'-adaptor' => $self,
'-slice' => $slice,
'-alternate_slice' => $f->alternate_slice,
'-type' => $f->type,
);
}
return \@out;
}
1;