BaseInfoAdaptor.pm
Go to the documentation of this file.
00001 
00002 =head1 LICENSE
00003 
00004 Copyright [1999-2016] EMBL-European Bioinformatics Institute
00005 
00006 Licensed under the Apache License, Version 2.0 (the "License");
00007 you may not use this file except in compliance with the License.
00008 You may obtain a copy of the License at
00009 
00010      http://www.apache.org/licenses/LICENSE-2.0
00011 
00012 Unless required by applicable law or agreed to in writing, software
00013 distributed under the License is distributed on an "AS IS" BASIS,
00014 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015 See the License for the specific language governing permissions and
00016 limitations under the License.
00017 
00018 =cut
00019 
00020 =pod
00021 
00022 =head1 NAME
00023 
00024 Bio::EnsEMBL::MetaData::DBSQL::BaseInfoAdaptor
00025 
00026 =head1 DESCRIPTION
00027 
00028 Base adaptor for storing and retrieving objects from MySQL genome_metadata database
00029 
00030 Provides basic methods for store/fetch
00031 
00032 =head1 AUTHOR
00033 
00034 Dan Staines
00035 
00036 =head1 SEE ALSO
00037 
00038 Bio::EnsEMBL::MetaData::BaseInfo
00039 
00040 =cut
00041 
00042 package Bio::EnsEMBL::MetaData::DBSQL::BaseInfoAdaptor;
00043 
00044 use strict;
00045 use warnings;
00046 use Carp qw(cluck croak);
00047 use Module::Load;
00048 use Bio::EnsEMBL::Utils::Argument qw( rearrange );
00049 use Bio::EnsEMBL::Utils::Exception qw/throw/;
00050 use List::MoreUtils qw/natatime/;
00051   
00052 use base qw/Bio::EnsEMBL::DBSQL::BaseAdaptor/;
00053 
00054 =head1 METHODS
00055 =head2 fetch_all
00056   Arg        : (optional) if 1, expand children of genome info
00057   Description: Fetch all genome info
00058   Returntype : Bio::EnsEMBL::MetaData::GenomeInfo
00059   Exceptions : none
00060   Caller     : general
00061   Status     : Stable
00062 =cut
00063 
00064 sub fetch_all {
00065   my ( $self, $keen ) = @_;
00066   return $self->_fetch_generic_with_args( {}, $keen );
00067 }
00068 
00069 =head2 fetch_by_dbID
00070   Arg        : ID of genome info
00071   Arg        : (optional) if 1, expand children of genome info
00072   Description: Fetch genome info for specified ID
00073   Returntype : Bio::EnsEMBL::MetaData::GenomeInfo
00074   Exceptions : none
00075   Caller     : internal
00076   Status     : Stable
00077 =cut
00078 
00079 sub fetch_by_dbID {
00080   my ( $self, $id, $keen ) = @_;
00081   return
00082     $self->_first_element( $self->_fetch_generic_with_args(
00083                                                  { $self->_get_id_field(), $id }
00084                            ),
00085                            $keen );
00086 }
00087 
00088 =head2 fetch_by_dbIDs
00089   Arg        : IDs of genome info
00090   Arg        : (optional) if 1, expand children of genome info
00091   Description: Fetch genome info for specified ID
00092   Returntype : Bio::EnsEMBL::MetaData::GenomeInfo
00093   Exceptions : none
00094   Caller     : internal
00095   Status     : Stable
00096 =cut
00097 
00098 sub fetch_by_dbIDs {
00099   my ( $self, $ids, $keen ) = @_;
00100   my @genomes = ();
00101   my $it = natatime 1000, @{$ids};
00102   while ( my @vals = $it->() ) {
00103     my $sql =
00104       $self->_get_base_sql() . ' where ' . $self->_get_id_field() . ' in (' .
00105       join( ',', @vals ) . ')';
00106     @genomes = ( @genomes, @{ $self->_fetch_generic( $sql, [] ) } );
00107   }
00108   return \@genomes;
00109 }
00110 
00111 =head1 INTERNAL METHODS
00112 =head2 _get_base_sql
00113   Description: Base SQL for fetching object - must be implemented 
00114   Returntype : String
00115   Exceptions : none
00116   Caller     : internal
00117   Status     : Stable
00118 =cut
00119 sub _get_base_sql {
00120   throw("Method not implemented in base class");
00121 }
00122 
00123 =head2 _get_id_field
00124   Description: Database column containing dbID - must be implemented 
00125   Returntype : String
00126   Exceptions : none
00127   Caller     : internal
00128   Status     : Stable
00129 =cut
00130 sub _get_id_field {
00131   throw("Method not implemented in base class");
00132 }
00133 
00134 =head2 _get_obj_class
00135   Description: Class of object retrieved - must be implemented 
00136   Returntype : String
00137   Exceptions : none
00138   Caller     : internal
00139   Status     : Stable
00140 =cut
00141 sub _get_obj_class {
00142   throw("Method not implemented in base class");
00143 }
00144 
00145 =head2 _fetch_generic_with_args
00146   Arg        : hashref of arguments by column
00147   Arg        : (optional) if set to 1, all children will be fetched
00148   Description: Instantiate a GenomeInfo from the database using a 
00149                generic method, with the supplied arguments
00150   Returntype : Arrayref of Bio::EnsEMBL::MetaData::GenomeInfo
00151   Exceptions : none
00152   Caller     : internal
00153   Status     : Stable
00154 =cut
00155 
00156 sub _fetch_generic_with_args {
00157   my ( $self, $args, $type, $keen ) = @_;
00158   my ( $sql, $params ) = $self->_args_to_sql( $self->_get_base_sql(), $args );
00159   my $info =
00160     $self->_fetch_generic( $sql, $params, $self->_get_obj_class(), $keen );
00161   return $info;
00162 }
00163 
00164 =head2 _get_obj_class
00165   Description: Load children of object - no-op implementation, can be overridden
00166   Arg        : Object to retrieve children for
00167   Returntype : non
00168   Exceptions : none
00169   Caller     : internal
00170   Status     : Stable
00171 =cut
00172 sub _fetch_children {
00173   my ( $self, $i ) = @_;
00174   # do nothing
00175   return;
00176 }
00177 
00178 =head2 _args_to_sql
00179   Description: Add where clauses to SQL given arguments
00180   Arg        : String - Base SQL
00181   Arg        : Hashref - arguments
00182   Returntype : String
00183   Exceptions : none
00184   Caller     : internal
00185   Status     : Stable
00186 =cut
00187 sub _args_to_sql {
00188   my ( $self, $sql_in, $args ) = @_;
00189   my $sql    = $sql_in;
00190   my $params = [];
00191   my $clause = '';
00192   while ( my ( $k, $v ) = each %$args ) {
00193     if ( $clause ne '' ) {
00194       $clause .= ' AND ';
00195     }
00196     if ( ref($v) eq 'ARRAY' ) {
00197       $clause .= "$k in (" . join( ',', map { '?' } @$v ) . ")";
00198       $params = [ @$params, @$v ];
00199     }
00200     else {
00201       $clause .= "$k = ?";
00202       push @$params, $v;
00203     }
00204   }
00205   if ( $clause ne '' ) {
00206     $sql .= ' where ' . $clause;
00207   }
00208   return ( $sql, $params );
00209 }
00210 
00211 =head2 _fetch_generic
00212   Arg        : SQL to use to fetch object
00213   Arg        : arrayref of bind parameters
00214   Arg        : (optional) if set to 1, all children will be fetched
00215   Description: Instantiate a GenomeInfo from the database using the specified SQL
00216   Returntype : Arrayref of Bio::EnsEMBL::MetaData::GenomeInfo
00217   Exceptions : none
00218   Caller     : internal
00219   Status     : Stable
00220 =cut
00221 
00222 sub _fetch_generic {
00223   my ( $self, $sql, $params, $type, $keen ) = @_;
00224   if ( !defined $type ) {
00225     $type = $self->_get_obj_class();
00226   }
00227   my $mds = $self->{dbc}->sql_helper()->execute(
00228     -SQL          => $sql,
00229     -USE_HASHREFS => 1,
00230     -CALLBACK     => sub {
00231       my $row = shift @_;
00232       my $md = $self->_get_cached_obj( $type, $row->{dbID} );
00233       if ( !defined $md ) {
00234         load $type;
00235         $md = bless $row, $type;
00236         $md->adaptor($self);
00237         $self->_store_cached_obj($md);
00238       }
00239       return $md;
00240     },
00241     -PARAMS => $params );
00242   if ($keen) {
00243     for my $md ( @{$mds} ) {
00244       $self->_fetch_children( $md, $keen );
00245     }
00246   }
00247   return $mds;
00248 } ## end sub _fetch_generic
00249 
00250 =head2 _get_division_id
00251   Arg        : division name
00252   Description: Return ID for division, storing if required
00253   Returntype : none
00254   Exceptions : none
00255   Caller     : internal
00256   Status     : Stable
00257 =cut
00258 
00259 my $division_names = { 'Ensembl'         => 'E',
00260                        'EnsemblGenomes'  => 'EG',
00261                        'EnsemblBacteria' => 'EB',
00262                        'EnsemblMetazoa'  => 'EM',
00263                        'EnsemblPlants'   => 'EPl',
00264                        'EnsemblProtists' => 'EPr',
00265                        'EnsemblFungi'    => 'EF' };
00266 
00267 sub _get_division_id {
00268   my ( $self, $division, $short_name ) = @_;
00269 
00270   my $div_id = $self->_cache('division')->{$division};
00271 
00272   if ( !defined $div_id ) {
00273 
00274     $div_id = $self->{dbc}->sql_helper()->transaction(
00275       -CALLBACK => sub {
00276         my ($dbc) = @_;
00277         my $id;
00278         my $ids =
00279           $dbc->sql_helper()->execute_simple(
00280                         -SQL => 'select division_id from division where name=?',
00281                         -PARAMS => [$division] );
00282         if ( scalar(@$ids) == 0 ) {
00283           # not found so create
00284           if ( !defined $short_name ) {
00285             $short_name = $division_names->{$division};
00286             if ( !defined $short_name ) {
00287               $short_name = $division;
00288               $short_name =~ s/[a-z]+//g;
00289             }
00290           }
00291           $dbc->sql_helper->execute_update(
00292             -SQL      => 'insert into division (name,short_name) values(?,?)',
00293             -CALLBACK => sub {
00294               my ( $sth, $dbh, $rv ) = @_;
00295               $id = $dbh->{mysql_insertid};
00296             },
00297             -PARAMS => [ $division, $short_name ] );
00298         }
00299         else {
00300           $id = $ids->[0];
00301         }
00302         return $id;
00303       } );
00304     $self->_cache('division')->{$division} = $div_id;
00305   } ## end if ( !defined $div_id )
00306   
00307   return $div_id;
00308 } ## end sub _get_division_id
00309 
00310 =head2 _cache
00311   Arg        : type of object for cache
00312   Description: Return internal cache for given type
00313   Returntype : none
00314   Exceptions : none
00315   Caller     : internal
00316   Status     : Stable
00317 =cut
00318 
00319 sub _cache {
00320   my ( $self, $type ) = @_;
00321   if ( !defined $self->{cache} || !defined $self->{cache}{$type} ) {
00322     $self->{cache}{$type} = {};
00323   }
00324   return $self->{cache}{$type};
00325 }
00326 
00327 =head2 _clear_cache
00328   Arg        : (optional) type of object to clear
00329   Description: Clear internal cache (optionally just one type)
00330   Returntype : none
00331   Exceptions : none
00332   Caller     : internal
00333   Status     : Stable
00334 =cut
00335 
00336 sub _clear_cache {
00337   my ( $self, $type ) = @_;
00338   if ( defined $type ) {
00339     $self->{cache}{$type} = {};
00340   }
00341   else {
00342     $self->{cache} = {};
00343   }
00344   return;
00345 }
00346 
00347 =head2 _get_cached_obj
00348   Arg        : type of object to retrieve
00349   Arg        : ID of object to retrieve
00350   Description: Retrieve object from internal cache
00351   Returntype : object
00352   Exceptions : none
00353   Caller     : internal
00354   Status     : Stable
00355 =cut
00356 
00357 sub _get_cached_obj {
00358   my ( $self, $type, $id ) = @_;
00359   return $self->_cache($type)->{$id};
00360 }
00361 
00362 =head2 _store_cached_obj
00363   Arg        : type of object to store
00364   Arg        : object to store
00365   Description: Store object in internal cache
00366   Returntype : none
00367   Exceptions : none
00368   Caller     : internal
00369   Status     : Stable
00370 =cut
00371 
00372 sub _store_cached_obj {
00373   my ( $self, $obj ) = @_;
00374   my $type = ref $obj;
00375   $self->_cache($type)->{ $obj->dbID() } = $obj;
00376   return;
00377 }
00378 
00379 =head2 _first_element
00380   Arg        : arrayref
00381   Description: Utility method to return the first element in a list, undef if empty
00382   Returntype : arrayref element
00383   Exceptions : none
00384   Caller     : internal
00385   Status     : Stable
00386 =cut
00387 
00388 sub _first_element {
00389   my ( $self, $arr ) = @_;
00390   if ( defined $arr && scalar(@$arr) > 0 ) {
00391     return $arr->[0];
00392   }
00393   else {
00394     return undef;
00395   }
00396 }
00397 
00398 1;