<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">package DBIx::Custom::Mapper;
use Object::Simple -base;

use DBIx::Custom::NotExists;

use Carp 'croak';
use DBIx::Custom::Util qw/_subname _deprecate/;

# Carp trust relationship
push @DBIx::Custom::CARP_NOT, __PACKAGE__;

has [qw/param/],
  condition =&gt; sub {
    sub { defined $_[0] &amp;&amp; length $_[0] }
  },
  pass =&gt; sub { [] };

sub map {
  my ($self, %rule) = @_;
  my $param = $self-&gt;param;
  $rule{$_} = {key =&gt; $_} for @{$self-&gt;pass};
  
  # Mapping
  my $new_param = {};
  for my $key (keys %rule) {
    
    my $mapping = $rule{$key};
    
    # Get mapping information
    my $new_key;
    my $value;
    my $condition;
    
    if (ref $mapping eq 'ARRAY') {
      $new_key = $mapping-&gt;[0];
      $value = $mapping-&gt;[1];
      $condition = ref $mapping-&gt;[2] eq 'HASH' ? $mapping-&gt;[2]-&gt;{condition} : $mapping-&gt;[2];
    }
    elsif (ref $mapping eq 'HASH') {
      $new_key = $mapping-&gt;{key};
      $value = $mapping-&gt;{value};
      $condition = $mapping-&gt;{condition};
    }
    elsif (!ref $mapping) {
      $new_key = $mapping;
      _deprecate('0.24', qq/map method's string value "$mapping" is DEPRECATED. / .
        qq/use {key =&gt; ...} syntax instead/);
    }
    elsif (ref $mapping eq 'CODE') {
      $value = $mapping;
      _deprecate('0.24', qq/map method's code reference value "$mapping" is DEPRECATED. / .
        qq/use {value =&gt; ...} syntax instead/);
    }
    
    $new_key = $key unless defined $new_key;
    $condition ||= $self-&gt;condition;
    $condition = $self-&gt;_condition_to_sub($condition);

    # Map parameter
    if (ref $condition eq 'CODE') {
      if (ref $param-&gt;{$key} eq 'ARRAY') {
        $new_param-&gt;{$new_key} = [];
        for (my $i = 0; $i &lt; @{$param-&gt;{$key}}; $i++) {
          $new_param-&gt;{$new_key}-&gt;[$i]
            = $condition-&gt;($param-&gt;{$key}-&gt;[$i]) ? $param-&gt;{$key}-&gt;[$i]
            : DBIx::Custom::NotExists-&gt;singleton;
        }
      }
      else {
        if ($condition-&gt;($param-&gt;{$key})) {
          if (defined $value) {
            if (ref $value) {
              $new_param-&gt;{$new_key} = $value-&gt;($param-&gt;{$key});
            }
            else {
              $value =~ s/&lt;value&gt;/$param-&gt;{$key}/e;
              $new_param-&gt;{$new_key} = $value;
            }
          }
          else { $new_param-&gt;{$new_key} = $param-&gt;{$key} }
        }
      }
    }
    elsif ($condition eq 'exists') {
      if (ref $param-&gt;{$key} eq 'ARRAY') {
        $new_param-&gt;{$new_key} = [];
        for (my $i = 0; $i &lt; @{$param-&gt;{$key}}; $i++) {
          $new_param-&gt;{$new_key}-&gt;[$i]
            = exists $param-&gt;{$key}-&gt;[$i] ? $param-&gt;{$key}-&gt;[$i]
            : DBIx::Custom::NotExists-&gt;singleton;
        }
      }
      else {
        if (exists $param-&gt;{$key}) {
          $new_param-&gt;{$new_key} = defined $value
            ? $value-&gt;($param-&gt;{$key}) : $param-&gt;{$key};
        }
      }
    }
    else { croak qq/Condition must be code reference or "exists" / . _subname }
  }
  
  return $new_param;
}

sub new {
  my $self = shift-&gt;SUPER::new(@_);
  
  # Check attribute names
  my @attrs = keys %$self;
  for my $attr (@attrs) {
    croak qq{"$attr" is invalid attribute name (} . _subname . ")"
      unless $self-&gt;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] &amp;&amp; length $_[0] }
    : ref $if eq 'CODE' ? $if
    : undef;

  croak "You can must specify right value to C&lt;condition&gt; " . _subname
    unless $if;
  
  return $if;
}

1;

=head1 NAME

DBIx::Custom::Mapper - Mapper of parameter

=head1 SYNOPSYS

  my $mapper = $dbi-&gt;mapper(param =&gt; $param);
  my $new_param = $mapper-&gt;map(
    title =&gt; 'book.title', # Key
    author =&gt; sub { '%' . $_[0] . '%'} # Value
    price =&gt; ['book.price' =&gt; sub { '%' . $_[0] . '%' }], # Key and value
  );

