Newer Older
366 lines | 9.414kb
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
    clause => sub { [] };
14

            
map cleanup
Yuki Kimoto authored on 2011-08-09
15
sub map {
16
    my ($self, %map) = @_;
17
    
added tests
Yuki Kimoto authored on 2011-08-09
18
    if ($self->if ne 'exists' || keys %map) {
19
        my $param = $self->_map_param($self->param, %map);
20
        $self->param($param);
21
    }
map cleanup
Yuki Kimoto authored on 2011-08-09
22
    return $self;
23
}
24

            
added map method(not complet...
Yuki Kimoto authored on 2011-08-09
25
sub _map_param {
26
    my $self = shift;
27
    my $param = shift;
28
    
29
    return $param if !defined $param;
30
    
31
    my %map = @_;
32
    
33
    # Mapping
34
    my $map_param = {};
35
    foreach my $key (keys %$param) {
36
    
37
        my $value_cb;
38
        my $condition;
39
        my $map_key;
40
        
41
        # Get mapping information
42
        if (ref $map{$key} eq 'ARRAY') {
43
            foreach my $some (@{$map{$key}}) {
44
                $map_key = $some unless ref $some;
45
                $condition = $some->{if} if ref $some eq 'HASH';
46
                $value_cb = $some if ref $some eq 'CODE';
47
            }
48
        }
cleanup
Yuki Kimoto authored on 2011-08-09
49
        elsif (defined $map{$key}) {
added map method(not complet...
Yuki Kimoto authored on 2011-08-09
50
            $map_key = $map{$key};
51
        }
cleanup
Yuki Kimoto authored on 2011-08-09
52
        else {
53
            $map_key = $key;
54
        }
55
        
added map method(not complet...
Yuki Kimoto authored on 2011-08-09
56
        $value_cb ||= sub { $_[0] };
57
        $condition ||= $self->if || 'exists';
58

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

            
95
sub if {
96
    my $self = shift;
97
    if (@_) {
98
        my $if = $_[0];
99
        
100
        $if = $if eq 'exists' ? $if
101
                : $if eq 'defined' ? sub { defined $_[0] }
added tests
Yuki Kimoto authored on 2011-08-09
102
                : $if eq 'length'  ? sub { defined $_[0] && length $_[0] }
added map method(not complet...
Yuki Kimoto authored on 2011-08-09
103
                : ref $if eq 'CODE' ? $if
104
                : undef;
105

            
106
        croak "You can must specify right value to C<if> " . _subname
107
          unless $if;
108

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

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

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

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

            
262
1;
263

            
264
=head1 NAME
265

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

            
268
=head1 SYNOPSYS
269

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

            
273
=head1 ATTRIBUTES
274

            
275
=head2 C<clause>
276

            
DBIx::Custom::Model type att...
Yuki Kimoto authored on 2011-06-17
277
    my $clause = $where->clause;
278
    $where = $where->clause(
279
        ['and',
280
            'title = :title', 
281
            ['or', 'date < :date', 'date > :date']
282
        ]
added test
Yuki Kimoto authored on 2011-01-19
283
    );
added experimental DBIx::Cus...
Yuki Kimoto authored on 2011-01-18
284

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

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

            
map cleanup
Yuki Kimoto authored on 2011-08-09
290
=head2 C<param>
291

            
292
    my $param = $where->param;
293
    $where = $where->param({
294
        title => 'Perl',
295
        date => ['2010-11-11', '2011-03-05'],
296
    });
297

            
298
=head2 C<dbi>
299

            
300
    my $dbi = $where->dbi;
301
    $where = $where->dbi($dbi);
302

            
303
L<DBIx::Custom> object.
304

            
305
=head1 METHODS
306

            
307
L<DBIx::Custom::Where> inherits all methods from L<Object::Simple>
308
and implements the following new ones.
309

            
310
=head2 C<if EXPERIMENTAL>
311
    
312
    my $if = $where->if($condition);
313
    $where->if($condition);
314

            
315
C<if> is default of C<map> method C<if> option.
316

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

            
map cleanup
Yuki Kimoto authored on 2011-08-09
319
Mapping parameter key and value. C<param> is converted,
320
so this method must be called after C<param> is set.
added map method(not complet...
Yuki Kimoto authored on 2011-08-09
321

            
map cleanup
Yuki Kimoto authored on 2011-08-09
322
    $where->map(
added map method(not complet...
Yuki Kimoto authored on 2011-08-09
323
        'id' => 'book.id',
324
        'author' => ['book.author' => sub { '%' . $_[0] . '%' }],
325
        'price' => [
326
            'book.price', {if => sub { length $_[0] }
327
        ]
map cleanup
Yuki Kimoto authored on 2011-08-09
328
    );
added map method(not complet...
Yuki Kimoto authored on 2011-08-09
329

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

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

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

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

            
340
In case C<defined> is specified, if the value is defined,
341
mapping is done.
342

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

            
345
In case C<length> is specified, the value is defined
346
and the length is bigger than 0, mappting is done.
347

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

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

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

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

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

            
358
    $where->to_string;
added test
Yuki Kimoto authored on 2011-01-19
359

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

            
362
double quote is override to execute C<to_string> method.
363

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

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