Newer Older
377 lines | 9.952kb
added experimental DBIx::Cus...
Yuki Kimoto authored on 2011-01-18
1
package DBIx::Custom::Where;
updatedd pod
Yuki Kimoto authored on 2011-06-12
2
use Object::Simple -base;
added experimental DBIx::Cus...
Yuki Kimoto authored on 2011-01-18
3

            
DBIx::Custom::Model type att...
Yuki Kimoto authored on 2011-06-17
4
use Carp 'croak';
5
use DBIx::Custom::Util '_subname';
added experimental DBIx::Cus...
Yuki Kimoto authored on 2011-01-18
6
use overload 'bool' => sub {1}, fallback => 1;
7
use overload '""' => sub { shift->to_string }, fallback => 1;
8

            
updated document
Yuki Kimoto authored on 2011-01-20
9
# Carp trust relationship
10
push @DBIx::Custom::CARP_NOT, __PACKAGE__;
11

            
sub module use DBIx::Custom ...
Yuki Kimoto authored on 2011-08-02
12
has [qw/dbi param/],
added map method(not complet...
Yuki Kimoto authored on 2011-08-09
13
    map => sub { {} },
14
    clause => sub { [] };
15

            
16
sub _map_param {
17
    my $self = shift;
18
    my $param = shift;
19
    
20
    return $param if !defined $param;
21
    
22
    my %map = @_;
23
    
24
    # Mapping
25
    my $map_param = {};
26
    foreach my $key (keys %$param) {
27
    
28
        unless (exists $map{$key}) {
29
            if (ref $param->{$key} eq 'ARRAY') {
30
                $map_param->{$key} = [@{$param->{$key}}];
31
            }
32
            else {
33
                $map_param->{$key} = $param->{$key};
34
            }
35
            next;
36
        }
37
        
38
        my $value_cb;
39
        my $condition;
40
        my $map_key;
41
        
42
        # Get mapping information
43
        if (ref $map{$key} eq 'ARRAY') {
44
            foreach my $some (@{$map{$key}}) {
45
                $map_key = $some unless ref $some;
46
                $condition = $some->{if} if ref $some eq 'HASH';
47
                $value_cb = $some if ref $some eq 'CODE';
48
            }
49
        }
50
        else {
51
            $map_key = $map{$key};
52
        }
53
        $value_cb ||= sub { $_[0] };
54
        $condition ||= $self->if || 'exists';
55

            
56
        # Map parameter
57
        my $value;
58
        if (ref $condition eq 'CODE') {
59
            if (ref $param->{$key} eq 'ARRAY') {
60
                $map_param->{$map_key} = [];
61
                for (my $i = 0; $i < @{$param->{$key}}; $i++) {
62
                    $map_param->{$map_key}->[$i]
63
                      = $condition->($param->{$key}->[$i]) ? $param->{$key}->[$i]
64
                      : $self->dbi->not_exists;
65
                }
66
            }
67
            else {
68
                $map_param->{$map_key} = $value_cb->($param->{$key})
69
                  if $condition->($param->{$key});
70
            }
71
        }
72
        elsif ($condition eq 'exists') {
73
            if (ref $param->{$key} eq 'ARRAY') {
74
                $map_param->{$map_key} = [];
75
                for (my $i = 0; $i < @{$param->{$key}}; $i++) {
76
                    $map_param->{$map_key}->[$i]
77
                      = exists $param->{$key}->[$i] ? $param->{$key}->[$i]
78
                      : $self->dbi->not_exists;
79
                }
80
            }
81
            else {
82
                $map_param->{$map_key} = $value_cb->($param->{$key})
83
                  if exists $param->{$key};
84
            }
85
        }
86
        else { croak qq/Condition must be code reference or "exists" / . _subname }
87
    }
88
    
89
    return $map_param;
90
}
91

            
92
sub if {
93
    my $self = shift;
94
    if (@_) {
95
        my $if = $_[0];
96
        
97
        $if = $if eq 'exists' ? $if
98
                : $if eq 'defined' ? sub { defined $_[0] }
99
                : $if eq 'length'  ? sub { length $_[0] }
100
                : ref $if eq 'CODE' ? $if
101
                : undef;
102

            
103
        croak "You can must specify right value to C<if> " . _subname
104
          unless $if;
105

            
106
        $self->{if} = $if;
107
        return $self;
108
    }
109
    $self->{if} = 'exists' unless exists $self->{if};
110
    return $self->{if};
111
}
added experimental DBIx::Cus...
Yuki Kimoto authored on 2011-01-18
112

            
improved error messages
Yuki Kimoto authored on 2011-04-18
113
sub new {
114
    my $self = shift->SUPER::new(@_);
115
    
116
    # Check attribute names
117
    my @attrs = keys %$self;
118
    foreach my $attr (@attrs) {
cleanup
Yuki Kimoto authored on 2011-04-25
119
        croak qq{"$attr" is invalid attribute name (} . _subname . ")"
improved error messages
Yuki Kimoto authored on 2011-04-18
120
          unless $self->can($attr);
121
    }
122
    
123
    return $self;
124
}
125

            
changed DBIx::Custom::Where ...
Yuki Kimoto authored on 2011-01-19
126
sub to_string {
added test
Yuki Kimoto authored on 2011-01-19
127
    my $self = shift;
added experimental DBIx::Cus...
Yuki Kimoto authored on 2011-01-18
128
    
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
129
    # Check if column name is safety character;
cleanup
Yuki Kimoto authored on 2011-08-02
130
    my $safety = $self->dbi->safety_character;
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
131
    if (ref $self->param eq 'HASH') {
132
        foreach my $column (keys %{$self->param}) {
133
            croak qq{"$column" is not safety column name (} . _subname . ")"
134
              unless $column =~ /^[$safety\.]+$/;
135
        }
136
    }
many changed
Yuki Kimoto authored on 2011-01-23
137
    # Clause
added test
Yuki Kimoto authored on 2011-01-19
138
    my $clause = $self->clause;
changed DBIx::Custom::Where ...
Yuki Kimoto authored on 2011-01-19
139
    $clause = ['and', $clause] unless ref $clause eq 'ARRAY';
added test
Yuki Kimoto authored on 2011-01-19
140
    $clause->[0] = 'and' unless @$clause;
added EXPERIMENTAL DBIx::Cus...
Yuki Kimoto authored on 2011-08-09
141
    
142
    # Map condition
added map method(not complet...
Yuki Kimoto authored on 2011-08-09
143
    my $if = $self->if || '';
144
    $if = $if eq 'exists' ? $if
145
            : $if eq 'defined' ? sub { defined $_[0] }
146
            : $if eq 'length'  ? sub { length $_[0] }
147
            : ref $if eq 'CODE' ? $if
added EXPERIMENTAL DBIx::Cus...
Yuki Kimoto authored on 2011-08-09
148
            : undef;
149
    
added map method(not complet...
Yuki Kimoto authored on 2011-08-09
150
    croak "You can must specify right value to C<if> " . _subname
151
      unless $if;
152
    $self->{_if} = $if;
153
    
154
    $self->{_param} = $self->_map_param($self->param, %{$self->map});
added EXPERIMENTAL DBIx::Cus...
Yuki Kimoto authored on 2011-08-09
155
    
many changed
Yuki Kimoto authored on 2011-01-23
156
    # Parse
added test
Yuki Kimoto authored on 2011-01-19
157
    my $where = [];
158
    my $count = {};
many changed
Yuki Kimoto authored on 2011-01-23
159
    $self->_parse($clause, $where, $count, 'and');
changed DBIx::Custom::Where ...
Yuki Kimoto authored on 2011-01-19
160
    
many changed
Yuki Kimoto authored on 2011-01-23
161
    # Stringify
162
    unshift @$where, 'where' if @$where;
added test
Yuki Kimoto authored on 2011-01-19
163
    return join(' ', @$where);
added experimental DBIx::Cus...
Yuki Kimoto authored on 2011-01-18
164
}
165

            
added test
Yuki Kimoto authored on 2011-01-19
166
our %VALID_OPERATIONS = map { $_ => 1 } qw/and or/;
many changed
Yuki Kimoto authored on 2011-01-23
167
sub _parse {
added test
Yuki Kimoto authored on 2011-01-19
168
    my ($self, $clause, $where, $count, $op) = @_;
added experimental DBIx::Cus...
Yuki Kimoto authored on 2011-01-18
169
    
many changed
Yuki Kimoto authored on 2011-01-23
170
    # Array
changed DBIx::Custom::Where ...
Yuki Kimoto authored on 2011-01-19
171
    if (ref $clause eq 'ARRAY') {
many changed
Yuki Kimoto authored on 2011-01-23
172
        
173
        # Start
added test
Yuki Kimoto authored on 2011-01-19
174
        push @$where, '(';
changed DBIx::Custom::Where ...
Yuki Kimoto authored on 2011-01-19
175
        
many changed
Yuki Kimoto authored on 2011-01-23
176
        # Operation
changed DBIx::Custom::Where ...
Yuki Kimoto authored on 2011-01-19
177
        my $op = $clause->[0] || '';
improved error message
Yuki Kimoto authored on 2011-06-13
178
        croak qq{First argument must be "and" or "or" in where clause } .
179
              qq{"$op" is passed} . _subname . ")"
changed DBIx::Custom::Where ...
Yuki Kimoto authored on 2011-01-19
180
          unless $VALID_OPERATIONS{$op};
many changed
Yuki Kimoto authored on 2011-01-23
181
        
fixed DBIx::Custom::Where to...
Yuki Kimoto authored on 2011-06-27
182
        my $pushed_array;
many changed
Yuki Kimoto authored on 2011-01-23
183
        # Parse internal clause
changed DBIx::Custom::Where ...
Yuki Kimoto authored on 2011-01-19
184
        for (my $i = 1; $i < @$clause; $i++) {
many changed
Yuki Kimoto authored on 2011-01-23
185
            my $pushed = $self->_parse($clause->[$i], $where, $count, $op);
added test
Yuki Kimoto authored on 2011-01-19
186
            push @$where, $op if $pushed;
fixed DBIx::Custom::Where to...
Yuki Kimoto authored on 2011-06-27
187
            $pushed_array = 1 if $pushed;
changed DBIx::Custom::Where ...
Yuki Kimoto authored on 2011-01-19
188
        }
added test
Yuki Kimoto authored on 2011-01-19
189
        pop @$where if $where->[-1] eq $op;
190
        
many changed
Yuki Kimoto authored on 2011-01-23
191
        # Undo
added test
Yuki Kimoto authored on 2011-01-19
192
        if ($where->[-1] eq '(') {
193
            pop @$where;
fixed DBIx::Custom::Where to...
Yuki Kimoto authored on 2011-06-27
194
            pop @$where if ($where->[-1] || '') eq $op;
added test
Yuki Kimoto authored on 2011-01-19
195
        }
many changed
Yuki Kimoto authored on 2011-01-23
196
        # End
renamed DBIx::Custom::TagPro...
Yuki Kimoto authored on 2011-01-24
197
        else { push @$where, ')' }
fixed DBIx::Custom::Where to...
Yuki Kimoto authored on 2011-06-27
198
        
199
        return $pushed_array;
changed DBIx::Custom::Where ...
Yuki Kimoto authored on 2011-01-19
200
    }
many changed
Yuki Kimoto authored on 2011-01-23
201
    
202
    # String
changed DBIx::Custom::Where ...
Yuki Kimoto authored on 2011-01-19
203
    else {
DBIx::Custom::Where clause a...
Yuki Kimoto authored on 2011-04-18
204
        # Pushed
205
        my $pushed;
changed DBIx::Custom::Where ...
Yuki Kimoto authored on 2011-01-19
206
        
added test
Yuki Kimoto authored on 2011-01-19
207
        # Column
cleanup
Yuki Kimoto authored on 2011-08-02
208
        my $columns = $self->dbi->query_builder->build_query($clause)->columns;
DBIx::Custom::Where clause a...
Yuki Kimoto authored on 2011-04-18
209
        if (@$columns == 0) {
210
            push @$where, $clause;
211
            $pushed = 1;
212
            return $pushed;
213
        }
214
        elsif (@$columns != 1) {
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
215
            croak qq{Each part contains one column name: "$clause" (}
cleanup
Yuki Kimoto authored on 2011-04-25
216
                  . _subname . ")";
DBIx::Custom::Where clause a...
Yuki Kimoto authored on 2011-04-18
217
        }
DBIx::Custom::Model type att...
Yuki Kimoto authored on 2011-06-17
218
        
219
        # Remove quote
changed DBIx::Custom::Where ...
Yuki Kimoto authored on 2011-01-19
220
        my $column = $columns->[0];
sub module use DBIx::Custom ...
Yuki Kimoto authored on 2011-08-02
221
        if (my $q = $self->dbi->_quote) {
added quote method's two cha...
Yuki Kimoto authored on 2011-07-29
222
            $q = quotemeta($q);
223
            $column =~ s/[$q]//g;
added EXPERIMENTAL reserved_...
Yuki Kimoto authored on 2011-03-30
224
        }
225
        
DBIx::Custom::Model type att...
Yuki Kimoto authored on 2011-06-17
226
        # Check safety
cleanup
Yuki Kimoto authored on 2011-08-02
227
        my $safety = $self->dbi->safety_character;
cleanup
Yuki Kimoto authored on 2011-04-25
228
        croak qq{"$column" is not safety column name (} . _subname . ")"
- remaned experimental safty...
Yuki Kimoto authored on 2011-03-10
229
          unless $column =~ /^[$safety\.]+$/;
changed DBIx::Custom::Where ...
Yuki Kimoto authored on 2011-01-19
230
        
many changed
Yuki Kimoto authored on 2011-01-23
231
        # Column count up
added test
Yuki Kimoto authored on 2011-01-19
232
        my $count = ++$count->{$column};
changed DBIx::Custom::Where ...
Yuki Kimoto authored on 2011-01-19
233
        
many changed
Yuki Kimoto authored on 2011-01-23
234
        # Push
added map method(not complet...
Yuki Kimoto authored on 2011-08-09
235
        my $param = $self->{_param};
added experimental not_exist...
Yuki Kimoto authored on 2011-01-26
236
        if (ref $param eq 'HASH') {
renamed DBIx::Custom::TagPro...
Yuki Kimoto authored on 2011-01-24
237
            if (exists $param->{$column}) {
added map method(not complet...
Yuki Kimoto authored on 2011-08-09
238
                my $if = $self->{_if};
added EXPERIMENTAL DBIx::Cus...
Yuki Kimoto authored on 2011-08-09
239
                
renamed DBIx::Custom::TagPro...
Yuki Kimoto authored on 2011-01-24
240
                if (ref $param->{$column} eq 'ARRAY') {
added EXPERIMENTAL DBIx::Cus...
Yuki Kimoto authored on 2011-08-09
241
                    unless (ref $param->{$column}->[$count - 1] eq 'DBIx::Custom::NotExists') {
added map method(not complet...
Yuki Kimoto authored on 2011-08-09
242
                        if ($if eq 'exists') {
added EXPERIMENTAL DBIx::Cus...
Yuki Kimoto authored on 2011-08-09
243
                            $pushed = 1 if exists $param->{$column}->[$count - 1];
244
                        }
245
                        else {
added map method(not complet...
Yuki Kimoto authored on 2011-08-09
246
                            $pushed = 1 if $if->($param->{$column}->[$count - 1]);
added EXPERIMENTAL DBIx::Cus...
Yuki Kimoto authored on 2011-08-09
247
                        }
248
                    }
added experimental not_exist...
Yuki Kimoto authored on 2011-01-26
249
                } 
renamed DBIx::Custom::TagPro...
Yuki Kimoto authored on 2011-01-24
250
                elsif ($count == 1) {
added map method(not complet...
Yuki Kimoto authored on 2011-08-09
251
                    if ($if eq 'exists') {
252
                        $pushed = 1 if exists $param->{$column};
added EXPERIMENTAL DBIx::Cus...
Yuki Kimoto authored on 2011-08-09
253
                    }
254
                    else {
added map method(not complet...
Yuki Kimoto authored on 2011-08-09
255
                        $pushed = 1 if $if->($param->{$column});
added EXPERIMENTAL DBIx::Cus...
Yuki Kimoto authored on 2011-08-09
256
                    }
renamed DBIx::Custom::TagPro...
Yuki Kimoto authored on 2011-01-24
257
                }
added experimental DBIx::Cus...
Yuki Kimoto authored on 2011-01-18
258
            }
renamed DBIx::Custom::TagPro...
Yuki Kimoto authored on 2011-01-24
259
            push @$where, $clause if $pushed;
260
        }
added experimental not_exist...
Yuki Kimoto authored on 2011-01-26
261
        elsif (!defined $param) {
renamed DBIx::Custom::TagPro...
Yuki Kimoto authored on 2011-01-24
262
            push @$where, $clause;
263
            $pushed = 1;
added experimental DBIx::Cus...
Yuki Kimoto authored on 2011-01-18
264
        }
improved error messages
Yuki Kimoto authored on 2011-04-18
265
        else {
cleanup
Yuki Kimoto authored on 2011-04-25
266
            croak "Parameter must be hash reference or undfined value ("
267
                . _subname . ")"
improved error messages
Yuki Kimoto authored on 2011-04-18
268
        }
added test
Yuki Kimoto authored on 2011-01-19
269
        return $pushed;
added experimental DBIx::Cus...
Yuki Kimoto authored on 2011-01-18
270
    }
fixed DBIx::Custom::Where to...
Yuki Kimoto authored on 2011-06-27
271
    return;
added experimental DBIx::Cus...
Yuki Kimoto authored on 2011-01-18
272
}
273

            
274
1;
275

            
276
=head1 NAME
277

            
removed EXPERIMETNAL flag fr...
Yuki Kimoto authored on 2011-03-25
278
DBIx::Custom::Where - Where clause
added experimental DBIx::Cus...
Yuki Kimoto authored on 2011-01-18
279

            
280
=head1 SYNOPSYS
281

            
many changed
Yuki Kimoto authored on 2011-01-23
282
    my $where = DBIx::Custom::Where->new;
DBIx::Custom::Model type att...
Yuki Kimoto authored on 2011-06-17
283
    my $string_where = "$where";
added experimental DBIx::Cus...
Yuki Kimoto authored on 2011-01-18
284

            
285
=head1 ATTRIBUTES
286

            
287
=head2 C<clause>
288

            
DBIx::Custom::Model type att...
Yuki Kimoto authored on 2011-06-17
289
    my $clause = $where->clause;
290
    $where = $where->clause(
291
        ['and',
292
            'title = :title', 
293
            ['or', 'date < :date', 'date > :date']
294
        ]
added test
Yuki Kimoto authored on 2011-01-19
295
    );
added experimental DBIx::Cus...
Yuki Kimoto authored on 2011-01-18
296

            
many changed
Yuki Kimoto authored on 2011-01-23
297
Where clause. Above one is expanded to the following SQL by to_string
298
If all parameter names is exists.
299

            
DBIx::Custom::Model type att...
Yuki Kimoto authored on 2011-06-17
300
    "where ( title = :title and ( date < :date or date > :date ) )"
added experimental DBIx::Cus...
Yuki Kimoto authored on 2011-01-18
301

            
added map method(not complet...
Yuki Kimoto authored on 2011-08-09
302
=head2 C<map EXPERIMENTAL>
303

            
304
Mapping parameter key and value when C<to_stirng> method is executed.
305

            
306
    $where->map({
307
        'id' => 'book.id',
308
        'author' => ['book.author' => sub { '%' . $_[0] . '%' }],
309
        'price' => [
310
            'book.price', {if => sub { length $_[0] }
311
        ]
312
    });
313

            
314
The following option is available.
added EXPERIMENTAL DBIx::Cus...
Yuki Kimoto authored on 2011-08-09
315

            
added map method(not complet...
Yuki Kimoto authored on 2011-08-09
316
=over 4
added EXPERIMENTAL DBIx::Cus...
Yuki Kimoto authored on 2011-08-09
317

            
added map method(not complet...
Yuki Kimoto authored on 2011-08-09
318
=item * C<if>
319

            
320
By default, if parameter key is exists, mapping is done.
added EXPERIMENTAL DBIx::Cus...
Yuki Kimoto authored on 2011-08-09
321
    
added map method(not complet...
Yuki Kimoto authored on 2011-08-09
322
    if => 'exists';
added EXPERIMENTAL DBIx::Cus...
Yuki Kimoto authored on 2011-08-09
323

            
324
In case C<defined> is specified, if the value is defined,
325
mapping is done.
326

            
added map method(not complet...
Yuki Kimoto authored on 2011-08-09
327
    if => 'defined';
added EXPERIMENTAL DBIx::Cus...
Yuki Kimoto authored on 2011-08-09
328

            
329
In case C<length> is specified, the value is defined
330
and the length is bigger than 0, mappting is done.
331

            
added map method(not complet...
Yuki Kimoto authored on 2011-08-09
332
    if => 'length';
added EXPERIMENTAL DBIx::Cus...
Yuki Kimoto authored on 2011-08-09
333

            
334
You can also subroutine like C<sub { defined $_[0] }> for mappging.
335

            
added map method(not complet...
Yuki Kimoto authored on 2011-08-09
336
    if => sub { defined $_[0] }
337

            
338
=back
added EXPERIMENTAL DBIx::Cus...
Yuki Kimoto authored on 2011-08-09
339

            
update pod
Yuki Kimoto authored on 2011-01-27
340
=head2 C<param>
341

            
342
    my $param = $where->param;
DBIx::Custom::Model type att...
Yuki Kimoto authored on 2011-06-17
343
    $where = $where->param({
344
        title => 'Perl',
345
        date => ['2010-11-11', '2011-03-05'],
346
    });
update pod
Yuki Kimoto authored on 2011-01-27
347

            
cleanup
Yuki Kimoto authored on 2011-08-02
348
=head2 C<dbi>
update pod
Yuki Kimoto authored on 2011-01-27
349

            
cleanup
Yuki Kimoto authored on 2011-08-02
350
    my $dbi = $where->dbi;
351
    $where = $where->dbi($dbi);
352

            
353
L<DBIx::Custom> object.
update pod
Yuki Kimoto authored on 2011-01-27
354

            
355
=head1 METHODS
356

            
DBIx::Custom::Model type att...
Yuki Kimoto authored on 2011-06-17
357
L<DBIx::Custom::Where> inherits all methods from L<Object::Simple>
358
and implements the following new ones.
359

            
added map method(not complet...
Yuki Kimoto authored on 2011-08-09
360
=head2 C<if EXPERIMENTAL>
361
    
362
    my $if = $where->if($condition);
363
    $where->if($condition);
364

            
365
C<if> is default of C<map> method C<if> option.
366

            
added experimental DBIx::Cus...
Yuki Kimoto authored on 2011-01-18
367
=head2 C<to_string>
368

            
369
    $where->to_string;
added test
Yuki Kimoto authored on 2011-01-19
370

            
DBIx::Custom::Model type att...
Yuki Kimoto authored on 2011-06-17
371
Convert where clause to string.
372

            
373
double quote is override to execute C<to_string> method.
374

            
375
    my $string_where = "$where";
added test
Yuki Kimoto authored on 2011-01-19
376

            
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
377
=cut