Newer Older
249 lines | 6.477kb
added Next version
Yuki Kimoto authored on 2011-11-16
1
package DBIx::Custom::Next::Mapper;
2
use Object::Simple -base;
3

            
4
use DBIx::Custom::Next::NotExists;
5

            
6
use Carp 'croak';
7
use DBIx::Custom::Next::Util '_subname';
8

            
9
# Carp trust relationship
10
push @DBIx::Custom::Next::CARP_NOT, __PACKAGE__;
11

            
12
has [qw/param/],
13
    condition => sub {
14
        sub { defined $_[0] && length $_[0] }
15
    },
16
    pass => sub { [] };
17

            
18
sub map {
19
    my ($self, %rule) = @_;
20
    my $param = $self->param;
21
    $rule{$_} = {key => $_} for @{$self->pass};
22
    
23
    # Mapping
24
    my $new_param = {};
25
    for my $key (keys %rule) {
26
        
27
        my $mapping = $rule{$key};
28
        
29
        # Get mapping information
30
        my $new_key;
31
        my $value;
32
        my $condition;
33
        
34
        if (ref $mapping eq 'ARRAY') {
35
            $new_key = $mapping->[0];
36
            $value = $mapping->[1];
37
            $condition = ref $mapping->[2] eq 'HASH' ? $mapping->[2]->{condition} : $mapping->[2];
38
        }
39
        elsif (ref $mapping eq 'HASH') {
40
            $new_key = $mapping->{key};
41
            $value = $mapping->{value};
42
            $condition = $mapping->{condition};
43
        }
44
        
45
        $new_key = $key unless defined $new_key;
46
        $condition ||= $self->condition;
47
        $condition = $self->_condition_to_sub($condition);
48

            
49
        # Map parameter
50
        if (ref $condition eq 'CODE') {
51
            if (ref $param->{$key} eq 'ARRAY') {
52
                $new_param->{$new_key} = [];
53
                for (my $i = 0; $i < @{$param->{$key}}; $i++) {
54
                    $new_param->{$new_key}->[$i]
55
                      = $condition->($param->{$key}->[$i]) ? $param->{$key}->[$i]
56
                      : DBIx::Custom::Next::NotExists->singleton;
57
                }
58
            }
59
            else {
60
              if ($condition->($param->{$key})) {
61
                  $new_param->{$new_key} = defined $value
62
                                         ? $value->($param->{$key})
63
                                         : $param->{$key};
64
              }
65
            }
66
        }
67
        elsif ($condition eq 'exists') {
68
            if (ref $param->{$key} eq 'ARRAY') {
69
                $new_param->{$new_key} = [];
70
                for (my $i = 0; $i < @{$param->{$key}}; $i++) {
71
                    $new_param->{$new_key}->[$i]
72
                      = exists $param->{$key}->[$i] ? $param->{$key}->[$i]
73
                      : DBIx::Custom::Next::NotExists->singleton;
74
                }
75
            }
76
            else {
77
                if (exists $param->{$key}) {
78
                    $new_param->{$new_key} = defined $value
79
                                           ? $value->($param->{$key})
80
                                           : $param->{$key};
81
                }
82
            }
83
        }
84
        else { croak qq/Condition must be code reference or "exists" / . _subname }
85
    }
86
    
87
    return $new_param;
88
}
89

            
90
sub new {
91
    my $self = shift->SUPER::new(@_);
92
    
93
    # Check attribute names
94
    my @attrs = keys %$self;
95
    for my $attr (@attrs) {
96
        croak qq{"$attr" is invalid attribute name (} . _subname . ")"
97
          unless $self->can($attr);
98
    }
99
    
100
    return $self;
101
}
102

            
103

            
104
sub _condition_to_sub {
105
    my ($self, $if) = @_;
106
    $if = $if eq 'exists' ? $if
107
            : $if eq 'defined' ? sub { defined $_[0] }
108
            : $if eq 'length'  ? sub { defined $_[0] && length $_[0] }
109
            : ref $if eq 'CODE' ? $if
110
            : undef;
111

            
112
    croak "You can must specify right value to C<condition> " . _subname
113
      unless $if;
114
    
115
    return $if;
116
}
117

            
118
1;
119

            
120
=head1 NAME
121

            
122
DBIx::Custom::Next::Mapper - Mapper of parameter
123

            
124
=head1 SYNOPSYS
125

            
126
    my $mapper = $dbi->mapper(param => $param);
127
    my $new_param = $mapper->map(
128
        title => 'book.title', # Key
129
        author => sub { '%' . $_[0] . '%'} # Value
130
        price => ['book.price' => sub { '%' . $_[0] . '%' }], # Key and value
131
    );
132

            
133
=head1 ATTRIBUTES
134

            
135
=head2 C<param>
136

            
137
    my $param = $mapper->param;
138
    $mapper = $mapper->param({title => 'Perl', author => 'Ken'});
139

            
140
Parameter.
141

            
142
=head2 C<pass>
143

            
144
    my $pass = $mapper->pass;
145
    $mapper = $mapper->pass([qw/title author/]);
146

            
147
the key and value is copied without change when C<map> method is executed.
148

            
149
=head2 C<condition>
150

            
151
    my $condition = $mapper->condition;
152
    $mapper = $mapper->condition('exists');
153

            
154
Mapping condtion, default to C<length>.
155

            
156
You can set the following values to C<condition>.
157

            
158
=over 4
159

            
160
=item * C<exists>
161
   
162
    condition => 'exists'
163

            
164
If key exists, key and value is mapped.
165

            
166
=item * C<defined>
167

            
168
    condition => 'defined';
169

            
170
If value is defined, key and value is mapped.
171

            
172
=item * C<length>
173

            
174
    condition => 'length';
175

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

            
178
=item * C<code reference>
179

            
180
    condition => sub { defined $_[0] }
181

            
182
You can set code reference to C<condtion>.
183
The subroutine return true, key and value is mapped.
184

            
185
=head1 METHODS
186

            
187
L<DBIx::Custom::Next::Mapper> inherits all methods from L<Object::Simple>
188
and implements the following new ones.
189

            
190
=head2 C<map>
191

            
192
    my $new_param = $mapper->map(
193
        price => {key => 'book.price'}
194
        title => {value => sub { '%' . $_[0] . '%'}}
195
        author => ['book.author' => sub { '%' . $_[0] . '%'}] # Key and value
196
    );
197

            
198
Map C<param> into new parameter.
199

            
200
For example, if C<param> is set to
201

            
202
    {
203
        price => 1900,
204
        title => 'Perl',
205
        author => 'Ken',
206
        issue_date => '2010-11-11'
207
    }
208

            
209
The following hash reference is returned.
210

            
211
    {
212
        'book.price' => 1900,
213
        title => '%Perl%',
214
        'book.author' => '%Ken%',
215
    }
216

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

            
219
    title => 'Perl'  # Mapped
220
    {title => '' }   # Not mapped
221
    {title => undef} # Not mapped
222
    {}               # Not mapped
223

            
224
You can set change mapping condition by C<condition> attribute.
225

            
226
    $mapper->condition('defined');
227

            
228
Or you can set C<condtion> option for each key.
229

            
230
    my $new_param = $mapper->map(
231
        price => {key => 'book.price', condition => 'defined'}]
232
        title => {value => sub { '%' . $_[0] . '%'}, condition => 'defined'}
233
        author => ['book.author', sub { '%' . $_[0] . '%'}, 'exists']
234
    );
235

            
236
If C<pass> attrivute is set, the keys and value is copied without change.
237

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

            
241
The following hash reference
242
    
243
    {title => 'Perl', author => 'Ken', price => 1900}
244

            
245
is mapped to
246

            
247
    {title => 'Perl', author => 'Ken', 'book.price' => 1900}
248

            
249
=cut