=head1 ATTRIBUTES

=head2 param

  my $param = $mapper-&gt;param;
  $mapper = $mapper-&gt;param({title =&gt; 'Perl', author =&gt; 'Ken'});

Parameter.

=head2 pass

  my $pass = $mapper-&gt;pass;
  $mapper = $mapper-&gt;pass([qw/title author/]);

the key and value is copied without change when C&lt;map&gt; method is executed.

=head2 condition

  my $condition = $mapper-&gt;condition;
  $mapper = $mapper-&gt;condition('exists');

Mapping condtion, default to C&lt;length&gt;.

You can set the following values to C&lt;condition&gt;.

=over 4

=item * exists
 
  condition =&gt; 'exists'

If key exists, key and value is mapped.

=item * defined

  condition =&gt; 'defined';

If value is defined, key and value is mapped.

=item * length

  condition =&gt; 'length';

If value is defined and has length, key and value is mapped.

=item * code reference

  condition =&gt; sub { defined $_[0] }

You can set code reference to C&lt;condtion&gt;.
The subroutine return true, key and value is mapped.

=head1 METHODS

L&lt;DBIx::Custom::Mapper&gt; inherits all methods from L&lt;Object::Simple&gt;
and implements the following new ones.

=head2 map

  my $new_param = $mapper-&gt;map(
    price =&gt; {key =&gt; 'book.price'}
    title =&gt; {value =&gt; '%&lt;value&gt;%'}
    author =&gt; ['book.author' =&gt; '%&lt;value&gt;%']
  );

  my $new_param = $mapper-&gt;map(
    price =&gt; {key =&gt; 'book.price'}
    title =&gt; {value =&gt; sub { '%' . shift . '%'}}
    author =&gt; ['book.author' =&gt; sub { '%' . shift . '%'}]
  );

Map parameter in C&lt;param&gt; attribute into new parameter.

For example, if C&lt;param&gt; is set to

  {
    price =&gt; 1900,
    title =&gt; 'Perl',
    author =&gt; 'Ken',
    issue_date =&gt; '2010-11-11'
  }

The following hash reference is returned.

  {
    'book.price' =&gt; 1900,
    title =&gt; '%Perl%',
    'book.author' =&gt; '%Ken%',
  }

=over 2

B&lt;Syntax:&gt;

=item * String =&gt; Hash reference

  # String =&gt; Hash reference
  price =&gt; {key =&gt; 'book.price'}
  title =&gt; {value =&gt; '%&lt;value&gt;%'}
  title =&gt; {value =&gt; sub { '%' . shift . '%'}}

If C&lt;key&gt; is used, only key name is mapped to new parameter

  # Rule
  price =&gt; {key =&gt; 'book.price'}
  # Parameter
  price =&gt; 1900,
  # New parameter
  'book.price' =&gt; 1900,

If C&lt;value&gt; is used, only value is mapped to new parameter

  # Rule
  title =&gt; {value =&gt; '%&lt;value&gt;%'}
  title =&gt; {value =&gt; sub { '%' . shift . '%'}}
  
  # Parameter
  title =&gt; 'Perl',
  # New parameter
  title =&gt; '%Perl%',

C&lt;E&lt;lt&gt;&gt;valueE&lt;gt&gt;&gt; is replaced by original value.
You can use code reference to convert original value.

=item * String =&gt; Array reference
  
  # String =&gt; Array reference
  author =&gt; ['book.author' =&gt; '%&lt;value&gt;%']

Both key name name and value is mapped to new parameter.
This is same as the following syntax.

  # Rule
  {key =&gt; 'book.author', value =&gt; '%&lt;value&gt;%'}

=back

By default, If the value has length, key and value is mapped.

  title =&gt; 'Perl'  # Mapped
  {title =&gt; '' }   # Not mapped
  {title =&gt; undef} # Not mapped
  {}               # Not mapped

You can set change mapping condition by C&lt;condition&gt; attribute.

  $mapper-&gt;condition('defined');

Or you can set C&lt;condtion&gt; option for each key.

  my $new_param = $mapper-&gt;map(
    price =&gt; {key =&gt; 'book.price', condition =&gt; 'defined'}]
    title =&gt; {value =&gt; sub { '%' . $_[0] . '%'}, condition =&gt; 'defined'}
    author =&gt; ['book.author', sub { '%' . $_[0] . '%'}, 'exists']
  );

If C&lt;pass&gt; attribute is set, the keys and value is copied without change.

  $mapper-&gt;pass([qw/title author/]);
  my $new_param = $mapper-&gt;map(price =&gt; {key =&gt; 'book.price'});

The following hash reference
  
  {title =&gt; 'Perl', author =&gt; 'Ken', price =&gt; 1900}

is mapped to

  {title =&gt; 'Perl', author =&gt; 'Ken', 'book.price' =&gt; 1900}

=cut
</pre></body></html>