ensembl-hive  2.7.0
DnaAlignFeatureAdaptor.pm
Go to the documentation of this file.
1 =head1 LICENSE
2 
3 See the NOTICE file distributed with this work for additional information
4 regarding copyright ownership.
5 
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
9 
10  http://www.apache.org/licenses/LICENSE-2.0
11 
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.
17 
18 =cut
19 
20 
21 =head1 CONTACT
22 
23  Please email comments or questions to the public Ensembl
24  developers list at <http://lists.ensembl.org/mailman/listinfo/dev>.
25 
26  Questions may also be sent to the Ensembl help desk at
27  <http://www.ensembl.org/Help/Contact>.
28 
29 =cut
30 
31 =head1 NAME
32 
33 Bio::EnsEMBL::DBSQL::DnaAlignFeatureAdaptor - Adaptor for DnaAlignFeatures
34 
35 =head1 SYNOPSIS
36 
37  $dafa = $registry->get_adaptor( 'Human', 'Core', 'DnaAlignFeature' );
38 
39  my @features = @{ $dafa->fetch_all_by_Slice($slice) };
40 
41  $dafa->store(@features);
42 
43 =head1 DESCRIPTION
44 
45 This is an adaptor responsible for the retrieval and storage of
46 DnaDnaAlignFeatures from the database. This adaptor inherits most of its
47 functionality from the BaseAlignFeatureAdaptor and BaseFeatureAdaptor
48 superclasses.
49 
50 =head1 METHODS
51 
52 =cut
53 
54 
55 package Bio::EnsEMBL::DBSQL::DnaAlignFeatureAdaptor;
56 use vars qw(@ISA);
57 use strict;
60 use Bio::EnsEMBL::Utils::Exception qw(throw warning);
61 
63 
64 
65 =head2 _tables
66 
67  Args : none
68  Example : @tabs = $self->_tables
69  Description: PROTECTED implementation of the abstract method inherited from
70  BaseFeatureAdaptor. Returns list of [tablename, alias] pairs
71  Returntype : list of listrefs of strings
72  Exceptions : none
74  Status : Stable
75 
76 =cut
77 
78 sub _tables {
79  my $self = shift;
80 
81  return (['dna_align_feature', 'daf'],['external_db','exdb']);
82 }
83 
84 
85 sub _left_join{
86  return (['external_db',"exdb.external_db_id = daf.external_db_id"]);
87 }
88 
89 =head2 _columns
90 
91  Args : none
92  Example : @columns = $self->_columns
93  Description: PROTECTED implementation of abstract superclass method.
94  Returns a list of columns that are needed for object creation.
95  Returntype : list of strings
96  Exceptions : none
98  Status : Stable
99 
100 =cut
101 
102 sub _columns {
103  my $self = shift;
104 
105  #warning, implementation of _objs_from_sth method depends on order of list
106  return qw(daf.dna_align_feature_id
107  daf.seq_region_id
108  daf.analysis_id
109  daf.seq_region_start
110  daf.seq_region_end
111  daf.seq_region_strand
112  daf.hit_start
113  daf.hit_end
114  daf.hit_name
115  daf.hit_strand
116  daf.cigar_line
117  daf.evalue
118  daf.perc_ident
119  daf.score
120  daf.external_db_id
121  daf.hcoverage
122  daf.align_type
123  exdb.db_name
124  exdb.db_display_name);
125 }
126 
127 
128 =head2 store
129 
130  Arg [1] : list of Bio::EnsEMBL::DnaAlignFeatures @feats
131  the features to store in the database
132  Example : $dna_align_feature_adaptor->store(@features);
133  Description: Stores a list of DnaAlignFeatures in the database
134  Returntype : none
135  Exceptions : throw if any of the provided features cannot be stored
136  which may occur if:
137  * The feature does not have an associate Slice
138  * The feature does not have an associated analysis
139  * The Slice the feature is associated with is on a seq_region
140  unknown to this database
141  A warning is given if:
142  * The feature has already been stored in this db
143  Caller : Pipeline
144  Status : Stable
145 
146 =cut
147 
148 sub store {
149  my ( $self, @feats ) = @_;
150 
151  throw("Must call store with features") if ( scalar(@feats) == 0 );
152 
153  my @tabs = $self->_tables;
154  my ($tablename) = @{ $tabs[0] };
155 
156  my $db = $self->db();
157  my $analysis_adaptor = $db->get_AnalysisAdaptor();
158 
159  my $sth = $self->prepare(
160  "INSERT INTO $tablename (seq_region_id, seq_region_start,
161  seq_region_end, seq_region_strand,
162  hit_start, hit_end, hit_strand, hit_name,
163  cigar_line, analysis_id, score, evalue,
164  perc_ident, external_db_id, hcoverage, align_type)
165  VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)" # 16 arguments, external_data removed and align_type added
166  );
167 
168 FEATURE:
169  foreach my $feat (@feats) {
170  if ( !ref $feat || !$feat->isa("Bio::EnsEMBL::DnaDnaAlignFeature") )
171  {
172  throw("feature must be a Bio::EnsEMBL::DnaDnaAlignFeature, not a [". ref($feat). "]." );
173  }
174 
175  if ( $feat->is_stored($db) ) {
176  warning( "DnaDnaAlignFeature [".$feat->dbID()."] is already stored in this database." );
177  next FEATURE;
178  }
179 
180  my $hstart = $feat->hstart();
181  my $hend = $feat->hend();
182  my $hstrand = $feat->hstrand();
183  $self->_check_start_end_strand( $hstart, $hend, $hstrand, $feat->hslice );
184 
185  my $cigar_string = $feat->cigar_string();
186  if ( !$cigar_string ) {
187  $cigar_string = $feat->length() . 'M';
188  warning( "DnaDnaAlignFeature does not define a cigar_string.\n"
189  . "Assuming ungapped block with cigar_line=$cigar_string ." );
190  }
191  my $align_type = $feat->align_type();
192 
193  my $hseqname = $feat->hseqname();
194  if ( !$hseqname ) {
195  throw("DnaDnaAlignFeature must define an hseqname.");
196  }
197 
198  if ( !defined( $feat->analysis ) ) {
199  throw(
200  "An analysis must be attached to the features to be stored.");
201  }
202 
203  #store the analysis if it has not been stored yet
204  if ( !$feat->analysis->is_stored($db) ) {
205  $analysis_adaptor->store( $feat->analysis() );
206  }
207 
208  my $original = $feat;
209  my $seq_region_id;
210  ( $feat, $seq_region_id ) = $self->_pre_store($feat);
211 
212  $sth->bind_param( 1, $seq_region_id, SQL_INTEGER );
213  $sth->bind_param( 2, $feat->start, SQL_INTEGER );
214  $sth->bind_param( 3, $feat->end, SQL_INTEGER );
215  $sth->bind_param( 4, $feat->strand, SQL_TINYINT );
216  $sth->bind_param( 5, $hstart, SQL_INTEGER );
217  $sth->bind_param( 6, $hend, SQL_INTEGER );
218  $sth->bind_param( 7, $hstrand, SQL_TINYINT );
219  $sth->bind_param( 8, $hseqname, SQL_VARCHAR );
220  $sth->bind_param( 9, $cigar_string, SQL_LONGVARCHAR );
221  $sth->bind_param( 10, $feat->analysis->dbID, SQL_INTEGER );
222  $sth->bind_param( 11, $feat->score, SQL_DOUBLE );
223  $sth->bind_param( 12, $feat->p_value, SQL_DOUBLE );
224  $sth->bind_param( 13, $feat->percent_id, SQL_FLOAT );
225  $sth->bind_param( 14, $feat->external_db_id, SQL_INTEGER );
226  $sth->bind_param( 15, $feat->hcoverage, SQL_DOUBLE );
227  $sth->bind_param( 16, $feat->align_type, SQL_VARCHAR);
228  $sth->execute();
229 
230  my $dbId = $self->last_insert_id("${tablename}_id", undef, $tablename);
231 
232  # store attributes if there are any
233  my $attr_adaptor = $db->get_AttributeAdaptor();
234  $attr_adaptor->store_on_DnaDnaAlignFeature($dbId, $feat->get_all_Attributes);
235 
236  $original->dbID( $dbId );
237  $original->adaptor($self);
238  } ## end foreach my $feat (@feats)
239 
240  $sth->finish();
241 } ## end sub store
242 
243 
244 =head2 remove
245 
246  Arg [1] : A feature $feature
247  Example : $feature_adaptor->remove($feature);
248  Description: This removes a feature from the database. The table the
249  feature is removed from is defined by the abstract method
250  _tablename, and the primary key of the table is assumed
251  to be _tablename() . '_id'. The feature argument must
252  be an object implementing the dbID method, and for the
253  feature to be removed from the database a dbID value must
254  be returned.
255  Returntype : none
256  Exceptions : thrown if $feature arg does not implement dbID(), or if
257  $feature->dbID is not a true value
258  Caller : general
259  Status : Stable
260 
261 =cut
262 
263 
264 sub remove {
265  my ($self, $feature) = @_;
266 
267  if(!$feature || !ref($feature) || !$feature->isa('Bio::EnsEMBL::Feature')) {
268  throw('Feature argument is required');
269  }
270 
271  if(!$feature->is_stored($self->db)) {
272  throw("This feature is not stored in this database");
273  }
274 
275  my @tabs = $self->_tables;
276  my ($table) = @{$tabs[0]};
277 
278  my $sth = $self->prepare("DELETE FROM $table WHERE ${table}_id = ?");
279  $sth->bind_param(1,$feature->dbID,SQL_INTEGER);
280  $sth->execute();
281 
282  # remove the attributes associated with this feature
283  my $attrib_adaptor = $self->db->get_AttributeAdaptor;
284  $attrib_adaptor->remove_from_DnaDnaAlignFeature($feature);
285 
286  #unset the feature dbID ad adaptor
287  $feature->dbID(undef);
288  $feature->adaptor(undef);
289 
290  return;
291 }
292 
293 
294 =head2 _objs_from_sth
295 
296  Arg [1] : DBI statement handle $sth
297  an exectuted DBI statement handle generated by selecting
298  the columns specified by _columns() from the table specified
299  by _table()
300  Example : @dna_dna_align_feats = $self->_obj_from_hashref
301  Description: PROTECTED implementation of superclass abstract method.
302  Creates DnaDnaAlignFeature objects from a DBI hashref
303  Returntype : listref of Bio::EnsEMBL::DnaDnaAlignFeatures
304  Exceptions : none
305  Caller : Bio::EnsEMBL::BaseFeatureAdaptor::generic_fetch
306  Status : Stable
307 
308 =cut
309 
310 sub _objs_from_sth {
311  my ( $self, $sth, $mapper, $dest_slice ) = @_;
312 
313  #
314  # This code is ugly because an attempt has been made to remove as many
315  # function calls as possible for speed purposes. Thus many caches and
316  # a fair bit of gymnastics is used.
317  #
318 
319  # In case of userdata we need the features on the dest_slice. In case
320  # of get_all_supporting_features dest_slice is not provided.
321  my $sa = ( $dest_slice
322  ? $dest_slice->adaptor()
323  : $self->db()->get_SliceAdaptor() );
324  my $aa = $self->db->get_AnalysisAdaptor();
325 
326  my @features;
327  my %analysis_hash;
328  my %slice_hash;
329  my %sr_name_hash;
330  my %sr_cs_hash;
331 
332  my ( $dna_align_feature_id, $seq_region_id,
333  $analysis_id, $seq_region_start,
334  $seq_region_end, $seq_region_strand,
335  $hit_start, $hit_end,
336  $hit_name, $hit_strand,
337  $cigar_line, $evalue,
338  $perc_ident, $score,
339  $external_db_id, $hcoverage,
340  $align_type,
341  $external_db_name, $external_display_db_name );
342 
343  $sth->bind_columns( \( $dna_align_feature_id, $seq_region_id,
344  $analysis_id, $seq_region_start,
345  $seq_region_end, $seq_region_strand,
346  $hit_start, $hit_end,
347  $hit_name, $hit_strand,
348  $cigar_line, $evalue,
349  $perc_ident, $score,
350  $external_db_id, $hcoverage,
351  $align_type,
352  $external_db_name, $external_display_db_name )
353  );
354 
355  my $dest_slice_start;
356  my $dest_slice_end;
357  my $dest_slice_strand;
358  my $dest_slice_length;
359  my $dest_slice_cs;
360  my $dest_slice_sr_name;
361  my $dest_slice_sr_id;
362  my $asma;
363 
364  if ($dest_slice) {
365  $dest_slice_start = $dest_slice->start();
366  $dest_slice_end = $dest_slice->end();
367  $dest_slice_strand = $dest_slice->strand();
368  $dest_slice_length = $dest_slice->length();
369  $dest_slice_cs = $dest_slice->coord_system();
370  $dest_slice_sr_name = $dest_slice->seq_region_name();
371  $dest_slice_sr_id = $dest_slice->get_seq_region_id();
372  $asma = $self->db->get_AssemblyMapperAdaptor();
373  }
374 
375  FEATURE: while($sth->fetch()) {
376 
377  #get the analysis object
378  my $analysis = $analysis_hash{$analysis_id} ||= $aa->fetch_by_dbID($analysis_id);
379  $analysis_hash{$analysis_id} = $analysis;
380 
381  #need to get the internal_seq_region, if present
382  $seq_region_id = $self->get_seq_region_id_internal($seq_region_id);
383  my $slice = $slice_hash{"ID:".$seq_region_id};
384 
385  if (!$slice) {
386  $slice = $sa->fetch_by_seq_region_id($seq_region_id);
387  $slice_hash{"ID:".$seq_region_id} = $slice;
388  $sr_name_hash{$seq_region_id} = $slice->seq_region_name();
389  $sr_cs_hash{$seq_region_id} = $slice->coord_system();
390  }
391 
392  #obtain a mapper if none was defined, but a dest_seq_region was
393  if(!$mapper && $dest_slice && !$dest_slice_cs->equals($slice->coord_system)) {
394  $mapper = $asma->fetch_by_CoordSystems($dest_slice_cs, $slice->coord_system);
395  }
396 
397  my $sr_name = $sr_name_hash{$seq_region_id};
398  my $sr_cs = $sr_cs_hash{$seq_region_id};
399 
400  #
401  # remap the feature coordinates to another coord system
402  # if a mapper was provided
403  #
404 
405  if ($mapper) {
406 
407  if (defined $dest_slice && $mapper->isa('Bio::EnsEMBL::ChainedAssemblyMapper') ) {
408  ($seq_region_id, $seq_region_start, $seq_region_end, $seq_region_strand) =
409  $mapper->map($sr_name, $seq_region_start, $seq_region_end, $seq_region_strand, $sr_cs, 1, $dest_slice);
410 
411  } else {
412  ($seq_region_id, $seq_region_start, $seq_region_end, $seq_region_strand) =
413  $mapper->fastmap($sr_name, $seq_region_start, $seq_region_end, $seq_region_strand, $sr_cs);
414  }
415 
416  #skip features that map to gaps or coord system boundaries
417  next FEATURE if (!defined($seq_region_id));
418 
419  #get a slice in the coord system we just mapped to
420  $slice = $slice_hash{"ID:".$seq_region_id} ||= $sa->fetch_by_seq_region_id($seq_region_id);
421  }
422 
423  #
424  # If a destination slice was provided convert the coords.
425  #
426  if (defined($dest_slice)) {
427  my $seq_region_len = $dest_slice->seq_region_length();
428 
429  if ( $dest_slice_strand == 1 ) {
430  $seq_region_start = $seq_region_start - $dest_slice_start + 1;
431  $seq_region_end = $seq_region_end - $dest_slice_start + 1;
432 
433  if ( $dest_slice->is_circular ) {
434  # Handle circular chromosomes.
435 
436  if ( $seq_region_start > $seq_region_end ) {
437  # Looking at a feature overlapping the chromosome origin.
438 
439  if ( $seq_region_end > $dest_slice_start ) {
440  # Looking at the region in the beginning of the chromosome
441  $seq_region_start -= $seq_region_len;
442  }
443  if ( $seq_region_end < 0 ) {
444  $seq_region_end += $seq_region_len;
445  }
446  } else {
447  if ($dest_slice_start > $dest_slice_end && $seq_region_end < 0) {
448  # Looking at the region overlapping the chromosome
449  # origin and a feature which is at the beginning of the
450  # chromosome.
451  $seq_region_start += $seq_region_len;
452  $seq_region_end += $seq_region_len;
453  }
454  }
455  }
456  } else {
457 
458  my $start = $dest_slice_end - $seq_region_end + 1;
459  my $end = $dest_slice_end - $seq_region_start + 1;
460 
461  if ($dest_slice->is_circular()) {
462 
463  if ($dest_slice_start > $dest_slice_end) {
464  # slice spans origin or replication
465 
466  if ($seq_region_start >= $dest_slice_start) {
467  $end += $seq_region_len;
468  $start += $seq_region_len if $seq_region_end > $dest_slice_start;
469 
470  } elsif ($seq_region_start <= $dest_slice_end) {
471  # do nothing
472  } elsif ($seq_region_end >= $dest_slice_start) {
473  $start += $seq_region_len;
474  $end += $seq_region_len;
475 
476  } elsif ($seq_region_end <= $dest_slice_end) {
477  $end += $seq_region_len if $end < 0;
478 
479  } elsif ($seq_region_start > $seq_region_end) {
480  $end += $seq_region_len;
481  }
482 
483  } else {
484 
485  if ($seq_region_start <= $dest_slice_end and $seq_region_end >= $dest_slice_start) {
486  # do nothing
487  } elsif ($seq_region_start > $seq_region_end) {
488  if ($seq_region_start <= $dest_slice_end) {
489  $start -= $seq_region_len;
490  } elsif ($seq_region_end >= $dest_slice_start) {
491  $end += $seq_region_len;
492  }
493  }
494  }
495  }
496 
497  $seq_region_start = $start;
498  $seq_region_end = $end;
499  $seq_region_strand *= -1;
500 
501  } ## end else [ if ( $dest_slice_strand...)]
502 
503  # Throw away features off the end of the requested slice or on
504  # different seq_region.
505  if ($seq_region_end < 1
506  || $seq_region_start > $dest_slice_length
507  || ($dest_slice_sr_id != $seq_region_id)) {
508  next FEATURE;
509  }
510  $slice = $dest_slice;
511  }
512 
513  # Finally, create the new DnaAlignFeature.
514  push( @features,
515  $self->_create_feature_fast(
516  'Bio::EnsEMBL::DnaDnaAlignFeature', {
517  'slice' => $slice,
518  'start' => $seq_region_start,
519  'end' => $seq_region_end,
520  'strand' => $seq_region_strand,
521  'hseqname' => $hit_name,
522  'hstart' => $hit_start,
523  'hend' => $hit_end,
524  'hstrand' => $hit_strand,
525  'score' => $score,
526  'p_value' => $evalue,
527  'percent_id' => $perc_ident,
528  'cigar_string' => $cigar_line,
529  'analysis' => $analysis,
530  'adaptor' => $self,
531  'dbID' => $dna_align_feature_id,
532  'external_db_id' => $external_db_id,
533  'hcoverage' => $hcoverage,
534  'align_type' => $align_type,
535  'dbname' => $external_db_name,
536  'db_display_name' => $external_display_db_name
537  } ) );
538 
539  } ## end while ( $sth->fetch() )
540 
541  return \@features;
542 } ## end sub _objs_from_sth
543 
544 =head2 list_dbIDs
545 
546  Arg [1] : none
547  Example : @feature_ids = @{$dna_align_feature_adaptor->list_dbIDs()};
548  Description: Gets an array of internal ids for all dna align features in
549  the current db
550  Arg[1] : <optional> int. not 0 for the ids to be sorted by the seq_region.
551  Returntype : list of ints
552  Exceptions : none
553  Caller : ?
554  Status : Stable
555 
556 =cut
557 
558 sub list_dbIDs {
559  my ($self, $ordered) = @_;
560 
561  return $self->_list_dbIDs("dna_align_feature",undef, $ordered);
562 }
563 
564 1;
565 
566 
EnsEMBL
Definition: Filter.pm:1
Bio::EnsEMBL::DBSQL::BaseFeatureAdaptor
Definition: BaseFeatureAdaptor.pm:24
Bio::EnsEMBL::DBSQL::BaseAdaptor::generic_fetch
public Listref generic_fetch()
Bio::EnsEMBL::DBSQL::BaseFeatureAdaptor::fetch_all_by_Slice
public Listref fetch_all_by_Slice()
Bio::EnsEMBL::DnaDnaAlignFeature
Definition: DnaDnaAlignFeature.pm:15
Bio
Definition: AltAlleleGroup.pm:4
Bio::EnsEMBL::Utils::Exception
Definition: Exception.pm:68
Bio::EnsEMBL::DBSQL::DnaAlignFeatureAdaptor
Definition: DnaAlignFeatureAdaptor.pm:25
Bio::EnsEMBL::DBSQL::BaseAlignFeatureAdaptor
Definition: BaseAlignFeatureAdaptor.pm:18