Raw content of BioMart::Configuration::ValueFilter
# $Id: ValueFilter.pm,v 1.3 2008/04/09 12:52:33 syed Exp $
#
# BioMart module for BioMart::Configuration::ValueFilter
#
# You may distribute this module under the same terms as perl itself
# POD documentation - main docs before the code
=head1 NAME
BioMart::Configuration::ValueFilter
=head1 SYNOPSIS
A Filter which represents one or more 'x op value' clauses in a
where clause, eg x = y, chr > 3, etc.
=head1 DESCRIPTION
A BioMart::Filter implementation that links represents one or more
'name' 'operation' 'value' where clauses connected by OR, where
value is taken from a particular row in the Table. The Table
for a ValueFilter should consist of only one column.
=head1 AUTHOR - Arek Kasprzyk, Syed Haider, Darin London, Damian Smedley
=head1 CONTACT
This module is part of the BioMart project http://www.biomart.org
Questions can be posted to the mart-dev mailing list:
mart-dev@ebi.ac.uk
=head1 METHODS
=cut
package BioMart::Configuration::ValueFilter;
# inherits from FilterBase, implements _toSQL
use strict;
use warnings;
use Digest::MD5;
use base qw(BioMart::Configuration::BaseFilter);
=head2 _new
Usage : see Usage for BioMart::Configuration::BaseFilter.
Description: creates a new ValueFilter object which becomes associated
with a single Attribute and AttributeTable (or ResultTable)
object and an operation specifier. The Table is assumed to
consist of only one column of data.
Returntype : BioMart::Configuration::ValueFilter
Exceptions : none
Caller : general
=cut
sub _new {
my ($self, @param) = @_;
$self->SUPER::_new(@param);
$self->attr('attribute', undef);
$self->attr('attribute_table', undef);
$self->attr('operation', undef);
$self->attr('otherFilters', undef);
$self->attr('regexp', undef);
$self->attr('defaultValue', undef);
$self->attr('sql', undef);
}
sub _init {
my ($self, @param) = @_;
$self->SUPER::_init(@param);
my $proto = shift @param;
# if the prototype table is set, take its reference
# as you will not want to change the underlying data
# most of the time FilterList objects will be copied
# before their tables are set
$self->attr('attribute_table', $proto->getTable);
$self->attr('attribute', $proto->attribute);
$self->attr('operation', $proto->operation);
$self->attr('otherFilters', $proto->otherFilters);
$self->attr('regexp', $proto->regexp);
$self->attr('defaultValue', $proto->defaultValue);
$self->attr('sql', undef);
}
# interface implementation
sub _toSQL {
# goes through each row of the table, adds 'OR' in between
my ($self,$oracle) = @_;
my $sql = $self->get('sql');
if ($sql){
return $sql;
}
else{
$sql = '';
}
my $or = '';
my @values;
my $attribute_table = $self->get('attribute_table');
my $attribute = $self->get('attribute');
my $operation = $self->get('operation');
my $temp; # holds a copy of a value for apostrohe substitution
# may need to replace with an IN list for large tables
# but can only do if not part of a FilterList
# loop over rows rather than fetching by nextRow so querys can
# potentiall be reexecuted
my $rows = $attribute_table->getRows();
foreach my $row (@{$rows}){
#while (my $row = $attribute_table->nextRow()){
next unless (defined($$row[0]));#avoid NULL entries
$temp = $$row[0];
$temp =~ s/'/''/; # substitute a ' with '' so it works on all platforms PG, ORACLE, MYSQL
if ($operation eq '='){
#push @values, $$row[0];
push @values, $temp;
}
else{
$sql .= $or.$attribute->toSQL.' '.$operation.' \''.$temp.'\'';
$or = ' OR ';
}
}
if (!$sql && @values > 0){#need to generate an IN list
if (@values > 1){
if ($oracle){
#will hold stringified sublists
my @in_lists;
#remove duplicates from @values for performance reasons
my %saw;
my @values = grep (!$saw{$_}++, @values);
#quote each value
@values = map{ "'".$_."'" } @values;
#create sublists of 1000 or less elements using 'splice'
while (@values) {
my @sublist = grep{ $_ } splice (@values, 0, 999);
push @in_lists, join(",",@sublist);
}
#now, create multiple IN clauses and join them together
@in_lists = map { " IN(".$_.")\n" } @in_lists;
$sql = $attribute->toSQL.join( "OR ".$attribute->toSQL,
@in_lists );
}
else{
$sql = $attribute->toSQL." IN('";
$sql .= join("','", grep { $_ } @values);
$sql .= "')";
}
}
else{
$sql .= $attribute->toSQL.' '.$operation.' \''.$values[0].'\'';
}
}
$sql = '('.$sql.')' if ($sql);#needs incase contains ORs and followed
# by an AND
$self->set('sql',$sql);
return $sql;
}
# public methods
=head2 attribute
Usage : my $att = $filt->attribute; $filt->attribute($att);
Description: get/set method for the BioMart::Configuration::Attribute
object for this BooleanFilter
This object represents the implementation specific location
of a data point on which to apply the filter.
Returntype : BioMart::Configuration::Attribute object
Exceptions : none
Caller : caller
=cut
sub attribute {
# stores attribute
my ($self, $attribute) = @_;
if ($attribute){
$self->set('attribute', $attribute);
$self->set('sql',undef);
}
return $self->get('attribute');
}
=head2 table
Usage :
Description: returns the table name associated with this filter;
Returntype : String table name
Exceptions : none
Caller : caller
=cut
sub table {
my $self = shift;
my $attribute = $self->get('attribute');
return $attribute->table;
}
=head2 operation
Usage : my $operation = $filt->operation; $filt->operation($op);
Description: get/set the operation to associate with the value filter
Returntype : scalar $op
Exceptions : none
Caller : caller
=cut
sub operation {
my ($self,$operation) = @_;
if ($operation) {
$self->set('operation',$operation);
$self->set('sql',undef);
}
return $self->get('operation');
}
=head2 otherFilters
Usage : my $otherFilters = $filt->otherFilters;
$filt->otherFilters($op);
Description: get/set the other filters to associate with the value filter
Returntype : scalar $otherFilters
Exceptions : none
Caller : caller
=cut
sub otherFilters {
my ($self,$otherFilters) = @_;
if ($otherFilters) {
$self->set('otherFilters',$otherFilters);
}
return $self->get('otherFilters');
}
=head2 regexp
Usage : my $regexp = $filt->regexp; $filt->regexp($op);
Description: get/set the regexp to associate with the value filter
Returntype : scalar $regexp
Exceptions : none
Caller : caller
=cut
sub regexp {
my ($self,$regexp) = @_;
if ($regexp) {
$self->set('regexp',$regexp);
}
return $self->get('regexp');
}
=head2 defaultValue
Usage : my $def = $filt->defaultValue; $filt->defaultValue($op);
Description: get/set the defaultValue to associate with the value filter
Returntype : scalar $defaultValue
Exceptions : none
Caller : caller
=cut
sub defaultValue {
my ($self,$defaultValue) = @_;
if ($defaultValue) {
$self->set('defaultValue',$defaultValue);
}
return $self->get('defaultValue');
}
=head2 setTable
Usage : set a BioMart::AttributeTable as the table
$vfilt->setTable($attTable);
set a BioMart::ResultTable as the table
$vfilt->setTable($rTable);
Description: stores a BioMart::AttributeTable or BioMart::ResultTable
object as the table to manipulate for toSQL.
Returntype : none
Exceptions : none
Caller : caller
=cut
sub setTable {
my ($self,$attribute_table) = @_;
$self->set('attribute_table',$attribute_table);
$self->set('sql',undef);
}
=head2 getTable
Usage : my $table = $vfilt->getTable;
Description : get the BioMart::AttributeTable or BioMart::ResultTable
object holding the data for this FilterList.
Returntype : may be either a BioMart::AttributeTable, or a
BioMart::ResultTable.
ResultTable objects can be manipulated as
read-only AttributeTable objects.
This is intended to be used by a BioMart::DatasetI
implementation to override the default toSQL method.
Exceptions : none
Caller : caller
=cut
sub getTable {
my $self = shift;
return $self->get('attribute_table');
}
sub _hashCode {
my $self = shift;
my $digest = Digest::MD5->new;
$digest->add($self->SUPER::_hashCode);
$digest->add($self->get('attribute')->hashCode) if ($self->get('attribute'));
$digest->add($self->get('attribute_table')->hashCode)
if ($self->get('attribute_table'));
$digest->add($self->get('operation')) if ($self->get('operation'));
return $digest->hexdigest;
}
1;