Skip to content
Snippets Groups Projects
Commit c8e6e805 authored by Leo Gordon's avatar Leo Gordon
Browse files

using a new BaseAdaptor as the base class for some simpler adaptors

parent baa146d3
Branches
Tags
No related merge requests found
Showing
with 514 additions and 709 deletions
......@@ -58,10 +58,21 @@ use Bio::EnsEMBL::Utils::Exception;
=cut
sub new {
my ($class,@args) = @_;
my $self = bless {}, $class;
my $class = shift @_;
my $self = bless {}, $class;
return $self;
my ( $dbID, $adaptor, $condition_analysis_url, $ctrled_analysis_id ) =
rearrange( [ qw (DBID ADAPTOR CONDITION_ANALYSIS_URL CTRLED_ANALYSIS_ID) ], @_ );
# database persistence:
$self->dbID( $dbID ) if(defined($dbID));
$self->adaptor( $adaptor ) if(defined($adaptor));
# simple scalars:
$self->condition_analysis_url( $condition_analysis_url ) if(defined($condition_analysis_url));
$self->ctrled_analysis_id( $ctrled_analysis_id ) if(defined($ctrled_analysis_id));
return $self;
}
sub adaptor {
......
......@@ -263,7 +263,7 @@ sub dataflow_output_id {
if($target_analysis_or_table->can('dataflow')) {
my $insert_ids = $target_analysis_or_table->dataflow( $output_ids_for_this_rule );
$target_analysis_or_table->dataflow( $output_ids_for_this_rule );
} else {
......
# Perl module for Bio::EnsEMBL::Hive::DBSQL::AnalysisCtrlRuleAdaptor
#
# Date of creation: 22.03.2004
# Original Creator : Jessica Severin <jessica@ebi.ac.uk>
#
# Copyright EMBL-EBI 2004
#
# You may distribute this module under the same terms as perl itself
=pod
=head1 NAME
......@@ -15,8 +6,8 @@
=head1 SYNOPSIS
$AnalysisCtrlRuleAdaptor = $db_adaptor->get_AnalysisCtrlRuleAdaptor;
$analysisCtrlRuleAdaptor = $analysisCtrlRuleObj->adaptor;
$analysis_ctrl_rule_adaptor = $db_adaptor->get_AnalysisCtrlRuleAdaptor;
$analysis_ctrl_rule_adaptor = $analysisCtrlRuleObj->adaptor;
=head1 DESCRIPTION
......@@ -27,98 +18,32 @@
Please contact ehive-users@ebi.ac.uk mailing list with questions/suggestions.
=head1 APPENDIX
The rest of the documentation details each of the object methods.
Internal methods are usually preceded with a _
=cut
package Bio::EnsEMBL::Hive::DBSQL::AnalysisCtrlRuleAdaptor;
use strict;
use Carp;
use Bio::EnsEMBL::Hive::AnalysisCtrlRule;
use Bio::EnsEMBL::Utils::Argument;
use Bio::EnsEMBL::Utils::Exception;
use base ('Bio::EnsEMBL::DBSQL::BaseAdaptor');
=head2 fetch_all_by_ctrled_analysis_id
Arg [1] : int $id
the unique database identifier for the feature to be obtained
Example : $ctrlRuleArray = $adaptor->fetch_all_by_ctrled_analysis_id($ctrled_analysis->dbID);
Description: Returns an array reference of all the AnalysisCtrlRule objects
for the specified controled analysis.
Returntype : listref of Bio::EnsEMBL::Hive::AnalysisCtrlRule objects
Exceptions : thrown if $id is not defined
Caller : general
=cut
sub fetch_all_by_ctrled_analysis_id {
my ($self,$id) = @_;
unless(defined $id) {
throw("fetch_all_by_ctrled_analysis_id must have an id");
}
use base ('Bio::EnsEMBL::Hive::DBSQL::BaseAdaptor');
my $constraint = "r.ctrled_analysis_id = $id";
return $self->_generic_fetch($constraint);
sub default_table_name {
return 'analysis_ctrl_rule';
}
=head2 fetch_all
Arg : None
Example : my $all_rules = $ctrlRuleDBA->fetch_all();
Description: fetches all AnalysisCtrlRule objects from database
Returntype : array reference of Bio::EnsEMBL::Hive::AnalysisCtrlRule objects
Exceptions : none
Caller : general
=cut
sub fetch_all {
my $self = shift;
return $self->_generic_fetch();
sub default_insertion_method {
return 'INSERT_IGNORE';
}
=head2 store
Arg[1] : Bio::EnsEMBL::Hive::AnalysisCtrlRule object
Usage : $self->store( $rule );
Function : Stores a rule in db
Sets adaptor and dbID in AnalysisCtrlRule object
Returntype : none
=cut
sub store {
my ( $self, $rule ) = @_;
my $newly_inserted_rule = 0;
my $condition_analysis_url = $rule->condition_analysis_url;
my $ctrled_analysis_id = $rule->ctrled_analysis_id;
sub object_class {
return 'Bio::EnsEMBL::Hive::AnalysisCtrlRule';
}
my $sth = $self->prepare("INSERT IGNORE INTO analysis_ctrl_rule (condition_analysis_url, ctrled_analysis_id) VALUES(?,?)");
my $rtnCode = $sth->execute($condition_analysis_url, $ctrled_analysis_id);
if($rtnCode and ($rtnCode != 0E0)) { # 0E0 is returned when the command succeeds, but 0 rows are updated (so in case of 'INSERT IGNORE' likely a key clash)
$newly_inserted_rule = 1;
$sth->finish();
} elsif(!$rtnCode) {
die "Could not create analysis_ctrl_rule('$condition_analysis_url', '$ctrled_analysis_id')";
}
$rule->adaptor( $self );
return $newly_inserted_rule;
}
=head2 remove_by_condition_analysis_url
......@@ -156,11 +81,10 @@ sub remove_by_condition_analysis_url {
analysis will only unblock if ALL conditions are satisified.
Returntype : none
Exceptions : none
Caller : general
Caller : HiveGeneric_conf.pm and various pipeline-creating scripts
=cut
sub create_rule {
my ($self, $conditionAnalysis, $ctrledAnalysis) = @_;
......@@ -171,121 +95,8 @@ sub create_rule {
$rule->ctrled_analysis($ctrledAnalysis);
$rule->condition_analysis($conditionAnalysis);
return $self->store($rule);
}
############################
#
# INTERNAL METHODS
# (pseudo subclass methods)
#
############################
#internal method used in multiple calls above to build objects from table data
sub _tables {
my $self = shift;
return (['analysis_ctrl_rule', 'r']);
}
sub _columns {
my $self = shift;
return qw (r.ctrled_analysis_id
r.condition_analysis_url
);
}
sub _objs_from_sth {
my ($self, $sth) = @_;
my @rules = ();
my ($ctrled_analysis_id, $condition_analysis_url);
$sth->bind_columns(\$ctrled_analysis_id, \$condition_analysis_url);
while ($sth->fetch()) {
my $rule = Bio::EnsEMBL::Hive::AnalysisCtrlRule->new;
$rule->adaptor($self);
$rule->ctrled_analysis_id($ctrled_analysis_id);
$rule->condition_analysis_url($condition_analysis_url);
push @rules, $rule;
}
return \@rules;
return $self->store($rule, 1); # avoid redundancy
}
sub _default_where_clause {
my $self = shift;
return '';
}
sub _final_clause {
my $self = shift;
return '';
}
###############################################################################
#
# General access methods that could be moved
# into a superclass
#
###############################################################################
sub _generic_fetch {
my ($self, $constraint, $join) = @_;
my @tables = $self->_tables;
my $columns = join(', ', $self->_columns());
if ($join) {
foreach my $single_join (@{$join}) {
my ($tablename, $condition, $extra_columns) = @{$single_join};
if ($tablename && $condition) {
push @tables, $tablename;
if($constraint) {
$constraint .= " AND $condition";
} else {
$constraint = " $condition";
}
}
if ($extra_columns) {
$columns .= ", " . join(', ', @{$extra_columns});
}
}
}
#construct a nice table string like 'table1 t1, table2 t2'
my $tablenames = join(', ', map({ join(' ', @$_) } @tables));
my $sql = "SELECT $columns FROM $tablenames";
my $default_where = $self->_default_where_clause;
my $final_clause = $self->_final_clause;
#append a where clause if it was defined
if($constraint) {
$sql .= " WHERE $constraint ";
if($default_where) {
$sql .= " AND $default_where ";
}
} elsif($default_where) {
$sql .= " WHERE $default_where ";
}
#append additional clauses which may have been defined
$sql .= " $final_clause";
my $sth = $self->prepare($sql);
$sth->execute;
# print STDERR $sql,"\n";
return $self->_objs_from_sth($sth);
}
1;
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');
sub default_table_name {
die "Please define table_name either by setting it via table_name() method or by redefining default_table_name() in your adaptor class";
}
sub default_insertion_method {
return 'INSERT_IGNORE';
}
sub table_name {
my $self = shift @_;
if(@_) { # setter
$self->{_table_name} = shift @_;
}
return $self->{_table_name} || $self->default_table_name();
}
sub insertion_method {
my $self = shift @_;
if(@_) { # setter
$self->{_insertion_method} = shift @_;
}
return $self->{_insertion_method} || $self->default_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 @_;
if(@_) { # setter
$self->{_column_set} = shift @_;
} elsif( !defined( $self->{_column_set} ) ) {
$self->_table_info_loader();
}
return $self->{_column_set};
}
sub primary_key { # not necessarily auto-incrementing
my $self = shift @_;
if(@_) { # setter
$self->{_primary_key} = shift @_;
} elsif( !defined( $self->{_primary_key} ) ) {
$self->_table_info_loader();
}
return $self->{_primary_key};
}
sub updatable_column_list { # it's just a cashed view, you cannot set it directly
my $self = shift @_;
unless($self->{_updatable_column_list}) {
my %primary_key_set = map { $_ => 1 } @{$self->primary_key()};
my $column_set = $self->column_set();
$self->{_updatable_column_list} = [ grep { not $primary_key_set{$_} } keys %$column_set ];
}
return $self->{_updatable_column_list};
}
sub autoinc_id {
my $self = shift @_;
if(@_) { # setter
$self->{_autoinc_id} = shift @_;
} elsif( !defined( $self->{_autoinc_id} ) ) {
$self->_table_info_loader();
}
return $self->{_autoinc_id};
}
sub _table_info_loader {
my $self = shift @_;
my $dbc = $self->dbc();
my $dbname = $dbc->dbname();
my $table_name = $self->table_name();
my %column_set = ();
my @primary_key = ();
my $autoinc_id = '';
my $sql = "SELECT column_name,column_key,extra FROM information_schema.columns WHERE table_schema='$dbname' and table_name='$table_name'";
my $sth = $self->prepare($sql);
$sth->execute;
while(my ($column_name, $column_key, $extra) = $sth->fetchrow ) {
$column_set{$column_name} = 1;
if($column_key eq 'PRI') {
push @primary_key, $column_name;
if($extra eq 'auto_increment') {
$autoinc_id = $column_name;
}
}
}
$sth->finish;
$self->column_set( \%column_set );
$self->primary_key( \@primary_key );
$self->autoinc_id( $autoinc_id );
}
sub count_all {
my ($self, $constraint) = @_;
my $table_name = $self->table_name();
my $sql = "SELECT COUNT(*) FROM $table_name";
if($constraint) {
$sql .= " WHERE $constraint ";
}
print STDOUT $sql,"\n";
my $sth = $self->prepare($sql);
$sth->execute;
my ($count) = $sth->fetchrow();
$sth->finish;
return $count;
}
sub fetch_all {
my ($self, $constraint) = @_;
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";
if($constraint) {
$sql .= " WHERE $constraint ";
}
# print STDOUT $sql,"\n";
my $sth = $self->prepare($sql);
$sth->execute;
my @objects;
while(my $hashref = $sth->fetchrow_hashref) {
if($object_class) {
push @objects, $object_class->new( -adaptor => $self, map { ('-'.uc($_) => $hashref->{$_}) } keys %$hashref );
} else {
push @objects, $hashref; # faster, but only works for naked data types and lacks a link back to the adaptor
}
}
$sth->finish;
return \@objects;
}
sub primary_key_constraint {
my $self = shift @_;
my $primary_key = $self->primary_key(); # Attention: the order of primary_key columns of your call should match the order in the table definition!
if(@$primary_key) {
return join (' AND ', map { $primary_key->[$_]."='".$_[$_]."'" } (0..scalar(@$primary_key)-1));
} else {
my $table_name = $self->table_name();
die "Table '$table_name' doesn't have a primary_key";
}
}
sub fetch_by_dbID {
my $self = shift @_; # the rest in @_ should be primary_key column values
return $self->fetch_all( $self->primary_key_constraint( @_ ) );
}
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 @_;
my $table_name = $self->table_name();
my $primary_key_constraint = $self->primary_key_constraint( $self->slicer($object, $self->primary_key()) );
my $sql = "DELETE FROM $table_name WHERE $primary_key_constraint";
my $sth = $self->prepare($sql);
$sth->execute();
$sth->finish();
}
sub update { # update (some or all) non_primary columns from the primary
my $self = shift @_;
my $object = shift @_; # the rest in @_ should be the column names to be updated
my $table_name = $self->table_name();
my $primary_key_constraint = $self->primary_key_constraint( $self->slicer($object, $self->primary_key()) );
my $columns_to_update = scalar(@_) ? \@_ : $self->updatable_column_list();
my $values_to_update = $self->slicer( $object, $columns_to_update );
unless(@$columns_to_update) {
die "There are no dependent columns to update, as everything seems to belong to the primary key";
}
my $sql = "UPDATE $table_name SET ".join(', ', map { "$columns_to_update->[$_]=$values_to_update->[$_]" } (0..@$columns_to_update-1) )." WHERE $primary_key_constraint";
my $sth = $self->prepare($sql);
$sth->execute();
$sth->finish();
}
sub check_object_present_in_db { # return autoinc_id/undef if the table has autoinc_id or just 1/undef if not
my ( $self, $object ) = @_;
my $table_name = $self->table_name();
my $column_set = $self->column_set();
my $autoinc_id = $self->autoinc_id();
my $non_autoinc_columns = [ grep { $_ ne $autoinc_id } keys %$column_set ];
my $non_autoinc_values = $self->slicer( $object, $non_autoinc_columns );
my $sql = 'SELECT '.($autoinc_id or 1)." FROM $table_name WHERE ".
# we look for identical contents, so must skip the autoinc_id columns when fetching:
join(' AND ', map { my $v=$non_autoinc_values->[$_]; "$non_autoinc_columns->[$_] ".(defined($v) ? "='$v'" : 'IS NULL') } (0..@$non_autoinc_columns-1) );
my $sth = $self->prepare($sql);
$sth->execute();
my ($return_value) = $sth->fetchrow();
$sth->finish;
return $return_value;
}
sub store {
my ($self, $object_or_list, $check_presence_in_db_first) = @_;
my $objects = (ref($object_or_list) eq 'ARRAY') # ensure we get an array of objects to store
? $object_or_list
: [ $object_or_list ];
return unless(scalar(@$objects));
my $table_name = $self->table_name();
my $column_set = $self->column_set();
my $autoinc_id = $self->autoinc_id();
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 ];
# By using question marks we can insert true NULLs by setting corresponding values to undefs:
my $sql = "$insertion_method INTO $table_name (".join(', ', @$non_autoinc_columns).') VALUES ('.join(',', (('?') x scalar(@$non_autoinc_columns))).')';
my $sth; # do not prepare the statement until there is a real need
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;
}
}
} else {
$sth ||= $self->prepare( $sql ); # only prepare (once) if we get here
my $non_autoinc_values = $self->slicer( $object, $non_autoinc_columns );
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'};
}
}
}
}
if($object_class) {
$object->adaptor($self);
}
}
$sth->finish();
return $object_or_list;
}
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;
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) {
unless($column_set->{$column_name}) {
die "unknown column '$column_name'";
}
}
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; };
}
goto &$AUTOLOAD; # restart the new method
} elsif($AUTOLOAD =~ /::count_all_by_(\w+)$/) {
my $filter_name = $1;
my ($self) = @_;
my $column_set = $self->column_set();
if($column_set->{$filter_name}) {
print "Setting up '$AUTOLOAD' method\n";
*$AUTOLOAD = sub { my ($self, $filter_value) = @_; return $self->count_all("$filter_name='$filter_value'"); };
goto &$AUTOLOAD; # restart the new method
} else {
die "unknown column '$filter_name'";
}
} elsif($AUTOLOAD =~ /::update_(\w+)$/) {
my @columns_to_update = split('_and_', $1);
print "Setting up '$AUTOLOAD' method\n";
*$AUTOLOAD = sub { my ($self, $object) = @_; return $self->update($object, @columns_to_update); };
goto &$AUTOLOAD; # restart the new method
} else {
print "sub '$AUTOLOAD' not implemented";
}
}
1;
......@@ -45,18 +45,21 @@ sub get_available_adaptors {
# Core adaptors extended with Hive stuff:
'MetaContainer' => 'Bio::EnsEMBL::Hive::DBSQL::MetaContainer',
'Analysis' => 'Bio::EnsEMBL::Hive::DBSQL::AnalysisAdaptor',
# Hive adaptors:
'Queen' => 'Bio::EnsEMBL::Hive::Queen',
'AnalysisJob' => 'Bio::EnsEMBL::Hive::DBSQL::AnalysisJobAdaptor',
'AnalysisData' => 'Bio::EnsEMBL::Hive::DBSQL::AnalysisDataAdaptor',
'AnalysisStats' => 'Bio::EnsEMBL::Hive::DBSQL::AnalysisStatsAdaptor',
# "new" Hive adaptors (sharing the same fetching/storing code inherited from the BaseAdaptor class) :
'AnalysisCtrlRule' => 'Bio::EnsEMBL::Hive::DBSQL::AnalysisCtrlRuleAdaptor',
'DataflowRule' => 'Bio::EnsEMBL::Hive::DBSQL::DataflowRuleAdaptor',
'ResourceDescription' => 'Bio::EnsEMBL::Hive::DBSQL::ResourceDescriptionAdaptor',
'NakedTable' => 'Bio::EnsEMBL::Hive::DBSQL::NakedTableAdaptor',
'JobMessage' => 'Bio::EnsEMBL::Hive::DBSQL::JobMessageAdaptor',
'NakedTable' => 'Bio::EnsEMBL::Hive::DBSQL::NakedTableAdaptor',
# "old" Hive adaptors (having their own fetching/storing code) :
'Queen' => 'Bio::EnsEMBL::Hive::Queen',
'AnalysisJob' => 'Bio::EnsEMBL::Hive::DBSQL::AnalysisJobAdaptor',
'AnalysisStats' => 'Bio::EnsEMBL::Hive::DBSQL::AnalysisStatsAdaptor',
'AnalysisData' => 'Bio::EnsEMBL::Hive::DBSQL::AnalysisDataAdaptor',
);
return (\%pairs);
return \%pairs;
}
1;
# Perl module for Bio::EnsEMBL::Hive::DBSQL::DataflowRuleAdaptor
#
# Date of creation: 22.03.2004
# Original Creator : Jessica Severin <jessica@ebi.ac.uk>
#
# Copyright EMBL-EBI 2004
#
# You may distribute this module under the same terms as perl itself
=pod
=head1 NAME
......@@ -15,8 +6,8 @@
=head1 SYNOPSIS
$dataflowRuleAdaptor = $db_adaptor->get_DataflowRuleAdaptor;
$dataflowRuleAdaptor = $dataflowRuleObj->adaptor;
$dataflow_rule_adaptor = $db_adaptor->get_DataflowRuleAdaptor;
$dataflow_rule_adaptor = $dataflowRuleObj->adaptor;
=head1 DESCRIPTION
......@@ -27,24 +18,34 @@
Please contact ehive-users@ebi.ac.uk mailing list with questions/suggestions.
=head1 APPENDIX
The rest of the documentation details each of the object methods.
Internal methods are usually preceded with a _
=cut
package Bio::EnsEMBL::Hive::DBSQL::DataflowRuleAdaptor;
use strict;
use Carp;
use Bio::EnsEMBL::Hive::DataflowRule;
use Bio::EnsEMBL::Utils::Argument;
use Bio::EnsEMBL::Utils::Exception;
use Bio::EnsEMBL::Hive::Utils ('stringify'); # import 'stringify()'
use base ('Bio::EnsEMBL::DBSQL::BaseAdaptor');
use base ('Bio::EnsEMBL::Hive::DBSQL::BaseAdaptor');
sub default_table_name {
return 'dataflow_rule';
}
sub default_insertion_method {
return 'INSERT';
}
sub object_class {
return 'Bio::EnsEMBL::Hive::DataflowRule';
}
=head2 branch_name_2_code
......@@ -88,105 +89,9 @@ sub fetch_all_by_from_analysis_id_and_branch_code {
my $branch_code = $self->branch_name_2_code($branch_name_or_code);
my $constraint = "r.from_analysis_id=${analysis_id} AND r.branch_code=${branch_code}";
return $self->_generic_fetch($constraint);
}
sub check_rule_exists_in_db {
my ( $self, $rule ) = @_;
my $from_analysis_id = $rule->from_analysis_id;
my $to_analysis_url = $rule->to_analysis_url;
my $branch_code = $rule->branch_code;
my $input_id_template = ref($rule->input_id_template) ? stringify($rule->input_id_template) : $rule->input_id_template;
my $sql = qq{
SELECT dataflow_rule_id
FROM dataflow_rule
WHERE from_analysis_id='$from_analysis_id'
AND to_analysis_url='$to_analysis_url'
AND branch_code='$branch_code'
AND input_id_template
} . ( defined($input_id_template) ? "='$input_id_template'" : "IS NULL" );
my $sth = $self->prepare($sql);
$sth->execute();
if(my ($dataflow_rule_id) = $sth->fetchrow()) {
$sth->finish;
return $dataflow_rule_id;
} else {
$sth->finish;
return 0;
}
}
=head2 store
my $constraint = "from_analysis_id=${analysis_id} AND branch_code=${branch_code}";
Usage : $self->store( $rule );
Function: Stores a rule in db
Sets adaptor and dbID in DataflowRule
Returns : -
Args : Bio::EnsEMBL::Hive::DataflowRule
=cut
sub store {
my ( $self, $rule ) = @_;
my $dataflow_rule_id;
if($dataflow_rule_id = $self->check_rule_exists_in_db($rule)) {
$rule->dbID($dataflow_rule_id);
$rule->adaptor( $self );
return 0;
} else {
my $from_analysis_id = $rule->from_analysis_id;
my $to_analysis_url = $rule->to_analysis_url;
my $branch_code = $rule->branch_code;
my $input_id_template = ref($rule->input_id_template) ? stringify($rule->input_id_template) : $rule->input_id_template;
my $sth = $self->prepare("INSERT INTO dataflow_rule (from_analysis_id, to_analysis_url, branch_code, input_id_template) VALUES (?,?,?,?)");
my $rtnCode = $sth->execute($from_analysis_id, $to_analysis_url, $branch_code, $input_id_template);
if($rtnCode and ($rtnCode != 0E0)) { # we managed to insert a new row (0E0 would indicate success when no rows were inserted)
$dataflow_rule_id = $sth->{'mysql_insertid'};
$sth->finish();
$rule->dbID($dataflow_rule_id);
$rule->adaptor( $self );
return 1;
} else {
die "Could not create a dataflow_rule('$from_analysis_id', '$to_analysis_url', '$branch_code', '$input_id_template')";
}
}
}
=head2 remove
Title : remove
Usage : $self->remove( $rule );
Function: removes given object from database.
Returns : -
Args : Bio::EnsEMBL::Hive::DataflowRule which must be persistent with a valid dbID
=cut
sub remove {
my ( $self, $rule ) = @_;
my $dbID = $rule->dbID;
if( !defined $dbID ) {
throw( "DataflowRuleAdaptor->remove called with non persistent DataflowRule" );
}
my $sth = $self->prepare("DELETE FROM dataflow_rule WHERE dataflow_rule_id = $dbID");
$sth->execute;
return $self->fetch_all($constraint);
}
......@@ -216,180 +121,12 @@ sub create_rule {
: ( -to_analysis_url => $to_analysis_or_url ),
-branch_code => $self->branch_name_2_code($branch_name_or_code),
-input_id_template => $input_id_template,
-input_id_template => (ref($input_id_template) ? stringify($input_id_template) : $input_id_template),
);
return $self->store($rule);
return $self->store($rule, 1); # avoid redundancy
}
############################
#
# INTERNAL METHODS
# (pseudo subclass methods)
#
############################
#internal method used in multiple calls above to build objects from table data
sub _tables {
my $self = shift;
return (['dataflow_rule', 'r']);
}
sub _columns {
my $self = shift;
return qw (r.dataflow_rule_id
r.from_analysis_id
r.to_analysis_url
r.branch_code
r.input_id_template
);
}
sub _objs_from_sth {
my ($self, $sth) = @_;
my @rules = ();
my ($dataflow_rule_id, $from_analysis_id, $to_analysis_url, $branch_code, $input_id_template);
$sth->bind_columns(\$dataflow_rule_id, \$from_analysis_id, \$to_analysis_url, \$branch_code, \$input_id_template);
while ($sth->fetch()) {
my $rule = Bio::EnsEMBL::Hive::DataflowRule->new(
-dbID => $dataflow_rule_id,
-adaptor => $self,
-from_analysis_id => $from_analysis_id,
-to_analysis_url => $to_analysis_url,
-branch_code => $branch_code,
-input_id_template => $input_id_template,
);
push @rules, $rule;
}
return \@rules;
}
sub _default_where_clause {
my $self = shift;
return '';
}
sub _final_clause {
my $self = shift;
return '';
}
###############################################################################
#
# General access methods that could be moved
# into a superclass
#
###############################################################################
=head2 fetch_by_dbID
Arg [1] : int $id
the unique database identifier for the feature to be obtained
Example : $feat = $adaptor->fetch_by_dbID(1234);
Description: Returns the Member created from the database defined by the
the id $id.
Returntype : Bio::EnsEMBL::Hive::DataflowRule
Exceptions : thrown if $id is not defined
Caller : general
=cut
sub fetch_by_dbID {
my ($self,$id) = @_;
unless(defined $id) {
throw("fetch_by_dbID must have an id");
}
my @tabs = $self->_tables;
my ($name, $syn) = @{$tabs[0]};
#construct a constraint like 't1.table1_id = 1'
my $constraint = "${syn}.${name}_id = $id";
#return first element of _generic_fetch list
my ($obj) = @{$self->_generic_fetch($constraint)};
return $obj;
}
=head2 fetch_all
Arg : None
Example :
Description:
Returntype :
Exceptions :
Caller :
=cut
sub fetch_all {
my $self = shift;
return $self->_generic_fetch();
}
sub _generic_fetch {
my ($self, $constraint, $join) = @_;
my @tables = $self->_tables;
my $columns = join(', ', $self->_columns());
if ($join) {
foreach my $single_join (@{$join}) {
my ($tablename, $condition, $extra_columns) = @{$single_join};
if ($tablename && $condition) {
push @tables, $tablename;
if($constraint) {
$constraint .= " AND $condition";
} else {
$constraint = " $condition";
}
}
if ($extra_columns) {
$columns .= ", " . join(', ', @{$extra_columns});
}
}
}
#construct a nice table string like 'table1 t1, table2 t2'
my $tablenames = join(', ', map({ join(' ', @$_) } @tables));
my $sql = "SELECT $columns FROM $tablenames";
my $default_where = $self->_default_where_clause;
my $final_clause = $self->_final_clause;
#append a where clause if it was defined
if($constraint) {
$sql .= " WHERE $constraint ";
if($default_where) {
$sql .= " AND $default_where ";
}
} elsif($default_where) {
$sql .= " WHERE $default_where ";
}
#append additional clauses which may have been defined
$sql .= " $final_clause";
my $sth = $self->prepare($sql);
$sth->execute;
# print STDERR $sql,"\n";
return $self->_objs_from_sth($sth);
}
1;
......@@ -10,7 +10,7 @@
=head1 DESCRIPTION
This is currently an "objectless" adaptor that simply helps to store messages thrown by jobs into job_message table.
This is currently an "objectless" adaptor that helps to store either warning-messages or die-messages generated by jobs
=head1 CONTACT
......@@ -23,16 +23,24 @@ package Bio::EnsEMBL::Hive::DBSQL::JobMessageAdaptor;
use strict;
use base ('Bio::EnsEMBL::DBSQL::BaseAdaptor');
use base ('Bio::EnsEMBL::Hive::DBSQL::BaseAdaptor');
sub default_table_name {
return 'job_message';
}
sub register_message {
my ($self, $job_id, $msg, $is_error) = @_;
chomp $msg; # we don't want that last "\n" in the database
my $table_name = $self->table_name();
# (the timestamp 'moment' column will be set automatically)
my $sql = qq{
REPLACE INTO job_message (job_id, worker_id, analysis_id, retry_count, status, msg, is_error)
REPLACE INTO $table_name (job_id, worker_id, analysis_id, retry_count, status, msg, is_error)
SELECT job_id, worker_id, analysis_id, retry_count, status, ?, ?
FROM job WHERE job_id=?
};
......
......@@ -7,14 +7,12 @@
=head1 SYNOPSIS
$naked_table_adaptor = $dba->get_NakedTableAdaptor;
$naked_table_adaptor = $naked_table->adaptor;
=head1 DESCRIPTION
This module together with its data container are used to enable dataflow into arbitrary tables (rather than just job).
NakedTable objects know *where* to dataflow, and NakedTableAdaptor knows *how* to dataflow.
This module together with its data container are used to enable dataflow into arbitrary tables (rather than just 'job' table).
Due to the implementation of EnsEMBL Registry code, NakedTable objects know *where* to dataflow, and NakedTableAdaptor knows *how* to dataflow.
=head1 CONTACT
......@@ -28,43 +26,10 @@ package Bio::EnsEMBL::Hive::DBSQL::NakedTableAdaptor;
use strict;
use Bio::EnsEMBL::Hive::NakedTable;
use base ('Bio::EnsEMBL::DBSQL::BaseAdaptor');
sub create_new {
my $self = shift @_;
return Bio::EnsEMBL::Hive::NakedTable->new(@_, -ADAPTOR => $self);
}
sub dataflow {
my ( $self, $naked_table, $output_ids ) = @_;
return unless(@$output_ids);
my $table_name = $naked_table->table_name();
my $insertion_method = uc( $naked_table->insertion_method() ); # INSERT, INSERT_IGNORE or REPLACE
$insertion_method =~ s/_/ /g;
# NB: here we assume all hashes will have the same keys (and also the same order):
my @column_names = keys %{$output_ids->[0]};
# By using question marks you can insert true NULLs by setting corresponding values to undefs:
my $sql = "$insertion_method INTO $table_name (".join(', ', @column_names).') VALUES ('.join(',', (('?') x scalar(@column_names))).')';
my $sth = $self->prepare( $sql );
my @insert_ids = ();
foreach my $data_hash (@$output_ids) {
$sth->execute( values %$data_hash ); # Perl manual promises that the order of "keys" will be the same as the order of "values", so no need to sort.
push @insert_ids, $sth->{'mysql_insertid'}; # capture it just in case
}
$sth->finish();
use base ('Bio::EnsEMBL::Hive::DBSQL::BaseAdaptor');
return \@insert_ids;
}
# 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.
1;
......@@ -27,169 +27,21 @@ package Bio::EnsEMBL::Hive::DBSQL::ResourceDescriptionAdaptor;
use strict;
use Bio::EnsEMBL::Hive::ResourceDescription;
use base ('Bio::EnsEMBL::DBSQL::BaseAdaptor');
use base ('Bio::EnsEMBL::Hive::DBSQL::BaseAdaptor');
sub fetch_by_rcid_meadowtype {
my ($self, $rc_id, $meadow_type) = @_;
my $constraint = "rd.rc_id = $rc_id AND rd.meadow_type = '$meadow_type'";
my ($rd) = @{ $self->_generic_fetch($constraint) };
return $rd; # returns one object or undef
}
sub fetch_all_by_meadowtype {
my ($self, $meadow_type) = @_;
my $constraint = "rd.meadow_type = '$meadow_type'";
return $self->_generic_fetch($constraint); # returns an arrayref
}
sub store {
my ( $self, $rd ) = @_;
my $sth = $self->prepare( q{REPLACE INTO resource_description (rc_id, meadow_type, parameters, description) VALUES (?,?,?,?) } );
$sth->execute($rd->rc_id, $rd->meadow_type, $rd->parameters, $rd->description);
$sth->finish();
return $rd;
}
sub remove {
my ( $self, $rd ) = @_;
my $sth = $self->prepare( q{DELETE FROM resource_description WHERE rc_id = ? AND meadow_type = ?} );
$sth->execute($rd->rc_id, $rd->meadow_type);
$sth->finish();
sub default_table_name {
return 'resource_description';
}
sub create_new {
my $self = shift @_;
my $rd = Bio::EnsEMBL::Hive::ResourceDescription->new(@_, -ADAPTOR => $self);
return $self->store($rd);
sub default_insertion_method {
return 'REPLACE';
}
############################
#
# INTERNAL METHODS
# (pseudo subclass methods)
#
############################
#internal method used in multiple calls above to build objects from table data
sub _tables {
my $self = shift;
return (['resource_description', 'rd']);
}
sub _columns {
my $self = shift;
return qw (rd.rc_id
rd.meadow_type
rd.parameters
rd.description
);
}
sub _objs_from_sth {
my ($self, $sth) = @_;
my @rds = ();
while(my ($rc_id, $meadow_type, $parameters, $description) = $sth->fetchrow_array) {
my $rd = Bio::EnsEMBL::Hive::ResourceDescription->new(
-ADAPTOR => $self,
-RC_ID => $rc_id,
-MEADOW_TYPE => $meadow_type,
-PARAMETERS => $parameters,
-DESCRIPTION => $description,
);
push @rds, $rd;
}
return \@rds;
}
sub _default_where_clause {
my $self = shift;
return '';
}
sub _final_clause {
my $self = shift;
return '';
}
###############################################################################
#
# General access methods that could be moved
# into a superclass
#
###############################################################################
sub fetch_all {
my $self = shift;
return $self->_generic_fetch();
}
sub _generic_fetch {
my ($self, $constraint, $join) = @_;
my @tables = $self->_tables;
my $columns = join(', ', $self->_columns());
if ($join) {
foreach my $single_join (@{$join}) {
my ($tablename, $condition, $extra_columns) = @{$single_join};
if ($tablename && $condition) {
push @tables, $tablename;
if($constraint) {
$constraint .= " AND $condition";
} else {
$constraint = " $condition";
}
}
if ($extra_columns) {
$columns .= ", " . join(', ', @{$extra_columns});
}
}
}
#construct a nice table string like 'table1 t1, table2 t2'
my $tablenames = join(', ', map({ join(' ', @$_) } @tables));
my $sql = "SELECT $columns FROM $tablenames";
my $default_where = $self->_default_where_clause;
my $final_clause = $self->_final_clause;
#append a where clause if it was defined
if($constraint) {
$sql .= " WHERE $constraint ";
if($default_where) {
$sql .= " AND $default_where ";
}
} elsif($default_where) {
$sql .= " WHERE $default_where ";
}
#append additional clauses which may have been defined
$sql .= " $final_clause";
my $sth = $self->prepare($sql);
$sth->execute;
# print STDERR $sql,"\n";
return $self->_objs_from_sth($sth);
sub object_class {
return 'Bio::EnsEMBL::Hive::ResourceDescription';
}
1;
......
......@@ -79,7 +79,14 @@ sub url {
sub dataflow {
my ( $self, $output_ids ) = @_;
return $self->adaptor->dataflow($self, $output_ids);
# we have to do this the ugly way
# because Registry code currently prevents us from passing arguments to adaptors' new() methods
# (and by caching guarantees there is only one instance of each adaptor per DBAdaptor)
my $adaptor = $self->adaptor();
$adaptor->table_name( $self->table_name() );
$adaptor->insertion_method( $self->insertion_method() );
$adaptor->store( $output_ids );
}
......
......@@ -345,8 +345,8 @@ sub run {
my $analysis_adaptor = $hive_dba->get_AnalysisAdaptor;
foreach my $aha (@{$self->pipeline_analyses}) {
my ($logic_name, $module, $parameters_hash, $input_ids, $program_file, $blocked, $batch_size, $hive_capacity, $failed_job_tolerance, $can_be_empty, $rc_id) =
rearrange([qw(logic_name module parameters input_ids program_file blocked batch_size hive_capacity failed_job_tolerance can_be_empty rc_id)], %$aha);
my ($logic_name, $module, $parameters_hash, $input_ids, $program_file, $blocked, $batch_size, $hive_capacity, $failed_job_tolerance, $max_retry_count, $can_be_empty, $rc_id) =
rearrange([qw(logic_name module parameters input_ids program_file blocked batch_size hive_capacity failed_job_tolerance max_retry_count can_be_empty rc_id)], %$aha);
$parameters_hash ||= {};
$input_ids ||= [];
......@@ -382,6 +382,7 @@ sub run {
$stats->batch_size( $batch_size ) if(defined($batch_size));
$stats->hive_capacity( $hive_capacity ) if(defined($hive_capacity));
$stats->failed_job_tolerance( $failed_job_tolerance ) if(defined($failed_job_tolerance));
$stats->max_retry_count( $max_retry_count ) if(defined($max_retry_count));
$stats->rc_id( $rc_id ) if(defined($rc_id));
$stats->can_be_empty( $can_be_empty ) if(defined($can_be_empty));
$stats->status($blocked ? 'BLOCKED' : 'READY'); # (some analyses will be waiting for human intervention in blocked state)
......@@ -419,10 +420,9 @@ sub run {
foreach my $condition_url (@$wait_for) {
if(my $condition_analysis = $analysis_adaptor->fetch_by_logic_name_or_url($condition_url)) {
my $new_cfr = $ctrl_rule_adaptor->create_rule( $condition_analysis, $analysis);
my $cfr_action = $new_cfr ? 'Created a new' : 'Found an existing';
$ctrl_rule_adaptor->create_rule( $condition_analysis, $analysis);
warn "$cfr_action Control rule: $condition_url -| $logic_name\n";
warn "Control rule: $condition_url -| $logic_name\n";
} else {
die "Could not fetch analysis '$condition_url' to create a control rule";
}
......@@ -442,10 +442,9 @@ sub run {
my $heir_analysis = $analysis_adaptor->fetch_by_logic_name_or_url($heir_url);
my $new_dfr = $dataflow_rule_adaptor->create_rule( $analysis, $heir_analysis || $heir_url, $branch_name_or_code, $input_id_template);
my $dfr_action = $new_dfr ? 'Created a new' : 'Found an existing';
$dataflow_rule_adaptor->create_rule( $analysis, $heir_analysis || $heir_url, $branch_name_or_code, $input_id_template);
warn "$dfr_action DataFlow rule: [$branch_name_or_code] $logic_name -> $heir_url"
warn "DataFlow rule: [$branch_name_or_code] $logic_name -> $heir_url"
.($input_id_template ? ' WITH TEMPLATE: '.stringify($input_id_template) : '')."\n";
}
}
......
......@@ -84,6 +84,8 @@ sub write_output { # nothing to write out, but some dataflow to perform:
# "fan out" into branch#2 first
$self->dataflow_output_id($output_ids, 2);
$self->warning(scalar(@$output_ids).' multiplication jobs have been created'); # warning messages get recorded into 'job_message' table
# then flow into the MAIN branch funnel; input_id would flow into MAIN branch by default anyway, but we request it here explicitly:
$self->dataflow_output_id($self->input_id, 'MAIN');
}
......
......@@ -48,6 +48,7 @@ use Bio::EnsEMBL::Hive::Extensions;
use Bio::EnsEMBL::DBSQL::AnalysisAdaptor;
use Bio::EnsEMBL::DBSQL::DBAdaptor;
use Bio::EnsEMBL::Hive::DBSQL::DBAdaptor;
use Bio::EnsEMBL::Hive::NakedTable;
#use Data::Dumper;
......@@ -112,7 +113,11 @@ sub fetch {
} else {
return $dba->get_NakedTableAdaptor->create_new(-table_name => $table_name, $tparam_value ? (-insertion_method => $tparam_value) : () );
return Bio::EnsEMBL::Hive::NakedTable->new(
-adaptor => $dba->get_NakedTableAdaptor,
-table_name => $table_name,
$tparam_value ? (-insertion_method => $tparam_value) : ()
);
}
}
return;
......
......@@ -366,7 +366,7 @@ sub run_autonomously {
# pre-hash the resource_class xparams for future use:
my %rc_xparams = map { ($_->rc_id => $_->parameters) }
@{ $self->{'dba'}->get_ResourceDescriptionAdaptor->fetch_all_by_meadowtype($self->{'meadow'}->type()) };
@{ $self->{'dba'}->get_ResourceDescriptionAdaptor->fetch_all_by_meadow_type($self->{'meadow'}->type()) };
my $iteration=0;
my $num_of_remaining_jobs=0;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment