package DBIx::Custom::Mapper; use Object::Simple -base; use DBIx::Custom::NotExists; use Carp 'croak'; use DBIx::Custom::Util '_subname'; # Carp trust relationship push @DBIx::Custom::CARP_NOT, __PACKAGE__; has [qw/param/], condition => sub { sub { defined $_[0] && length $_[0] } }, pass => sub { [] }; sub map { my ($self, %rule) = @_; my $param = $self->param; $rule{$_} = $rule{$_} for @{$self->pass}; # Mapping my $new_param = {}; foreach my $key (keys %rule) { my $value_cb; my $condition; my $new_key; # Get mapping information $rule{$key} = [$key, $rule{$key}] if ref $rule{$key} eq 'CODE'; if (ref $rule{$key} eq 'ARRAY') { foreach my $some (@{$rule{$key}}) { $new_key = $some unless ref $some; $condition = $some->{condition} if ref $some eq 'HASH'; $value_cb = $some if ref $some eq 'CODE'; } } elsif (defined $rule{$key}) { $new_key = $rule{$key}; } else { $new_key = $key; } $value_cb ||= sub { $_[0] }; $condition ||= $self->condition; $condition = $self->_condition_to_sub($condition); # Map parameter my $value; if (ref $condition eq 'CODE') { if (ref $param->{$key} eq 'ARRAY') { $new_param->{$new_key} = []; for (my $i = 0; $i < @{$param->{$key}}; $i++) { $new_param->{$new_key}->[$i] = $condition->($param->{$key}->[$i]) ? $param->{$key}->[$i] : DBIx::Custom::NotExists->singleton; } } else { $new_param->{$new_key} = $value_cb->($param->{$key}) if $condition->($param->{$key}); } } elsif ($condition eq 'exists') { if (ref $param->{$key} eq 'ARRAY') { $new_param->{$new_key} = []; for (my $i = 0; $i < @{$param->{$key}}; $i++) { $new_param->{$new_key}->[$i] = exists $param->{$key}->[$i] ? $param->{$key}->[$i] : DBIx::Custom::NotExists->singleton; } } else { $new_param->{$new_key} = $value_cb->($param->{$key}) if exists $param->{$key}; } } else { croak qq/Condition must be code reference or "exists" / . _subname } } return $new_param; } sub new { my $self = shift->SUPER::new(@_); # Check attribute names my @attrs = keys %$self; foreach my $attr (@attrs) { croak qq{"$attr" is invalid attribute name (} . _subname . ")" unless $self->can($attr); } return $self; } sub _condition_to_sub { my ($self, $if) = @_; $if = $if eq 'exists' ? $if : $if eq 'defined' ? sub { defined $_[0] } : $if eq 'length' ? sub { defined $_[0] && length $_[0] } : ref $if eq 'CODE' ? $if : undef; croak "You can must specify right value to C " . _subname unless $if; return $if; } 1; =head1 NAME DBIx::Custom::Mapper - Mapper of parameter EXPERIMENTAL =head1 SYNOPSYS my $mapper = $dbi->mapper(param => $param); my $new_param = $mapper->map( title => 'book.title', # Key author => sub { '%' . $_[0] . '%'} # Value price => ['book.price' => sub { '%' . $_[0] . '%' }], # Key and value ); =head1 ATTRIBUTES =head2 C my $param = $mapper->param; $mapper = $mapper->param({title => 'Perl', author => 'Ken'}); Parameter. =head2 C my $pass = $mapper->pass; $mapper = $mapper->pass([qw/title author/]); the key and value is copied without change when C method is executed. =head2 C my $condition = $mapper->condition; $mapper = $mapper->condition('exists'); Mapping condtion, default to C. You can set the following values to C. =over 4 =item * C condition => 'exists' If key exists, key and value is mapped. =item * C condition => 'defined'; If value is defined, key and value is mapped. =item * C condition => 'length'; If value is defined and has length, key and value is mapped. =item * C condition => sub { defined $_[0] } You can set code reference to C. The subroutine return true, key and value is mapped. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 C my $new_param = $mapper->map( price => 'book.price', # Key title => sub { '%' . $_[0] . '%'}, # Value author => ['book.author', sub { '%' . $_[0] . '%'}] # Key and value ); Map C's key and value and return new parameter. For example, if C is set to { price => 1900, title => 'Perl', author => 'Ken', issue_date => '2010-11-11' } The following hash reference is returned. { 'book.price' => 1900, title => '%Perl%', 'book.author' => '%Ken%', } By default, If the value has length, key and value is mapped. title => 'Perl' # Mapped {title => '' } # Not mapped {title => undef} # Not mapped {} # Not mapped You can set change mapping condition by C attribute. $mapper->condition('defined'); Or you can set C option for each key. my $new_param = $mapper->map( price => ['book.price', {condition => 'defined'}] title => [sub { '%' . $_[0] . '%'}, {condition => 'defined'}] # Value author => ['book.author', sub { '%' . $_[0] . '%'}, condtion => 'exists'] ); If C attrivute is set, the keys and value is copied without change. $mapper->pass([qw/title author/]); my $new_param = $mapper->map(price => 'book.price'); The following hash reference {title => 'Perl', author => 'Ken', price => 1900} is mapped to {title => 'Perl', author => 'Ken', 'book.price' => 1900} =cut