Commit e2f9fada authored by Leo Gordon's avatar Leo Gordon
Browse files

updated version of adaptors class hierarchy

parent b250f832
......@@ -26,7 +26,7 @@ package Bio::EnsEMBL::Hive::DBSQL::AnalysisCtrlRuleAdaptor;
use strict;
use Bio::EnsEMBL::Hive::AnalysisCtrlRule;
use base ('Bio::EnsEMBL::Hive::DBSQL::BaseAdaptor');
use base ('Bio::EnsEMBL::Hive::DBSQL::ObjectAdaptor');
sub default_table_name {
......
package Bio::EnsEMBL::Hive::DBSQL::BaseAdaptor;
use strict;
use Data::Dumper;
no strict 'refs'; # needed to allow AUTOLOAD create new methods
use base ('Bio::EnsEMBL::DBSQL::BaseAdaptor');
......@@ -22,6 +21,7 @@ sub table_name {
if(@_) { # setter
$self->{_table_name} = shift @_;
$self->_table_info_loader();
}
return $self->{_table_name} || $self->default_table_name();
}
......@@ -37,16 +37,6 @@ sub insertion_method {
}
sub object_class { # this one can stay undefined
my $self = shift @_;
if(@_) { # setter
$self->{_object_class} = shift @_;
}
return $self->{_object_class};
}
sub column_set {
my $self = shift @_;
......@@ -149,11 +139,10 @@ sub count_all {
sub fetch_all {
my ($self, $constraint) = @_;
my ($self, $constraint, $one_per_key, $key_list, $value_column) = @_;
my $table_name = $self->table_name();
my $columns_csv = join(', ', keys %{$self->column_set()});
my $object_class = $self->object_class();
my $sql = "SELECT $columns_csv FROM $table_name";
......@@ -166,18 +155,33 @@ sub fetch_all {
my $sth = $self->prepare($sql);
$sth->execute;
my @objects;
my $result_struct; # will be autovivified to the correct data structure
while(my $hashref = $sth->fetchrow_hashref) {
if($object_class) {
push @objects, $object_class->new( -adaptor => $self, map { ('-'.uc($_) => $hashref->{$_}) } keys %$hashref );
my $pptr = \$result_struct;
foreach my $syll (@$key_list) {
$pptr = \$$pptr->{$hashref->{$syll}}; # using pointer-to-pointer to enforce same-level vivification
}
my $object = $value_column
? $hashref->{$value_column}
: $self->objectify($hashref);
if($one_per_key) {
$$pptr = $object;
} else {
push @objects, $hashref; # faster, but only works for naked data types and lacks a link back to the adaptor
push @$$pptr, $object;
}
}
$sth->finish;
return \@objects;
unless(defined($result_struct)) {
if(scalar(@$key_list)) {
$result_struct = {};
} elsif(!$one_per_key) {
$result_struct = [];
}
}
return $result_struct; # either listref or hashref is returned, depending on the call parameters
}
......@@ -202,18 +206,6 @@ sub fetch_by_dbID {
}
sub slicer { # take a slice of the object (if only we could inline in Perl!)
my ($self, $object, $fields) = @_;
if( my $object_class = $self->object_class() ) {
return [ map { $object->$_() } @$fields ];
} else {
return [ @$object{@$fields} ]; # <--- slicing a hashref here
}
}
sub remove { # remove the object by primary_key
my $self = shift @_;
my $object = shift @_;
......@@ -286,8 +278,6 @@ sub store {
my $insertion_method = $self->insertion_method; # INSERT, INSERT_IGNORE or REPLACE
$insertion_method =~ s/_/ /g;
my $object_class = $self->object_class();
# NB: here we assume all hashes will have the same keys:
my $non_autoinc_columns = [ grep { $_ ne $autoinc_id } keys %$column_set ];
......@@ -297,34 +287,22 @@ sub store {
foreach my $object (@$objects) {
if($check_presence_in_db_first and my $present = $self->check_object_present_in_db($object)) {
if($autoinc_id) {
if($object_class) {
$object->dbID($present);
} else {
$object->{$autoinc_id} = $present;
}
}
$self->mark_stored($object, $present);
} else {
#print "STORE: $sql\n";
$sth ||= $self->prepare( $sql ); # only prepare (once) if we get here
#print "NON_AUTOINC_COLUMNS: ".join(', ', @$non_autoinc_columns)."\n";
my $non_autoinc_values = $self->slicer( $object, $non_autoinc_columns );
#print "NON_AUTOINC_VALUES: ".join(', ', @$non_autoinc_values)."\n";
my $return_code = $sth->execute( @$non_autoinc_values )
# using $return_code in boolean context allows to skip the value '0E0' ('no rows affected') that Perl treats as zero but regards as true:
or die "Could not perform\n\t$sql\nwith data:\n\t(".join(',', @$non_autoinc_values).')';
if($return_code > 0) { # <--- for the same reason we have to be expliticly numeric here
if($autoinc_id) {
if($object_class) {
$object->dbID( $sth->{'mysql_insertid'} );
} else {
$object->{$autoinc_id} = $sth->{'mysql_insertid'};
}
}
$self->mark_stored($object, $sth->{'mysql_insertid'});
}
}
if($object_class) {
$object->adaptor($self);
}
}
$sth->finish();
......@@ -333,50 +311,46 @@ sub store {
}
sub create_new {
my $self = shift @_;
my $check_presence_in_db_first = (scalar(@_)%2)
? pop @_ # extra 'odd' parameter that would disrupt the hash integrity anyway
: 0; # do not check by default
my $object;
if( my $object_class = $self->object_class() ) {
$object = $object_class->new( -adaptor => $self, @_ );
} else {
$object = { @_ };
}
return $self->store( $object, $check_presence_in_db_first );
}
sub DESTROY { } # to simplify AUTOLOAD
sub AUTOLOAD {
our $AUTOLOAD;
if($AUTOLOAD =~ /::fetch_(all_)?by_(\w+)$/) {
my $all = $1;
my $filter_name = $2;
if($AUTOLOAD =~ /::fetch(_all)?(?:_by_(\w+?))?(?:_HASHED_FROM_(\w+?))?(?:_TO_(\w+?))?$/) {
my $all = $1;
my $filter_string = $2;
my $key_string = $3;
my $value_column = $4;
my ($self) = @_;
my $column_set = $self->column_set();
my @columns_to_fetch_by = split('_and_', $filter_name);
foreach my $column_name (@columns_to_fetch_by) {
my $filter_components = $filter_string && [ split('_and_', $filter_string) ];
foreach my $column_name ( @$filter_components ) {
unless($column_set->{$column_name}) {
die "unknown column '$column_name'";
}
}
my $key_components = $key_string && [ split('_and_', $key_string) ];
foreach my $column_name ( @$key_components ) {
unless($column_set->{$column_name}) {
die "unknown column '$column_name'";
}
}
if($value_column && !$column_set->{$value_column}) {
die "unknown column '$value_column'";
}
print "Setting up '$AUTOLOAD' method\n";
if($all) {
*$AUTOLOAD = sub { my $self = shift @_; return $self->fetch_all( join(' AND ', map { "$columns_to_fetch_by[$_]='$_[$_]'" } 0..scalar(@columns_to_fetch_by)-1) ); };
} else {
*$AUTOLOAD = sub { my $self = shift @_; my ($object) = @{ $self->fetch_all( join(' AND ', map { "$columns_to_fetch_by[$_]='$_[$_]'" } 0..scalar(@columns_to_fetch_by)-1) ) }; return $object; };
}
*$AUTOLOAD = sub {
my $self = shift @_;
return $self->fetch_all(
join(' AND ', map { "$filter_components->[$_]='$_[$_]'" } 0..scalar(@$filter_components)-1),
!$all,
$key_components,
$value_column
);
};
goto &$AUTOLOAD; # restart the new method
} elsif($AUTOLOAD =~ /::count_all_by_(\w+)$/) {
my $filter_name = $1;
......
......@@ -27,7 +27,7 @@ use strict;
use Bio::EnsEMBL::Hive::DataflowRule;
use Bio::EnsEMBL::Hive::Utils ('stringify'); # import 'stringify()'
use base ('Bio::EnsEMBL::Hive::DBSQL::BaseAdaptor');
use base ('Bio::EnsEMBL::Hive::DBSQL::ObjectAdaptor');
sub default_table_name {
......
......@@ -23,7 +23,7 @@ package Bio::EnsEMBL::Hive::DBSQL::JobMessageAdaptor;
use strict;
use base ('Bio::EnsEMBL::Hive::DBSQL::BaseAdaptor');
use base ('Bio::EnsEMBL::Hive::DBSQL::NakedTableAdaptor');
sub default_table_name {
......
......@@ -28,8 +28,27 @@ use Bio::EnsEMBL::Hive::NakedTable;
use base ('Bio::EnsEMBL::Hive::DBSQL::BaseAdaptor');
# No, you could not just use the Bio::EnsEMBL::Hive::DBSQL::BaseAdaptor instead of NakedTableAdaptor
# because AUTOLOAD will be creating class-specific methods and you don't want to clutter BaseAdaptor's namespace.
sub slicer { # take a slice of the hashref (if only we could inline in Perl!)
my ($self, $object, $fields) = @_;
return [ @$object{@$fields} ];
}
sub objectify { # pretend the hashref becomes an object (if only we could inline in Perl!)
return pop @_;
}
sub mark_stored {
my ($self, $hashref, $dbID) = @_;
if(my $autoinc_id = $self->autoinc_id()) {
$hashref->{$autoinc_id} = $dbID;
}
}
1;
=pod
=head1 NAME
Bio::EnsEMBL::Hive::DBSQL::ObjectAdaptor
=head1 SYNOPSIS
$object_adaptor = $dba->get_SpecificObjectAdaptor;
$object_adaptor = $specific_object->adaptor;
=head1 DESCRIPTION
This module defines a parent class for all specific object adaptors.
It is not supposed to be instantiated directly.
=head1 CONTACT
Please contact ehive-users@ebi.ac.uk mailing list with questions/suggestions.
=cut
package Bio::EnsEMBL::Hive::DBSQL::ObjectAdaptor;
use strict;
use base ('Bio::EnsEMBL::Hive::DBSQL::BaseAdaptor');
sub object_class {
die "Please define object_class() in your specific adaptor class to return the class name of your intended object";
}
sub slicer { # take a slice of the object (if only we could inline in Perl!)
my ($self, $object, $fields) = @_;
return [ map { $object->$_() } @$fields ];
}
sub objectify { # turn the hashref into an object (if only we could inline in Perl!)
my ($self, $hashref) = @_;
return $self->object_class()->new( -adaptor => $self, map { ('-'.uc($_) => $hashref->{$_}) } keys %$hashref );
}
sub mark_stored {
my ($self, $object, $dbID) = @_;
if($self->autoinc_id()) {
$object->dbID($dbID);
}
$object->adaptor($self);
}
sub create_new {
my $self = shift @_;
my $check_presence_in_db_first = (scalar(@_)%2)
? pop @_ # extra 'odd' parameter that would disrupt the hash integrity anyway
: 0; # do not check by default
my $object = $self->object_class()->new( -adaptor => $self, @_ );
return $self->store( $object, $check_presence_in_db_first );
}
1;
......@@ -27,7 +27,7 @@ package Bio::EnsEMBL::Hive::DBSQL::ResourceDescriptionAdaptor;
use strict;
use Bio::EnsEMBL::Hive::ResourceDescription;
use base ('Bio::EnsEMBL::Hive::DBSQL::BaseAdaptor');
use base ('Bio::EnsEMBL::Hive::DBSQL::ObjectAdaptor');
sub default_table_name {
......
......@@ -20,6 +20,7 @@ and stores the result in 'final_result' database table.
package Bio::EnsEMBL::Hive::RunnableDB::LongMult::AddTogether;
use strict;
use Bio::EnsEMBL::Hive::DBSQL::NakedTableAdaptor; # to fetch data from 'intermediate_result' table
use base ('Bio::EnsEMBL::Hive::Process');
......@@ -38,19 +39,15 @@ sub fetch_input { # fetch all the (relevant) precomputed products
my $self = shift @_;
my $a_multiplier = $self->param('a_multiplier') || die "'a_multiplier' is an obligatory parameter";
my %product_pair = ();
my $sql = "SELECT digit, result FROM intermediate_result WHERE a_multiplier = ?";
my $sth = $self->db->dbc()->prepare($sql);
$sth->execute($a_multiplier);
while (my ($digit, $result)=$sth->fetchrow_array()) {
$product_pair{$digit} = $result;
}
$sth->finish();
$product_pair{1} = $a_multiplier;
$product_pair{0} = 0;
my $adaptor = $self->db->get_NakedTableAdaptor();
$adaptor->table_name( 'intermediate_result' );
my $product_pair = $adaptor->fetch_by_a_multiplier_HASHED_FROM_digit_TO_result( $a_multiplier );
$product_pair->{1} = $a_multiplier;
$product_pair->{0} = 0;
$self->param('product_pair', \%product_pair);
$self->param('product_pair', $product_pair);
}
=head2 run
......
......@@ -207,7 +207,7 @@ sub main {
if($check_for_dead) { $queen->check_for_dead_workers($self->{'meadow'}, 1); }
if ($kill_worker_id) {
my $worker = $queen->fetch_by_worker_id($kill_worker_id);
my $worker = $queen->fetch_by_dbID($kill_worker_id);
if( $self->{'meadow'}->responsible_for_worker($worker)
and not defined($worker->cause_of_death())) {
......@@ -365,8 +365,7 @@ sub run_autonomously {
my $worker_cmd = generate_worker_cmd($self);
# pre-hash the resource_class xparams for future use:
my %rc_xparams = map { ($_->rc_id => $_->parameters) }
@{ $self->{'dba'}->get_ResourceDescriptionAdaptor->fetch_all_by_meadow_type($self->{'meadow'}->type()) };
my $rc_xparams = $self->{'dba'}->get_ResourceDescriptionAdaptor->fetch_by_meadow_type_HASHED_FROM_rc_id_TO_parameters($self->{'meadow'}->type());
my $iteration=0;
my $num_of_remaining_jobs=0;
......@@ -401,7 +400,7 @@ sub run_autonomously {
print "Submitting $this_rc_worker_count workers (rc_id=$rc_id) to ".$self->{'meadow'}->type()."\n";
$self->{'meadow'}->submit_workers($iteration, $worker_cmd, $this_rc_worker_count, $rc_id, $rc_xparams{$rc_id} || '');
$self->{'meadow'}->submit_workers($iteration, $worker_cmd, $this_rc_worker_count, $rc_id, $rc_xparams->{$rc_id} || '');
$worker_quota -= $this_rc_worker_count;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment