package DBR::Config::Trans::Enum;
use strict;
use base 'DBR::Config::Trans';
use Clone qw(clone);
use constant {
# Cache Constants
x_list => 0,
x_hmap => 1,
x_idmap => 2,
# Value Constants
v_id => 0,
v_handle => 1,
v_name => 2,
};
my %FIELDMAP;
sub moduleload{
my( $package ) = shift;
my %params = @_;
my $self = { session => $params{session} };
bless( $self, $package ); # Dummy object
my $instance = $params{instance} || return $self->_error('instance is required');
my $field_ids = $params{field_id} || return $self->_error('field_id is required');
$field_ids = [$field_ids] unless ref($field_ids) eq 'ARRAY';
my $dbrh = $instance->connect || return $self->_error("Failed to connect to ${\$instance->name}");
return $self->_error('Failed to select from enum_map') unless
my $maps = $dbrh->select(
-table => 'enum_map',
-fields => 'field_id enum_id sortval',
-where => { field_id => ['d in',@$field_ids] },
);
my @enumids = $self->_uniq( map { $_->{enum_id} } @$maps);
my $values = [];
if(@enumids){
return $self->_error('Failed to select from enum') unless
$values = $dbrh->select(
-table => 'enum',
-fields => 'enum_id handle name override_id',
-where => { enum_id => ['d in',@enumids ] },
);
}
my %VALUES_BY_ID;
foreach my $value (@$values){
my $enum_id = $value->{enum_id};
my $id = defined($value->{override_id}) ? $value->{override_id} : $enum_id;
$VALUES_BY_ID{ $enum_id } = [$id,$value->{handle},$value->{name}]; #
}
foreach my $map (sort {( $a->{sortval}||0 ) <=> ( $b->{sortval}||0 ) } @$maps){
my $enum_id = $map->{enum_id};
my $value = $VALUES_BY_ID{ $enum_id };
my $ref = $FIELDMAP{ $map->{field_id} } ||=[];
push @{$ref->[ x_list ]}, $value;
$ref->[ x_hmap ]->{ $value->[ v_handle ] } = $value; # Forward
$ref->[ x_idmap ]->{ $value->[ v_id ] } = $value; # Backward
}
return 1;
}
sub new { die "Should not get here" }
sub options{
my $self = shift;
my $opts = $FIELDMAP{ $self->{field_id} }->[ x_list ];
return [ map { bless([$_,$self->{field_id}], 'DBR::_ENUM') } @$opts ];
}
sub forward{
my $self = shift;
my $id = shift;
if (defined($id)){
return bless( [ $FIELDMAP{ $self->{field_id} }->[ x_idmap ]->{ $id }, $self->{field_id} ] , 'DBR::_ENUM');
}else{
# Looks like a null value. return a dummy object
return bless( [ ['','',''] , $self->{field_id} ] , 'DBR::_ENUM');
}
}
sub backward{
my $self = shift;
my $value = shift;
return undef unless defined($value) && length($value);
if( ref($value) eq 'DBR::_ENUM' ){ # smells like an enum object
$value = $value->handle; # swap it out for the handle, so we can make sure they didn't mix up enum objects
return $FIELDMAP{ $self->{field_id} }->[ x_hmap ]->{ $value }->[ v_id ]; # id
}
my @out;
foreach ( $self->_split($value) ){
#otherwise hit the lookup
my $id = $FIELDMAP{ $self->{field_id} }->[ x_hmap ]->{ $_ }->[ v_id ];
return () unless defined($id);
push @out, $id;
}
return @out;
}
###############################################################################################################
###############################################################################################################
###############################################################################################################
###############################################################################################################
package DBR::_ENUM;
use constant {
# Cache Constants
x_list => 0,
x_hmap => 1,
x_idmap => 2,
# Value Constants
v_id => 0,
v_handle => 1,
v_name => 2,
};
use strict;
use Carp;
use overload
# Values
'""' => sub { $_[0]->name },
# Operators
'eq' => sub { $_[0]->handle eq _strhandle($_[1]) },
'ne' => sub { $_[0]->handle ne _strhandle($_[1]) },
'nomethod' => sub {croak "Enum object: Invalid operation '$_[3]' The ways in which you can use an enum are restricted"}
;
*TO_JSON = \&chunk;
sub id { $_[0][0]->[ v_id ] }
sub handle { $_[0][0]->[ v_handle ] }
sub name { $_[0][0]->[ v_name ] }
sub chunk {return { handle => $_[0]->handle, name => $_[0]->name} }
sub field_id { $_[0][1] }
sub in{
my $self = shift;
my $hmap = $FIELDMAP{ $self->field_id }->[ x_hmap ] or die 'Unable to locate field in cache';
my $id = $self->id;
my @ids = map {
$hmap->{$_}->[ v_id ] or croak "Enum->in: Invalid value $_"
}
map {
split(/\s+/,$_)
} @_;
map { return 1 if $id eq $_ } @ids;
return 0;
}
#######################################
######### Util ####################
#######################################
sub _strhandle{
my $val = $_[1] || $_[0]; # can be OO or functional
return $val->handle if ref($val) eq __PACKAGE__;
return $val;
}
1;