ensembl-hive  2.7.0
AttributeAdaptor.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 
22 =head1 CONTACT
23 
24  Please email comments or questions to the public Ensembl
25  developers list at <http://lists.ensembl.org/mailman/listinfo/dev>.
26 
27  Questions may also be sent to the Ensembl help desk at
28  <http://www.ensembl.org/Help/Contact>.
29 
30 =cut
31 
32 =head1 NAME
33 
34 Bio::EnsEMBL::DBSQL::AttributeAdaptor - Provides database interaction for
36 
37 
38 =head1 SYNOPSIS
39 
40  # $db is a Bio::EnsEMBL::DBSQL::DBAdaptor object:
41  $attribute_adaptor = $db->get_AttributeAdaptor();
42 
43  $attributes = $attribute_adaptor->fetch_all_by_MiscFeature($feature);
44 
45  $attributes = $attribute_adaptor->fetch_all_by_Slice($slice);
46 
47  $attribute_adaptor->store_on_Slice( $slice, \@attributes );
48 
49  $attribute_adaptor->store_on_MiscFeature( $misc_feature,
50  \@attributes )
51 
52 =head1 DESCRIPTION
53 
54 =head1 METHODS
55 
56 =cut
57 
58 package Bio::EnsEMBL::DBSQL::AttributeAdaptor;
59 
60 use strict;
61 use warnings;
62 
65 
66 use Bio::EnsEMBL::Utils::Exception qw(throw warning);
67 use Bio::EnsEMBL::Utils::Scalar qw(assert_ref);
68 
69 use vars qw(@ISA);
70 
72 
73 =head2 new
74 
75  Arg [...] : Superclass args. See Bio::EnsEMBL::DBSQL::BaseAdaptor
76  Description: Instantiates a Bio::EnsEMBL::DBSQL::AttributeAdaptor
77  Returntype : Bio::EnsEMBL::AttributeAdaptor
78  Exceptions : none
79  Caller : DBAdaptor
80  Status : Stable
81 
82 =cut
83 
84 sub new {
85  my $class = shift;
86 
87  my $self = $class->SUPER::new(@_);
88 
89  # cache creation could go here
90  return $self;
91 }
92 
93 
94 
95 ## Storing methods
96 
97 ## Batch store
98 
99 sub store_batch_on_Object {
100  my ($self, $table, $attributes, $batch_size) = @_;
101  # $attributes is a hashref where the key is the object ID
102  # and the value is an array ref of Attribute objects
103 
104  # maintain a hash of attrib type IDs by code so we don't have to keep looking them up...
105  my $attrib_type_ids = {};
106 
107  # create an arrayref of the values to store
108  my $rows = [];
109  $batch_size ||= scalar(values(%$attributes));
110 
111  while (my ($obj_id, $attribs) = each %{$attributes}) {
112  for my $attrib (@{$attribs}) {
113 
114  my $attrib_type_id = $attrib_type_ids->{$attrib->code()};
115  if (!defined $attrib_type_id) {
116  $attrib_type_id = $self->_store_type($attrib);
117  $attrib_type_ids->{$attrib->code()} = $attrib_type_id;
118  }
119 
120  push @$rows, sprintf('(%d, %d, %s)', $obj_id, $attrib_type_id, $self->dbc()->db_handle()->quote($attrib->value()));
121 
122  if (scalar(@$rows) == $batch_size) {
123  $rows = $self->_store_batch_rows($table, $rows);
124  }
125  }
126  }
127 
128  $rows = $self->_store_batch_rows($table, $rows);
129 
130  return;
131 }
132 
133 sub _store_batch_rows {
134  my ($self, $table, $rows) = @_;
135  if (scalar(@$rows) > 0) {
136  $self->dbc()->sql_helper()->execute_update(-SQL => 'INSERT INTO ' . $table . '_attrib(' . $table . '_id, attrib_type_id, value) VALUES ' . join(',', @$rows));
137  }
138  return [];
139 }
140 
141 
142 sub store_batch_on_MiscAttrib {
143  my ($self, $attributes, $batch_size) = @_;
144 
145  $self->store_batch_on_Object('misc_feature', $attributes, $batch_size);
146 
147  return;
148 }
149 
150 sub store_batch_on_Slice {
151  my ($self, $attributes, $batch_size) = @_;
152 
153  $self->store_batch_on_Object('seq_region', $attributes, $batch_size);
154 
155  return;
156 }
157 
158 sub store_batch_on_Gene {
159  my ($self, $attributes, $batch_size) = @_;
160 
161  $self->store_batch_on_Object('gene', $attributes, $batch_size);
162 
163  return;
164 }
165 
166 sub store_batch_on_Transcript {
167  my ($self, $attributes, $batch_size) = @_;
168 
169  $self->store_batch_on_Object('transcript', $attributes, $batch_size);
170 
171  return;
172 }
173 
174 sub store_batch_on_Translation {
175  my ($self, $attributes, $batch_size) = @_;
176 
177  $self->store_batch_on_Object('translation', $attributes, $batch_size);
178 
179  return;
180 }
181 
182 sub store_batch_on_DnaDnaAlignFeature {
183  my ($self, $attributes, $batch_size) = @_;
184 
185  $self->store_batch_on_Object('dna_align_feature', $attributes, $batch_size);
186 
187  return;
188 }
189 
190 
191 ## Single store
192 
193 sub store_on_Object {
194  my ($self, $object_id, $attributes, $table, $type) = @_;
195 
196  my $db = $self->db();
197  if (!defined $type) {
198  $type = $table;
199  }
200 
201  my $insert_ignore = $self->insert_ignore_clause();
202  my $sth = $self->prepare( "${insert_ignore} INTO ${table}_attrib (${type}_id, attrib_type_id, value)" .
203  "VALUES (?, ?, ?)" );
204 
205  for my $attrib ( @$attributes ) {
206  if(!ref($attrib) && $attrib->isa('Bio::EnsEMBL::Attribute')) {
207  throw("Reference to list of Bio::EnsEMBL::Attribute objects " .
208  "argument expected.");
209  }
210 
211  my $atid = $self->_store_type( $attrib );
212  $sth->bind_param(1,$object_id,SQL_INTEGER);
213  $sth->bind_param(2,$atid,SQL_INTEGER);
214  $sth->bind_param(3,$attrib->value,SQL_VARCHAR);
215  $sth->execute();
216  }
217 
218  return;
219 }
220 
221 
222 sub store_on_MiscFeature {
223  my ($self, $object, $attributes) = @_;
224 
225  assert_ref( $object, 'Bio::EnsEMBL::MiscFeature');
226 
227  my $object_id = $object->dbID();
228  $self->store_on_Object($object_id, $attributes, 'misc', 'misc_feature');
229 
230  return;
231 }
232 
233 sub store_on_Slice {
234  my ($self, $object, $attributes) = @_;
235 
236  assert_ref( $object, 'Bio::EnsEMBL::Slice');
237 
238  my $object_id = $object->get_seq_region_id();
239  $self->store_on_Object($object_id, $attributes, 'seq_region');
240 
241  my $undef_circular_cache = 0;
242  for my $attrib ( @$attributes ) {
243  if ((defined $attrib->code) and ($attrib->code eq 'circular_seq')) {
244  $undef_circular_cache = 1;
245  }
246  }
247 
248  if ($undef_circular_cache) {
249  #the slice is circular
250  $object->{'circular'} = 1;
251  my $slice_adaptor = $object->adaptor();
252  #undefine slice adaptor->is_circular and the circular slice cache
253  if (defined $slice_adaptor) {
254  $slice_adaptor->{'is_circular'} = undef;
255  $slice_adaptor->{'circular_sr_id_cache'} = {};
256  }
257  }
258 
259  return;
260 }
261 
262 sub store_on_Gene {
263  my ($self, $object, $attributes) = @_;
264 
265  my $object_id;
266  if (!ref($object)){
267  $object_id = $object;
268  }
269  else {
270  $object_id = $object->dbID;
271  }
272 
273  $self->store_on_Object($object_id, $attributes, 'gene');
274 
275  return;
276 }
277 
278 sub store_on_Transcript {
279  my ($self, $object, $attributes) = @_;
280 
281  my $object_id;
282  if (!ref($object)){
283  $object_id = $object;
284  }
285  else {
286  $object_id = $object->dbID;
287  }
288 
289  $self->store_on_Object($object_id, $attributes, 'transcript');
290 
291  return;
292 }
293 
294 sub store_on_RNAProduct {
295  my ($self, $object, $attributes) = @_;
296 
297  my $object_id;
298  if (!ref($object)) {
299  $object_id = $object;
300  }
301  else {
302  $object_id = $object->dbID();
303  }
304 
305  $self->store_on_Object($object_id, $attributes, 'rnaproduct');
306 
307  return;
308 }
309 
310 sub store_on_Translation {
311  my ($self, $object, $attributes) = @_;
312 
313  my $object_id;
314  if (!ref($object)){
315  $object_id = $object;
316  }
317  else {
318  $object_id = $object->dbID;
319  }
320 
321  $self->store_on_Object($object_id, $attributes, 'translation');
322 
323  return;
324 }
325 
326 sub store_on_DnaDnaAlignFeature {
327  my ($self, $object, $attributes) = @_;
328 
329  my $object_id;
330  if (!ref($object)){
331  $object_id = $object;
332  }
333  else {
334  $object_id = $object->dbID;
335  }
336 
337  $self->store_on_Object($object_id, $attributes, 'dna_align_feature');
338 
339  return;
340 }
341 
342 
343 ## Remove methods
344 
345 sub remove_from_Object {
346  my ($self, $object_id, $table, $code, $type) = @_;
347 
348  my $db = $self->db();
349 
350  if(!defined($object_id)) {
351  throw("$table must have dbID.");
352  }
353  if (!defined($type)) {
354  $type = $table;
355  }
356 
357  my $sth;
358  if (defined($code)) {
359  if ($db->dbc->driver() eq 'mysql') {
360  $sth = $self->prepare("DELETE a FROM " . $table . "_attrib a, attrib_type at " .
361  "WHERE a.attrib_type_id = at.attrib_type_id AND ".
362  "a." . $type . "_id = ? AND ".
363  "at.code like ?");
364  } else {
365  $sth = $self->prepare(qq{DELETE FROM ${table}_attrib
366  WHERE ${type}_id = ? AND
367  attrib_type_id IN
368  (SELECT attrib_type_id
369  FROM attrib_type
370  WHERE code LIKE ? ) });
371  }
372  $sth->bind_param(1,$object_id,SQL_INTEGER);
373  $sth->bind_param(2,$code,SQL_VARCHAR);
374  }
375  else{
376  $sth = $self->prepare("DELETE FROM " . $table . "_attrib " .
377  "WHERE " . $type . "_id = ?");
378  $sth->bind_param(1,$object_id,SQL_INTEGER);
379  }
380  $sth->execute();
381  $sth->finish();
382 
383  return;
384 
385 }
386 
387 
388 sub remove_from_MiscFeature {
389  my ($self, $object, $code) = @_;
390 
391  assert_ref($object, 'Bio::EnsEMBL::MiscFeature');
392 
393  my $object_id = $object->dbID();
394  $self->remove_from_Object($object_id, 'misc', $code, 'misc_feature');
395 
396  return;
397 
398 }
399 
400 sub remove_from_Slice {
401  my ($self, $object, $code) = @_;
402 
403  assert_ref($object, 'Bio::EnsEMBL::Slice');
404 
405  my $object_id = $object->get_seq_region_id();
406  $self->remove_from_Object($object_id, 'seq_region', $code);
407 
408  return;
409 
410 }
411 
412 sub remove_from_Gene {
413  my ($self, $object, $code) = @_;
414 
415  assert_ref($object, 'Bio::EnsEMBL::Gene');
416 
417  my $object_id = $object->dbID();
418  $self->remove_from_Object($object_id, 'gene', $code);
419 
420  return;
421 
422 }
423 
424 sub remove_from_Transcript {
425  my ($self, $object, $code) = @_;
426 
427  assert_ref($object, 'Bio::EnsEMBL::Transcript');
428 
429  my $object_id = $object->dbID();
430  $self->remove_from_Object($object_id, 'transcript', $code);
431 
432  return;
433 
434 }
435 
436 sub remove_from_RNAProduct {
437  my ($self, $object, $code) = @_;
438 
439  assert_ref($object, 'Bio::EnsEMBL::RNAProduct');
440 
441  my $object_id = $object->dbID();
442  $self->remove_from_Object($object_id, 'rnaproduct', $code);
443 
444  return;
445 
446 }
447 
448 sub remove_from_Translation {
449  my ($self, $object, $code) = @_;
450 
451  assert_ref($object, 'Bio::EnsEMBL::Translation');
452 
453  my $object_id = $object->dbID();
454  $self->remove_from_Object($object_id, 'translation', $code);
455 
456  return;
457 
458 }
459 
460 sub remove_from_DnaDnaAlignFeature {
461  my ($self, $object, $code) = @_;
462 
463  assert_ref($object, 'Bio::EnsEMBL::DnaDnaAlignFeature');
464 
465  my $object_id = $object->dbID();
466  $self->remove_from_Object($object_id, 'dna_align_feature', $code);
467 
468  return;
469 
470 }
471 
472 
473 
474 ## Fetch methods
475 
476 sub fetch_all {
477  throw("Use of method fetch_all not supported for attributes");
478 }
479 
480 sub fetch_by_code {
481  my ($self, $code) = @_;
482 
483  my $sql = "SELECT attrib_type_id, code, name, description " .
484  "FROM attrib_type
485  WHERE code = '$code' ";
486  my $sth = $self->prepare($sql);
487  $sth->execute();
488 
489  my ($attrib_type_id, $name, $desc);
490  $sth->bind_columns(\$attrib_type_id, \$code, \$name, \$desc);
491 
492  my @results = $sth->fetchrow_array;
493  $sth->finish();
494 
495  return \@results;
496 }
497 
498 
499 
500 sub fetch_all_by_Object {
501  my ($self, $object_id, $table, $code, $type) = @_;
502 
503  if (!defined $type) {
504  $type = $table;
505  }
506 
507  my $sql = "SELECT at.code, at.name, at.description, a.value " .
508  "FROM " . $table . "_attrib a, attrib_type at " .
509  "WHERE at.attrib_type_id = a.attrib_type_id ";
510 
511  if (defined($code)) {
512  $sql .= 'AND at.code like "' . $code . '" ';
513  }
514  if (defined($object_id)) {
515  $sql .= "AND a." .$type . "_id = " . $object_id;
516  }
517 
518  my $sth = $self->prepare($sql);
519  $sth->execute();
520  my $results = $self->_obj_from_sth($sth);
521  $sth->finish();
522 
523  return $results;
524 }
525 
526 
527 sub fetch_all_by_MiscFeature {
528  my ($self, $object, $code) = @_;
529 
530  my $object_id;
531 
532  if (defined($object)) {
533  assert_ref($object, 'Bio::EnsEMBL::MiscFeature');
534  $object_id = $object->dbID();
535  }
536 
537  my $results = $self->fetch_all_by_Object($object_id, 'misc', $code, 'misc_feature');
538 
539  return $results;
540 
541 }
542 
543 sub fetch_all_by_Slice {
544  my ($self, $object, $code) = @_;
545 
546  my $object_id;
547 
548  if (defined($object)) {
549  assert_ref($object, 'Bio::EnsEMBL::Slice');
550  $object_id = $object->get_seq_region_id();
551  }
552 
553  my $results = $self->fetch_all_by_Object($object_id, 'seq_region', $code);
554 
555  return $results;
556 
557 }
558 
559 sub fetch_all_by_Gene {
560  my ($self, $object, $code) = @_;
561 
562  my $object_id;
563 
564  if (defined($object)) {
565  assert_ref($object, 'Bio::EnsEMBL::Gene');
566  $object_id = $object->dbID();
567  }
568 
569  my $results = $self->fetch_all_by_Object($object_id, 'gene', $code);
570 
571  return $results;
572 
573 }
574 
575 sub fetch_all_by_Transcript {
576  my ($self, $object, $code) = @_;
577 
578  my $object_id;
579 
580  if (defined($object)) {
581  assert_ref($object, 'Bio::EnsEMBL::Transcript');
582  $object_id = $object->dbID();
583  }
584 
585  my $results = $self->fetch_all_by_Object($object_id, 'transcript', $code);
586 
587  return $results;
588 
589 }
590 
591 sub fetch_all_by_Translation {
592  my ($self, $object, $code) = @_;
593 
594  my $object_id;
595 
596  if (defined($object)) {
597  assert_ref($object, 'Bio::EnsEMBL::Translation');
598  $object_id = $object->dbID();
599  }
600 
601  my $results = $self->fetch_all_by_Object($object_id, 'translation', $code);
602 
603  return $results;
604 
605 }
606 
607 sub fetch_all_by_RNAProduct {
608  my ($self, $object, $code) = @_;
609 
610  my $object_id;
611 
612  if (defined($object)) {
613  assert_ref($object, 'Bio::EnsEMBL::RNAProduct');
614  $object_id = $object->dbID();
615  }
616 
617  my $results = $self->fetch_all_by_Object($object_id, 'rnaproduct', $code);
618 
619  return $results;
620 
621 }
622 
623 sub fetch_all_by_DnaDnaAlignFeature {
624  my ($self, $object, $code) = @_;
625 
626  my $object_id;
627 
628  if (defined($object)) {
629  assert_ref($object, 'Bio::EnsEMBL::DnaDnaAlignFeature');
630  $object_id = $object->dbID();
631  }
632 
633  my $results = $self->fetch_all_by_Object($object_id, 'dna_align_feature', $code);
634 
635  return $results;
636 
637 }
638 
639 
640 
641 
642 #
643 # _id_check
644 #
645 # backwards compatibility check:
646 # check if $ensID is an object; if so, return $obj->dbID
647 #
648 
649 sub _id_check {
650  my $self = shift;
651  my $ensID = shift;
652 
653  if ($ensID =~ /^\d+$/) {
654  return $ensID;
655 
656  } elsif ( ref($ensID) eq 'Bio::EnsEMBL::Gene'
657  or ref($ensID) eq 'Bio::EnsEMBL::Transcript'
658  or ref($ensID) eq 'Bio::EnsEMBL::Translation')
659  {
660 
661  warning("You should pass a dbID rather than an ensembl object to store the attribute on");
662 
663  if ($ensID->dbID) {
664  return $ensID->dbID;
665  } else {
666  throw("Ensembl object " . $ensID->display_id . " doesn't have a dbID, can't store attribute");
667  }
668 
669  } else {
670  throw("Invalid dbID");
671  }
672 
673 } ## end sub _id_check
674 
675 # _store_type
676 
677 sub _store_type {
678  my $self = shift;
679  my $attrib = shift;
680 
681  my $insert_ignore = $self->insert_ignore_clause();
682  my $sth1 = $self->prepare
683  ("${insert_ignore} INTO attrib_type (code, name, description) values (?, ?, ?)" );
684 
685 
686  $sth1->bind_param(1, $attrib->code, SQL_VARCHAR);
687  $sth1->bind_param(2, $attrib->name, SQL_VARCHAR);
688  $sth1->bind_param(3, $attrib->description, SQL_LONGVARCHAR);
689 
690  my $rows_inserted = $sth1->execute();
691 
692  my $atid = $self->last_insert_id('attrib_type_id', undef, 'attrib_type');
693 
694  if ($rows_inserted == 0) {
695  # the insert failed because the code is already stored
696  my $sth2 = $self->prepare("SELECT attrib_type_id FROM attrib_type " . "WHERE code = ?");
697  $sth2->bind_param(1, $attrib->code, SQL_VARCHAR);
698  $sth2->execute();
699  ($atid) = $sth2->fetchrow_array();
700 
701  $sth2->finish();
702 
703  if (!$atid) {
704  throw("Could not store or fetch attrib_type code [" . $attrib->code . "]\n" . "Wrong database user/permissions?");
705  }
706  }
707 
708  $sth1->finish();
709 
710  return $atid;
711 } ## end sub _store_type
712 
713 sub _obj_from_sth {
714  my $self = shift;
715  my $sth = shift;
716 
717  my ($code, $name, $desc, $value);
718  $sth->bind_columns(\$code, \$name, \$desc, \$value);
719 
720  my @results;
721  while ($sth->fetch()) {
722  push @results,
723  Bio::EnsEMBL::Attribute->new_fast({'code' => $code,
724  'name' => $name,
725  'description' => $desc,
726  'value' => $value});
727  }
728 
729  return \@results;
730 }
731 
732 1;
733 
Bio::EnsEMBL::DBSQL::DBAdaptor
Definition: DBAdaptor.pm:40
Bio::EnsEMBL::DBSQL::AttributeAdaptor
Definition: AttributeAdaptor.pm:27
Bio::EnsEMBL::DBSQL::BaseAdaptor
Definition: BaseAdaptor.pm:71
Bio::EnsEMBL::Utils::Scalar
Definition: Scalar.pm:66
Bio::EnsEMBL::Attribute::new_fast
public Bio::EnsEMBL::Attribute new_fast()
Bio::EnsEMBL::Attribute
Definition: Attribute.pm:34
Bio::EnsEMBL::Utils::Exception
Definition: Exception.pm:68