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::AssemblyExceptionFeatureAdaptor
|
|
24
|
|
25 =head1 SYNOPSIS
|
|
26
|
|
27 my $assembly_exception_feature_adaptor =
|
|
28 $database_adaptor->get_AssemblyExceptionFeatureAdaptor();
|
|
29
|
|
30 @assembly_exception_features =
|
|
31 $assembly_exception_feature_adaptor->fetch_all_by_Slice($slice);
|
|
32
|
|
33 =head1 DESCRIPTION
|
|
34
|
|
35 Assembly Exception Feature Adaptor - database access for assembly
|
|
36 exception features.
|
|
37
|
|
38 =head1 METHODS
|
|
39
|
|
40 =cut
|
|
41
|
|
42 package Bio::EnsEMBL::DBSQL::AssemblyExceptionFeatureAdaptor;
|
|
43
|
|
44 use strict;
|
|
45 use warnings;
|
|
46 no warnings qw(uninitialized);
|
|
47
|
|
48 use Bio::EnsEMBL::DBSQL::BaseAdaptor;
|
|
49 use Bio::EnsEMBL::DBSQL::BaseFeatureAdaptor;
|
|
50 use Bio::EnsEMBL::AssemblyExceptionFeature;
|
|
51 use Bio::EnsEMBL::Utils::Exception qw(throw warning);
|
|
52 use Bio::EnsEMBL::Utils::Cache;
|
|
53
|
|
54 our @ISA = qw(Bio::EnsEMBL::DBSQL::BaseAdaptor);
|
|
55
|
|
56 # set the number of slices you'd like to cache
|
|
57 our $ASSEMBLY_EXCEPTION_FEATURE_CACHE_SIZE = 100;
|
|
58
|
|
59 =head2 new
|
|
60
|
|
61 Arg [1] : list of args @args
|
|
62 Superclass constructor arguments
|
|
63 Example : none
|
|
64 Description: Constructor which just initializes internal cache structures
|
|
65 Returntype : Bio::EnsEMBL::DBSQL::AssemblyExceptionFeatureAdaptor
|
|
66 Exceptions : none
|
|
67 Caller : implementing subclass constructors
|
|
68 Status : Stable
|
|
69
|
|
70 =cut
|
|
71
|
|
72 sub new {
|
|
73 my $caller = shift;
|
|
74 my $class = ref($caller) || $caller;
|
|
75
|
|
76 my $self = $class->SUPER::new(@_);
|
|
77
|
|
78 # initialize an LRU cache for slices
|
|
79 my %cache;
|
|
80 tie(%cache, 'Bio::EnsEMBL::Utils::Cache',
|
|
81 $ASSEMBLY_EXCEPTION_FEATURE_CACHE_SIZE);
|
|
82
|
|
83 $self->{'_aexc_slice_cache'} = \%cache;
|
|
84
|
|
85 return $self;
|
|
86 }
|
|
87
|
|
88 =head2 fetch_all
|
|
89
|
|
90 Arg [1] : none
|
|
91 Example : my @axfs = @{$axfa->fetch_all()};
|
|
92 Description: Retrieves all assembly exception features which are in the
|
|
93 database and builds internal caches of the features.
|
|
94 Returntype : reference to list of Bio::EnsEMBL::AssemblyExceptionFeatures
|
|
95 Exceptions : none
|
|
96 Caller : fetch_by_dbID, fetch_by_Slice
|
|
97 Status : Stable
|
|
98
|
|
99 =cut
|
|
100
|
|
101 sub fetch_all {
|
|
102 my $self = shift;
|
|
103
|
|
104 # this is the "global" cache for all assembly exception features in the db
|
|
105 if(defined($self->{'_aexc_cache'})) {
|
|
106 return $self->{'_aexc_cache'};
|
|
107 }
|
|
108
|
|
109 my $statement = qq(
|
|
110 SELECT ae.assembly_exception_id,
|
|
111 ae.seq_region_id,
|
|
112 ae.seq_region_start,
|
|
113 ae.seq_region_end,
|
|
114 ae.exc_type,
|
|
115 ae.exc_seq_region_id,
|
|
116 ae.exc_seq_region_start,
|
|
117 ae.exc_seq_region_end,
|
|
118 ae.ori
|
|
119 FROM assembly_exception ae,
|
|
120 coord_system cs,
|
|
121 seq_region sr
|
|
122 WHERE cs.species_id = ?
|
|
123 AND sr.coord_system_id = cs.coord_system_id
|
|
124 AND sr.seq_region_id = ae.seq_region_id);
|
|
125
|
|
126 my $sth = $self->prepare($statement);
|
|
127
|
|
128 $sth->bind_param( 1, $self->species_id(), SQL_INTEGER );
|
|
129
|
|
130 $sth->execute();
|
|
131
|
|
132 my ($ax_id, $sr_id, $sr_start, $sr_end,
|
|
133 $x_type, $x_sr_id, $x_sr_start, $x_sr_end, $ori);
|
|
134
|
|
135 $sth->bind_columns(\$ax_id, \$sr_id, \$sr_start, \$sr_end,
|
|
136 \$x_type, \$x_sr_id, \$x_sr_start, \$x_sr_end, \$ori);
|
|
137
|
|
138 my @features;
|
|
139 my $sa = $self->db()->get_SliceAdaptor();
|
|
140
|
|
141 $self->{'_aexc_dbID_cache'} = {};
|
|
142
|
|
143 while($sth->fetch()) {
|
|
144 my $slice = $sa->fetch_by_seq_region_id($sr_id);
|
|
145 my $x_slice = $sa->fetch_by_seq_region_id($x_sr_id);
|
|
146
|
|
147 # each row creates TWO features, each of which has alternate_slice
|
|
148 # pointing to the "other" one
|
|
149
|
|
150
|
|
151 my $a = Bio::EnsEMBL::AssemblyExceptionFeature->new
|
|
152 ('-dbID' => $ax_id,
|
|
153 '-start' => $sr_start,
|
|
154 '-end' => $sr_end,
|
|
155 '-strand' => 1,
|
|
156 '-adaptor' => $self,
|
|
157 '-slice' => $slice,
|
|
158 '-alternate_slice' => $x_slice->sub_Slice($x_sr_start, $x_sr_end),
|
|
159 '-type' => $x_type);
|
|
160
|
|
161 push @features, $a;
|
|
162 $self->{'_aexc_dbID_cache'}->{$ax_id} = $a;
|
|
163
|
|
164 push @features, Bio::EnsEMBL::AssemblyExceptionFeature->new
|
|
165 ('-dbID' => $ax_id,
|
|
166 '-start' => $x_sr_start,
|
|
167 '-end' => $x_sr_end,
|
|
168 '-strand' => 1,
|
|
169 '-adaptor' => $self,
|
|
170 '-slice' => $x_slice,
|
|
171 '-alternate_slice' => $slice->sub_Slice($sr_start, $sr_end),
|
|
172 '-type' => "$x_type REF" );
|
|
173 }
|
|
174
|
|
175 $sth->finish();
|
|
176
|
|
177 $self->{'_aexc_cache'} = \@features;
|
|
178
|
|
179 return \@features;
|
|
180 }
|
|
181
|
|
182
|
|
183 =head2 fetch_by_dbID
|
|
184
|
|
185 Arg [1] : int $dbID
|
|
186 Example : my $axf = $axfa->fetch_by_dbID(3);
|
|
187 Description: Retrieves a single assembly exception feature via its internal
|
|
188 identifier. Note that this only retrieves one of the two
|
|
189 assembly exception features which are represented by a single
|
|
190 row in the assembly_exception table.
|
|
191 Returntype : Bio::EnsEMBL::AssemblyExceptionFeature
|
|
192 Exceptions : none
|
|
193 Caller : general
|
|
194 Status : Stable
|
|
195
|
|
196 =cut
|
|
197
|
|
198 sub fetch_by_dbID {
|
|
199 my $self = shift;
|
|
200 my $dbID = shift;
|
|
201
|
|
202 if(!exists($self->{'_aexc_dbID_cache'})) {
|
|
203 # force loading of cache
|
|
204 $self->fetch_all();
|
|
205 }
|
|
206
|
|
207 return $self->{'_aexc_dbID_cache'}->{$dbID};
|
|
208 }
|
|
209
|
|
210
|
|
211 =head2 fetch_all_by_Slice
|
|
212
|
|
213 Arg [1] : Bio::EnsEMBL::Slice $slice
|
|
214 Example : my @axfs = @{$axfa->fetch_all_by_Slice($slice)};
|
|
215 Description: Retrieves all assembly exception features which overlap the
|
|
216 provided slice. The returned features will be in coordinate
|
|
217 system of the slice.
|
|
218 Returntype : reference to list of Bio::EnsEMBL::AssemblyException features
|
|
219 Exceptions : none
|
|
220 Caller : Feature::get_all_alt_locations, general
|
|
221 Status : Stable
|
|
222
|
|
223 =cut
|
|
224
|
|
225 sub fetch_all_by_Slice {
|
|
226 my $self = shift;
|
|
227 my $slice = shift;
|
|
228
|
|
229 my $key= uc($slice->name());
|
|
230
|
|
231 # return features from the slice cache if present
|
|
232 if(exists($self->{'_aexc_slice_cache'}->{$key})) {
|
|
233 return $self->{'_aexc_slice_cache'}->{$key};
|
|
234 }
|
|
235
|
|
236 my $all_features = $self->fetch_all();
|
|
237
|
|
238 my $mcc = $self->db()->get_MetaCoordContainer();
|
|
239 my $css = $mcc->fetch_all_CoordSystems_by_feature_type('assembly_exception');
|
|
240
|
|
241 my @features;
|
|
242
|
|
243 my $ma = $self->db()->get_AssemblyMapperAdaptor();
|
|
244
|
|
245 foreach my $cs (@$css) {
|
|
246 my $mapper;
|
|
247 if($cs->equals($slice->coord_system)) {
|
|
248 $mapper = undef;
|
|
249 } else {
|
|
250 $mapper = $ma->fetch_by_CoordSystems($cs,$slice->coord_system());
|
|
251 }
|
|
252
|
|
253 push @features, @{ $self->_remap($all_features, $mapper, $slice) };
|
|
254 }
|
|
255
|
|
256 $self->{'_aexc_slice_cache'}->{$key} = \@features;
|
|
257
|
|
258 return \@features;
|
|
259 }
|
|
260
|
|
261
|
|
262 #
|
|
263 # Given a list of features checks if they are in the correct coord system
|
|
264 # by looking at the first features slice. If they are not then they are
|
|
265 # converted and placed on the slice.
|
|
266 #
|
|
267 # Note that this is a re-implementation of a method with the same name in
|
|
268 # BaseFeatureAdaptor, and in contrast to the latter which maps features in
|
|
269 # place, this method returns a remapped copy of each feature. The reason for
|
|
270 # this is to get around conflicts with caching.
|
|
271 #
|
|
272 sub _remap {
|
|
273 my ($self, $features, $mapper, $slice) = @_;
|
|
274
|
|
275 # check if any remapping is actually needed
|
|
276 if(@$features && (!$features->[0]->isa('Bio::EnsEMBL::Feature') ||
|
|
277 $features->[0]->slice == $slice)) {
|
|
278 return $features;
|
|
279 }
|
|
280
|
|
281 # remapping has not been done, we have to do our own conversion from
|
|
282 # to slice coords
|
|
283
|
|
284 my @out;
|
|
285
|
|
286 my $slice_start = $slice->start();
|
|
287 my $slice_end = $slice->end();
|
|
288 my $slice_strand = $slice->strand();
|
|
289 my $slice_cs = $slice->coord_system();
|
|
290
|
|
291 my ($seq_region, $start, $end, $strand);
|
|
292
|
|
293 my $slice_seq_region = $slice->seq_region_name();
|
|
294
|
|
295 foreach my $f (@$features) {
|
|
296 # since feats were obtained in contig coords, attached seq is a contig
|
|
297 my $fslice = $f->slice();
|
|
298 if(!$fslice) {
|
|
299 throw("Feature does not have attached slice.\n");
|
|
300 }
|
|
301 my $fseq_region = $fslice->seq_region_name();
|
|
302 my $fcs = $fslice->coord_system();
|
|
303
|
|
304 if(!$slice_cs->equals($fcs)) {
|
|
305 # slice of feature in different coord system, mapping required
|
|
306 ($seq_region, $start, $end, $strand) =
|
|
307 $mapper->fastmap($fseq_region,$f->start(),$f->end(),$f->strand(),$fcs);
|
|
308
|
|
309 # undefined start means gap
|
|
310 next if(!defined $start);
|
|
311 } else {
|
|
312 $start = $f->start();
|
|
313 $end = $f->end();
|
|
314 $strand = $f->strand();
|
|
315 $seq_region = $f->slice->seq_region_name();
|
|
316 }
|
|
317
|
|
318 # maps to region outside desired area
|
|
319 next if ($start > $slice_end) || ($end < $slice_start) ||
|
|
320 ($slice_seq_region ne $seq_region);
|
|
321
|
|
322 # create new copies of successfully mapped feaatures with shifted start,
|
|
323 # end and strand
|
|
324 my ($new_start, $new_end);
|
|
325 if($slice_strand == -1) {
|
|
326 $new_start = $slice_end - $end + 1;
|
|
327 $new_end = $slice_end - $start + 1;
|
|
328 } else {
|
|
329 $new_start = $start - $slice_start + 1;
|
|
330 $new_end = $end - $slice_start + 1;
|
|
331 }
|
|
332
|
|
333 push @out, Bio::EnsEMBL::AssemblyExceptionFeature->new(
|
|
334 '-dbID' => $f->dbID,
|
|
335 '-start' => $new_start,
|
|
336 '-end' => $new_end,
|
|
337 '-strand' => $strand * $slice_strand,
|
|
338 '-adaptor' => $self,
|
|
339 '-slice' => $slice,
|
|
340 '-alternate_slice' => $f->alternate_slice,
|
|
341 '-type' => $f->type,
|
|
342 );
|
|
343 }
|
|
344
|
|
345 return \@out;
|
|
346 }
|
|
347
|
|
348 =head2 store
|
|
349
|
|
350 Arg[1] : Bio::EnsEMBL::AssemblyException $asx
|
|
351 Arg[2] : Bio::EnsEMBL::AssemblyException $asx2
|
|
352
|
|
353 Example : $asx = Bio::EnsEMBL::AssemblyExceptionFeature->new(...)
|
|
354 $asx2 = Bio::EnsEMBL::AssemblyExceptionFeature->new(...)
|
|
355 $asx_seq_region_id = $asx_adaptor->store($asx);
|
|
356 Description: This stores a assembly exception feature in the
|
|
357 assembly_exception table and returns the assembly_exception_id.
|
|
358 Needs 2 features: one pointing to the Assembly_exception, and the
|
|
359 other pointing to the region in the reference that is being mapped to
|
|
360 Will check that start, end and type are defined, and the alternate
|
|
361 slice is present as well.
|
|
362 ReturnType: int
|
|
363 Exceptions: throw if assembly exception not defined (needs start, end,
|
|
364 type and alternate_slice) of if $asx not a Bio::EnsEMBL::AssemblyException
|
|
365 Caller: general
|
|
366 Status: Stable
|
|
367
|
|
368 =cut
|
|
369
|
|
370 sub store{
|
|
371 my $self = shift;
|
|
372 my $asx = shift;
|
|
373 my $asx2 = shift;
|
|
374
|
|
375
|
|
376 if (! $asx->isa('Bio::EnsEMBL::AssemblyExceptionFeature')){
|
|
377 throw("$asx is not a Ensembl assemlby exception -- not stored");
|
|
378 }
|
|
379 #if already present, return ID in the database
|
|
380 my $db = $self->db();
|
|
381 if ($asx->is_stored($db)){
|
|
382 return $asx->dbID();
|
|
383 }
|
|
384 #do some checkings for the object
|
|
385 #at the moment, the orientation is always 1
|
|
386 if (! $asx->start || ! $asx->end ){
|
|
387 throw("Assembly exception does not have coordinates");
|
|
388 }
|
|
389 if ($asx->type !~ /PAR|HAP|PATCH_NOVEL|PATCH_FIX/){
|
|
390 throw("Only types of assembly exception features valid are PAR, HAP, PATCH_FIX or PATCH_NOVEL");
|
|
391 }
|
|
392 if ( !($asx->alternate_slice->isa('Bio::EnsEMBL::Slice')) ){
|
|
393 throw("Alternate slice should be a Bio::EnsEMBL::Slice");
|
|
394 }
|
|
395 #now check the other Assembly exception feature, the one pointing to the REF
|
|
396 # region
|
|
397 if (!$asx2->isa('Bio::EnsEMBL::AssemblyExceptionFeature')){
|
|
398 throw("$asx2 is not a Ensembl assemlby exception -- not stored");
|
|
399 }
|
|
400 if (! $asx2->start || ! $asx2->end ){
|
|
401 throw("Assembly exception does not have coordinates");
|
|
402 }
|
|
403 if ($asx2->type !~ /HAP REF|PAR REF|PATCH_NOVEL REF|PATCH_FIX REF/){
|
|
404 throw("$asx2 should have type of assembly exception features HAP REF, PAR REF, PATCH_FIX REF or PATCH_NOVEL REF");
|
|
405 }
|
|
406 if (! ($asx2->alternate_slice->isa('Bio::EnsEMBL::Slice')) ){
|
|
407 throw("Alternate slice should be a Bio::EnsEMBL::Slice");
|
|
408 }
|
|
409 #finally check that both features are pointing to each other slice
|
|
410 if ($asx->slice != $asx2->alternate_slice || $asx->alternate_slice != $asx2->slice){
|
|
411 throw("Slice and alternate slice in both features are not pointing to each other");
|
|
412 }
|
|
413 #prepare the SQL
|
|
414 my $asx_sql = q{
|
|
415 INSERT INTO assembly_exception( seq_region_id, seq_region_start,
|
|
416 seq_region_end,
|
|
417 exc_type, exc_seq_region_id,
|
|
418 exc_seq_region_start, exc_seq_region_end,
|
|
419 ori)
|
|
420 VALUES (?, ?, ?, ?, ?, ?, ?, 1)
|
|
421 };
|
|
422
|
|
423 my $asx_st = $self->prepare($asx_sql);
|
|
424 my $asx_id = undef;
|
|
425 my $asx_seq_region_id;
|
|
426 my $asx2_seq_region_id;
|
|
427 my $original = $asx;
|
|
428 my $original2 = $asx2;
|
|
429 #check all feature information
|
|
430 ($asx, $asx_seq_region_id) = $self->_pre_store($asx);
|
|
431 ($asx2, $asx2_seq_region_id) = $self->_pre_store($asx2);
|
|
432
|
|
433 #and store it
|
|
434 $asx_st->bind_param(1, $asx_seq_region_id, SQL_INTEGER);
|
|
435 $asx_st->bind_param(2, $asx->start(), SQL_INTEGER);
|
|
436 $asx_st->bind_param(3, $asx->end(), SQL_INTEGER);
|
|
437 $asx_st->bind_param(4, $asx->type(), SQL_VARCHAR);
|
|
438 $asx_st->bind_param(5, $asx2_seq_region_id, SQL_INTEGER);
|
|
439 $asx_st->bind_param(6, $asx2->start(), SQL_INTEGER);
|
|
440 $asx_st->bind_param(7, $asx2->end(), SQL_INTEGER);
|
|
441
|
|
442 $asx_st->execute();
|
|
443 $asx_id = $asx_st->{'mysql_insertid'};
|
|
444
|
|
445 #finally, update the dbID and adaptor of the asx and asx2
|
|
446 $original->adaptor($self);
|
|
447 $original->dbID($asx_id);
|
|
448 $original2->adaptor($self);
|
|
449 $original2->dbID($asx_id);
|
|
450 #and finally update dbID cache with new assembly exception
|
|
451 $self->{'_aexc_dbID_cache'}->{$asx_id} = $original;
|
|
452 #and update the other caches as well
|
|
453 push @{$self->{'_aexc_slice_cache'}->{uc($asx->slice->name)}},$original, $original2;
|
|
454 push @{$self->{'_aexc_cache'}}, $original, $original2;
|
|
455
|
|
456 return $asx_id;
|
|
457 }
|
|
458
|
|
459 #
|
|
460 # Helper function containing some common feature storing functionality
|
|
461 #
|
|
462 # Given a Feature this will return a copy (or the same feature if no changes
|
|
463 # to the feature are needed) of the feature which is relative to the start
|
|
464 # of the seq_region it is on. The seq_region_id of the seq_region it is on
|
|
465 # is also returned.
|
|
466 #
|
|
467 # This method will also ensure that the database knows which coordinate
|
|
468 # systems that this feature is stored in.
|
|
469 # Since this adaptor doesn't inherit from BaseFeatureAdaptor, we need to copy
|
|
470 # the code
|
|
471 #
|
|
472
|
|
473 sub _pre_store {
|
|
474 my $self = shift;
|
|
475 my $feature = shift;
|
|
476
|
|
477 if(!ref($feature) || !$feature->isa('Bio::EnsEMBL::Feature')) {
|
|
478 throw('Expected Feature argument.');
|
|
479 }
|
|
480
|
|
481 $self->_check_start_end_strand($feature->start(),$feature->end(),
|
|
482 $feature->strand());
|
|
483
|
|
484
|
|
485 my $db = $self->db();
|
|
486
|
|
487 my $slice_adaptor = $db->get_SliceAdaptor();
|
|
488 my $slice = $feature->slice();
|
|
489
|
|
490 if(!ref($slice) || !($slice->isa('Bio::EnsEMBL::Slice') or $slice->isa('Bio::EnsEMBL::LRGSlice')) ) {
|
|
491 throw('Feature must be attached to Slice to be stored.');
|
|
492 }
|
|
493
|
|
494 # make sure feature coords are relative to start of entire seq_region
|
|
495
|
|
496 if($slice->start != 1 || $slice->strand != 1) {
|
|
497 #move feature onto a slice of the entire seq_region
|
|
498 $slice = $slice_adaptor->fetch_by_region($slice->coord_system->name(),
|
|
499 $slice->seq_region_name(),
|
|
500 undef, #start
|
|
501 undef, #end
|
|
502 undef, #strand
|
|
503 $slice->coord_system->version());
|
|
504
|
|
505 $feature = $feature->transfer($slice);
|
|
506
|
|
507 if(!$feature) {
|
|
508 throw('Could not transfer Feature to slice of ' .
|
|
509 'entire seq_region prior to storing');
|
|
510 }
|
|
511 }
|
|
512
|
|
513 # Ensure this type of feature is known to be stored in this coord system.
|
|
514 my $cs = $slice->coord_system;
|
|
515
|
|
516 my $mcc = $db->get_MetaCoordContainer();
|
|
517
|
|
518 $mcc->add_feature_type($cs, 'assembly_exception', $feature->length);
|
|
519
|
|
520 my $seq_region_id = $slice_adaptor->get_seq_region_id($slice);
|
|
521
|
|
522 if(!$seq_region_id) {
|
|
523 throw('Feature is associated with seq_region which is not in this DB.');
|
|
524 }
|
|
525
|
|
526 return ($feature, $seq_region_id);
|
|
527 }
|
|
528
|
|
529 #
|
|
530 # helper function used to validate start/end/strand and
|
|
531 # hstart/hend/hstrand etc.
|
|
532 #
|
|
533 sub _check_start_end_strand {
|
|
534 my $self = shift;
|
|
535 my $start = shift;
|
|
536 my $end = shift;
|
|
537 my $strand = shift;
|
|
538
|
|
539 #
|
|
540 # Make sure that the start, end, strand are valid
|
|
541 #
|
|
542 if(int($start) != $start) {
|
|
543 throw("Invalid Feature start [$start]. Must be integer.");
|
|
544 }
|
|
545 if(int($end) != $end) {
|
|
546 throw("Invalid Feature end [$end]. Must be integer.");
|
|
547 }
|
|
548 if(int($strand) != $strand || $strand < -1 || $strand > 1) {
|
|
549 throw("Invalid Feature strand [$strand]. Must be -1, 0 or 1.");
|
|
550 }
|
|
551 if($end < $start) {
|
|
552 throw("Invalid Feature start/end [$start/$end]. Start must be less " .
|
|
553 "than or equal to end.");
|
|
554 }
|
|
555
|
|
556 return 1;
|
|
557 }
|
|
558
|
|
559 =head2 remove
|
|
560
|
|
561 Arg [1] : $asx Bio::EnsEMBL::AssemblyFeatureException
|
|
562 Example : $asx_adaptor->remove($asx);
|
|
563 Description: This removes a assembly exception feature from the database.
|
|
564 Returntype : none
|
|
565 Exceptions : thrown if $asx arg does not implement dbID(), or if
|
|
566 $asx->dbID is not a true value
|
|
567 Caller : general
|
|
568 Status : Stable
|
|
569
|
|
570 =cut
|
|
571
|
|
572 #again, this method is generic in BaseFeatureAdaptor, but since this class
|
|
573 #is not inheriting, need to copy&paste
|
|
574 sub remove {
|
|
575 my ($self, $feature) = @_;
|
|
576
|
|
577 if(!$feature || !ref($feature) || !$feature->isa('Bio::EnsEMBL::AssemblyExceptionFeature')) {
|
|
578 throw('AssemblyExceptionFeature argument is required');
|
|
579 }
|
|
580
|
|
581 if(!$feature->is_stored($self->db)) {
|
|
582 throw("This feature is not stored in this database");
|
|
583 }
|
|
584
|
|
585 my $asx_id = $feature->dbID();
|
|
586 my $key = uc($feature->slice->name);
|
|
587 my $sth = $self->prepare("DELETE FROM assembly_exception WHERE assembly_exception_id = ?");
|
|
588 $sth->bind_param(1,$feature->dbID,SQL_INTEGER);
|
|
589 $sth->execute();
|
|
590
|
|
591 #and clear cache
|
|
592 #and finally update dbID cache
|
|
593 delete $self->{'_aexc_dbID_cache'}->{$asx_id};
|
|
594 #and remove from cache feature
|
|
595 my @features;
|
|
596 foreach my $asx (@{$self->{'_aexc_slice_cache'}->{$key}}){
|
|
597 if ($asx->dbID != $asx_id){
|
|
598 push @features, $asx;
|
|
599 }
|
|
600 }
|
|
601 $self->{'_aexc_slice_cache'}->{$key} = \@features;
|
|
602 @features = ();
|
|
603 foreach my $asx (@{$self->{'_aexc_cache'}}){
|
|
604 if ($asx->dbID != $asx_id){
|
|
605 push @features, $asx;
|
|
606 }
|
|
607 }
|
|
608 $self->{'_aexc_cache'} = \@features;
|
|
609
|
|
610 #unset the feature dbID ad adaptor
|
|
611 $feature->dbID(undef);
|
|
612 $feature->adaptor(undef);
|
|
613
|
|
614 return;
|
|
615 }
|
|
616
|
|
617
|
|
618 1;
|