Archive Ensembl HomeArchive Ensembl Home
AttributeAdaptor.pm
Go to the documentation of this file.
00001 =head1 LICENSE
00002 
00003   Copyright (c) 1999-2012 The European Bioinformatics Institute and
00004   Genome Research Limited.  All rights reserved.
00005 
00006   This software is distributed under a modified Apache license.
00007   For license details, please see
00008 
00009     http://www.ensembl.org/info/about/code_licence.html
00010 
00011 =head1 CONTACT
00012 
00013   Please email comments or questions to the public Ensembl
00014   developers list at <dev@ensembl.org>.
00015 
00016   Questions may also be sent to the Ensembl help desk at
00017   <helpdesk@ensembl.org>.
00018 
00019 =cut
00020 
00021 =head1 NAME
00022 
00023 Bio::EnsEMBL::DBSQL::AttributeAdaptor - Provides database interaction for
00024 Bio::EnsEMBL::Attribute objects.
00025 
00026 
00027 =head1 SYNOPSIS
00028 
00029   # $db is a Bio::EnsEMBL::DBSQL::DBAdaptor object:
00030   $attribute_adaptor = $db->get_AttributeAdaptor();
00031 
00032   $attributes = $attribute_adaptor->fetch_all_by_MiscFeature($feature);
00033 
00034   $attributes = $attribute_adaptor->fetch_all_by_Slice($slice);
00035 
00036   $attribute_adaptor->store_on_Slice( $slice, \@attributes );
00037 
00038   $attribute_adaptor->store_on_MiscFeature( $misc_feature,
00039     \@attributes )
00040 
00041 =head1 DESCRIPTION
00042 
00043 =head1 METHODS
00044 
00045 =cut
00046 
00047 package Bio::EnsEMBL::DBSQL::AttributeAdaptor;
00048 
00049 use strict;
00050 use warnings;
00051 
00052 use Bio::EnsEMBL::DBSQL::BaseAdaptor;
00053 use Bio::EnsEMBL::Attribute;
00054 
00055 use Bio::EnsEMBL::Utils::Exception qw(throw warning);
00056 
00057 use vars qw(@ISA);
00058 
00059 @ISA = qw(Bio::EnsEMBL::DBSQL::BaseAdaptor);
00060 
00061 
00062 =head2 new
00063 
00064   Arg [...]  : Superclass args.  See Bio::EnsEMBL::DBSQL::BaseAdaptor
00065   Description: Instantiates a Bio::EnsEMBL::DBSQL::AttributeAdaptor
00066   Returntype : Bio::EnsEMBL::AttributeAdaptor
00067   Exceptions : none
00068   Caller     : DBAdaptor
00069   Status     : Stable
00070 
00071 =cut
00072 
00073 
00074 sub new {
00075   my $class = shift;
00076 
00077   my $self = $class->SUPER::new(@_);
00078 
00079 
00080   # cache creation could go here
00081   return $self;
00082 }
00083 
00084 use vars '$AUTOLOAD';
00085 
00086 sub AUTOLOAD {
00087   my ($self,@args) = @_;
00088   my @array_return=();
00089   my $ref_return = undef;
00090   $AUTOLOAD =~ /^.*::(\w+_)+(\w+)$/ ;
00091 
00092   my $sub = $1;
00093   my $type = $2;
00094 
00095 
00096 
00097 #  print STDERR "AUTO".$AUTOLOAD."\n";
00098 
00099 #  print STDERR "AUTOLOAD reached with call to $sub of type $type\n";
00100   if($self->can($sub)){
00101     return $self->$sub($type,@args);
00102   }
00103   else{
00104     warn("In AttribAdaptor cannot call sub $sub$type\n");
00105   }
00106   return undef;
00107 }
00108 
00109 
00110 
00111 sub store_on_ {
00112   my $self = shift;
00113   my $type = shift;
00114   my $object = shift;
00115   my $attributes = shift;
00116   my $table;
00117 
00118 
00119   my $object_id;
00120   if($type =~ /[GT][er][na][en]/){
00121     if (!ref($object)){
00122       $object_id = $object;
00123     }
00124     else {
00125       $object_id = $object->dbID;
00126     }
00127     $table = lc($type);
00128 #    $type = lc($type);
00129   }
00130   else{
00131     if(!ref($object) || !$object->isa('Bio::EnsEMBL::'.$type)) {
00132       throw("$type argument is required. but you passed $object");
00133     }
00134     if($type eq "Slice"){
00135       $object_id = $object->get_seq_region_id();
00136       $table = "seq_region"; 
00137       $type = "seq_region";
00138     }
00139     else{
00140       if($type eq "MiscFeature"){
00141     $type = "misc_feature";
00142     $table = "misc"; 
00143       }
00144       else{
00145     $table = lc($type);
00146       }
00147       
00148       $object_id = $object->dbID();
00149       my $db = $self->db();
00150       
00151       if(!$object->is_stored($db)) {
00152     throw("$type is not stored in this database.");
00153       }
00154       
00155     }
00156   }
00157   my $sth = $self->prepare( "INSERT into ".$table."_attrib ".
00158                 "SET ".$type."_id = ?, attrib_type_id = ?, ".
00159                 "value = ? " );
00160 
00161   my $undef_circular_cache = 0;
00162   for my $attrib ( @$attributes ) {
00163     if(!ref($attrib) && $attrib->isa('Bio::EnsEMBL::Attribute')) {
00164       throw("Reference to list of Bio::EnsEMBL::Attribute objects " .
00165             "argument expected.");
00166     }
00167     my $atid = $self->_store_type( $attrib );
00168     if ((defined $attrib->code) and ($attrib->code eq 'circular_seq')) {
00169     $undef_circular_cache = 1;
00170     }
00171     $sth->bind_param(1,$object_id,SQL_INTEGER);
00172     $sth->bind_param(2,$atid,SQL_INTEGER);
00173     $sth->bind_param(3,$attrib->value,SQL_VARCHAR);
00174     $sth->execute();
00175   }
00176 
00177   if($table eq "seq_region") {        
00178     if ($undef_circular_cache) {
00179     #the slice is circular
00180     $object->{'circular'} = 1;
00181     my $slice_adaptor = $object->adaptor();
00182         #undefine slice adaptor->is_circular and the circular slice cache
00183     if (defined $slice_adaptor) {
00184         $slice_adaptor->{'is_circular'} = undef;
00185         $slice_adaptor->{'circular_sr_id_cache'} = {};
00186     }
00187     }
00188   }
00189 
00190   return;
00191 }
00192 
00193 
00194 sub remove_from_{
00195   my $self   = shift;
00196   my $type   = shift;
00197   my $object = shift;
00198   my $code   = shift;
00199   my $table;
00200 
00201   if(!ref($object) || !$object->isa('Bio::EnsEMBL::'.$type)) {
00202     throw("$type argument is required or a attrib code. but you passed $object");
00203   }
00204 
00205   my $object_id;
00206   if($type eq "Slice"){
00207     $object_id = $object->get_seq_region_id();
00208     $table = "seq_region"; 
00209     $type = "seq_region";
00210     if ((defined $code) and ($code eq 'circular_seq')) {
00211     #undefine slice->is_circular, slice adaptor->is_circular and the circular slice cache
00212     $object->{'circular'} = undef;
00213     my $slice_adaptor = $object->adaptor();
00214     if (defined $slice_adaptor) {
00215         $slice_adaptor->{'is_circular'} = undef;
00216         $slice_adaptor->{'circular_sr_id_cache'} = {};
00217     }
00218     }
00219   }
00220   else{
00221     if($type eq "MiscFeature"){
00222       $type = "misc_feature";
00223       $table = "misc"; 
00224     }
00225     else{
00226       $table = lc($type);
00227     }
00228 
00229     $object_id = $object->dbID();
00230     my $db = $self->db();
00231     
00232     if(!$object->is_stored($db)) {
00233       throw("$type is not stored in this database.");
00234     }
00235 
00236   }
00237 
00238   if(!defined($object_id)) {
00239     throw("$type must have dbID.");
00240   }
00241 
00242   my $sth;
00243   if(defined($code)){
00244     $sth = $self->prepare("DELETE a FROM ".$table."_attrib a ,attrib_type at " .
00245                          "WHERE a.attrib_type_id = at.attrib_type_id AND ".
00246                          "a.".$type."_id = ? AND ".
00247              "at.code like ?");
00248     $sth->bind_param(1,$object_id,SQL_INTEGER);
00249     $sth->bind_param(2,$code,SQL_VARCHAR);
00250   }
00251   else{
00252     $sth = $self->prepare("DELETE FROM ".$table."_attrib " .
00253                          "WHERE ".$type."_id = ?");
00254     $sth->bind_param(1,$object_id,SQL_INTEGER);
00255   }
00256   $sth->execute();
00257 
00258   $sth->finish();
00259 
00260   return;
00261 }
00262 
00263 
00264 
00265 sub fetch_all_by_{
00266   my $self     = shift;
00267   my $type     = shift;
00268   my $object   = shift;
00269   my $code     = shift;
00270   my $table =undef;
00271 
00272   if(!ref($object) || !$object->isa('Bio::EnsEMBL::'.$type)) {
00273     throw("$type argument is required. but you passed $object");
00274   }
00275 
00276   my $object_id;
00277   if($type eq "Slice"){
00278     $object_id = $object->get_seq_region_id();
00279     $table = "seq_region"; 
00280     $type = "seq_region";
00281   }
00282   else{
00283     if($type eq "MiscFeature"){
00284       $type = "misc_feature";
00285       $table = "misc"; 
00286     }
00287     else{
00288       $table = lc($type);
00289     }
00290 
00291     $object_id = $object->dbID();
00292   }
00293 
00294   if(!defined($object_id)) {
00295     throw("$type must have dbID.");
00296   }
00297 
00298 
00299   my $sql = "SELECT at.code, at.name, at.description, t.value " .
00300               "FROM ".($table||$type)."_attrib t, attrib_type at ".
00301                  "WHERE t.".$type."_id = ? " .
00302              "AND   at.attrib_type_id = t.attrib_type_id ";
00303 
00304   if(defined($code)){
00305     $sql .= 'AND at.code like "'.$code.'" ';
00306   }
00307            
00308   my $sth = $self->prepare($sql);
00309 
00310   $sth->bind_param(1,$object_id,SQL_INTEGER);
00311   $sth->execute();
00312 
00313   my $results = $self->_obj_from_sth($sth);
00314 
00315   $sth->finish();
00316 
00317   return $results;
00318   
00319 }
00320 
00321 
00322 sub DESTROY{
00323 }
00324 
00325 
00326 #
00327 # _id_check
00328 #
00329 # backwards compatibility check:
00330 # check if $ensID is an object; if so, return $obj->dbID
00331 #
00332 
00333 sub _id_check {
00334   my $self = shift;
00335   my $ensID = shift;
00336 
00337   if ($ensID =~ /^\d+$/) {
00338     return $ensID;
00339   
00340   } elsif (ref($ensID) eq 'Bio::EnsEMBL::Gene' or
00341       ref($ensID) eq 'Bio::EnsEMBL::Transcript' or
00342       ref($ensID) eq 'Bio::EnsEMBL::Translation') {
00343 
00344     warning("You should pass a dbID rather than an ensembl object to store the attribute on");
00345 
00346     if ($ensID->dbID) {
00347       return $ensID->dbID;
00348     } else {
00349       throw("Ensembl object ".$ensID->display_id." doesn't have a dbID, can't store attribute");
00350     }
00351 
00352   } else {
00353     throw("Invalid dbID");
00354   }
00355 
00356 }
00357 
00358 
00359 # _store_type
00360 
00361 sub _store_type {
00362   my $self = shift;
00363   my $attrib = shift;
00364 
00365   my $sth1 = $self->prepare
00366     ("INSERT IGNORE INTO attrib_type set code = ?, name = ?, ".
00367      "description = ?" );
00368 
00369 
00370   $sth1->bind_param(1,$attrib->code,SQL_VARCHAR);
00371   $sth1->bind_param(2,$attrib->name,SQL_VARCHAR);
00372   $sth1->bind_param(3,$attrib->description,SQL_LONGVARCHAR);
00373 
00374   my $rows_inserted =  $sth1->execute();
00375 
00376   my $atid = $sth1->{'mysql_insertid'};
00377 
00378   if($rows_inserted == 0) {
00379     # the insert failed because the code is already stored
00380     my $sth2 = $self->prepare
00381       ("SELECT attrib_type_id FROM attrib_type " .
00382        "WHERE code = ?");
00383     $sth2->bind_param(1,$attrib->code,SQL_VARCHAR);
00384     $sth2->execute();
00385     ($atid) = $sth2->fetchrow_array();
00386 
00387     $sth2->finish();
00388 
00389     if(!$atid) {
00390       throw("Could not store or fetch attrib_type code [".$attrib->code."]\n" .
00391         "Wrong database user/permissions?");
00392     }
00393   }
00394 
00395   $sth1->finish();
00396 
00397   return $atid;
00398 }
00399 
00400 
00401 sub _obj_from_sth {
00402   my $self = shift;
00403   my $sth = shift;
00404 
00405   my ($code, $name, $desc, $value);
00406   $sth->bind_columns(\$code, \$name, \$desc, \$value);
00407 
00408   my @results;
00409   while($sth->fetch()) {
00410     push @results, Bio::EnsEMBL::Attribute->new_fast
00411                                              ( {'code' => $code,
00412                                                 'name' => $name,
00413                                                 'description' => $desc,
00414                                                 'value' => $value} );
00415   }
00416 
00417   return \@results;
00418 }
00419 
00420 
00421 
00422 
00423 1;
00424