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

            
4
use Carp 'croak';
5
use DBIx::Custom::Next::Util qw/_array_to_hash _subname/;
6

            
7
has [qw/dbi sth/],
8
    stash => sub { {} };
9

            
10
*all = \&fetch_hash_all;
11

            
12
sub filter {
13
    my $self = shift;
14
    
15
    # Set
16
    if (@_) {
17
        
18
        # Convert filter name to subroutine
19
        my $filter = @_ == 1 ? $_[0] : [@_];
20
        $filter = _array_to_hash($filter);
21
        for my $column (keys %$filter) {
22
            my $fname = $filter->{$column};
23
            if  (exists $filter->{$column}
24
              && defined $fname
25
              && ref $fname ne 'CODE') 
26
            {
27
              croak qq{Filter "$fname" is not registered" } . _subname
28
                unless exists $self->dbi->filters->{$fname};
29
              $filter->{$column} = $self->dbi->filters->{$fname};
30
            }
31
        }
32
        
33
        # Merge
34
        $self->{filter} = {%{$self->filter}, %$filter};
35
        
36
        return $self;
37
    }
38
    
39
    return $self->{filter} ||= {};
40
}
41

            
42
sub fetch {
43
    my $self = shift;
44
    
45
    # Info
46
    $self->_cache unless $self->{_cache};
47
    
48
    # Fetch
49
    my @row = $self->{sth}->fetchrow_array;
50
    return unless @row;
51
    
52
    # Type rule
53
    if ($self->{type_rule}->{from1} && !$self->{type_rule_off} && !$self->{type_rule1_off}) {
54
        my $from = $self->{type_rule}->{from1};
55
        for my $type (keys %$from) {
56
            for my $column (@{$self->{_type_map}->{$type}}) {
57
                $row[$_] = $from->{$type}->($row[$_])
58
                  for @{$self->{_pos}{$column} || []};
59
            }
60
        }
61
    }
62
    if ($self->{type_rule}->{from2} && !$self->{type_rule_off} && !$self->{type_rule2_off}) {
63
        my $from = $self->{type_rule}->{from2};
64
        for my $type (keys %$from) {
65
            for my $column (@{$self->{_type_map}->{$type}}) {
66
                $row[$_] = $from->{$type}->($row[$_])
67
                  for @{$self->{_pos}{$column} || []};
68
            }
69
        }
70
    }
71
    
72
    # Filter
73
    if ($self->{filter}) {
74
         for my $column (keys %{$self->{filter}}) {
75
             my $filter = $self->{filter}->{$column};
76
             next unless $filter;
77
             $row[$_] = $filter->($row[$_])
78
               for @{$self->{_pos}{$column} || []};
79
         }
80
    }
81
    return \@row;
82
}
83

            
84
sub fetch_hash {
85
    my $self = shift;
86
    
87
    # Info
88
    $self->_cache unless $self->{_cache};
89
    
90
    # Fetch
91
    return unless my $row = $self->{sth}->fetchrow_hashref;
92
    
93
    # Type rule
94
    if ($self->{type_rule}->{from1} &&
95
      !$self->{type_rule_off} && !$self->{type_rule1_off})
96
    {
97
        my $from = $self->{type_rule}->{from1};
98
        for my $type (keys %$from) {
99
            $from->{$type} and $row->{$_} = $from->{$type}->($row->{$_})
100
              for @{$self->{_type_map}->{$type}};
101
        }
102
    }
103
    if ($self->{type_rule}->{from2} &&
104
      !$self->{type_rule_off} && !$self->{type_rule2_off})
105
    {
106
        my $from = $self->{type_rule}->{from2};
107
        for my $type (keys %{$self->{type_rule}->{from2}}) {
108
            $from->{$type} and $row->{$_} = $from->{$type}->($row->{$_})
109
              for @{$self->{_type_map}->{$type}};
110
        }
111
    }        
112
    # Filter
113
    if ($self->{filter}) {
114
       exists $row->{$_} && $self->{filter}->{$_}
115
           and $row->{$_} = $self->{filter}->{$_}->($row->{$_})
116
         for keys %{$self->{filter}};
117
    }
118
    $row;
119
}
120

            
121
sub fetch_all {
122
    my $self = shift;
123
    
124
    # Fetch all rows
125
    my $rows = [];
126
    while(my $row = $self->fetch) { push @$rows, $row}
127
    
128
    return $rows;
129
}
130

            
131
sub fetch_first {
132
    my $self = shift;
133
    
134
    # Fetch
135
    my $row = $self->fetch;
136
    return unless $row;
137
    
138
    # Finish statement handle
139
    $self->sth->finish;
140
    
141
    return $row;
142
}
143

            
144
sub fetch_hash_all {
145
    my $self = shift;
146
    
147
    # Fetch all rows as hash
148
    my $rows = [];
149
    while(my $row = $self->fetch_hash) { push @$rows, $row }
150
    
151
    return $rows;
152
}
153

            
154
sub fetch_hash_first {
155
    my $self = shift;
156
    
157
    # Fetch hash
158
    my $row = $self->fetch_hash;
159
    return unless $row;
160
    
161
    # Finish statement handle
162
    $self->sth->finish;
163
    
164
    return $row;
165
}
166

            
167
sub fetch_hash_multi {
168
    my ($self, $count) = @_;
169
    
170
    # Fetch multiple rows
171
    croak 'Row count must be specified ' . _subname
172
      unless $count;
173
    
174
    return if $self->{_finished};
175

            
176
    my $rows = [];
177
    for (my $i = 0; $i < $count; $i++) {
178
        my $row = $self->fetch_hash;
179
        unless ($row) {
180
            $self->{_finished} = 1;
181
            last;
182
        }
183
        push @$rows, $row;
184
    }
185
    
186
    return unless @$rows;
187
    return $rows;
188
}
189

            
190
sub fetch_multi {
191
    my ($self, $count) = @_;
192
    
193
    # Row count not specifed
194
    croak 'Row count must be specified ' . _subname
195
      unless $count;
196
    
197
    return if $self->{_finished};
198
    
199
    # Fetch multi rows
200
    my $rows = [];
201
    for (my $i = 0; $i < $count; $i++) {
202
        my $row = $self->fetch;
203
        unless ($row) {
204
            $self->{_finished} = 1;
205
            last;
206
        }
207
        push @$rows, $row;
208
    }
209
    
210
    return unless @$rows;
211
    return $rows;
212
}
213

            
214
sub header { shift->sth->{NAME} }
215

            
216
*one = \&fetch_hash_first;
217

            
218
sub type_rule {
219
    my $self = shift;
220
    
221
    if (@_) {
222
        my $type_rule = ref $_[0] eq 'HASH' ? $_[0] : {@_};
223

            
224
        # From
225
        for my $i (1 .. 2) {
226
            $type_rule->{"from$i"} = _array_to_hash($type_rule->{"from$i"});
227
            for my $data_type (keys %{$type_rule->{"from$i"} || {}}) {
228
                croak qq{data type of from$i section must be lower case or number}
229
                  if $data_type =~ /[A-Z]/;
230
                my $fname = $type_rule->{"from$i"}{$data_type};
231
                if (defined $fname && ref $fname ne 'CODE') {
232
                    croak qq{Filter "$fname" is not registered" } . _subname
233
                      unless exists $self->dbi->filters->{$fname};
234
                    
235
                    $type_rule->{"from$i"}{$data_type} = $self->dbi->filters->{$fname};
236
                }
237
            }
238
        }
239
        $self->{type_rule} = $type_rule;
240
        
241
        return $self;
242
    }
243
    
244
    return $self->{type_rule} || {};
245
}
246

            
247
sub type_rule_off {
248
    my $self = shift;
249
    $self->{type_rule_off} = 1;
250
    return $self;
251
}
252

            
253
sub type_rule_on {
254
    my $self = shift;
255
    $self->{type_rule_off} = 0;
256
    return $self;
257
}
258

            
259
sub type_rule1_off {
260
    my $self = shift;
261
    $self->{type_rule1_off} = 1;
262
    return $self;
263
}
264

            
265
sub type_rule1_on {
266
    my $self = shift;
267
    $self->{type_rule1_off} = 0;
268
    return $self;
269
}
270

            
271
sub type_rule2_off {
272
    my $self = shift;
273
    $self->{type_rule2_off} = 1;
274
    return $self;
275
}
276

            
277
sub type_rule2_on {
278
    my $self = shift;
279
    $self->{type_rule2_off} = 0;
280
    return $self;
281
}
282

            
283
sub _cache {
284
    my $self = shift;
285
    $self->{_type_map} = {};
286
    $self->{_pos} = {};
287
    $self->{_columns} = {};
288
    for (my $i = 0; $i < @{$self->{sth}->{NAME}}; $i++) {
289
        my $type = lc $self->{sth}{TYPE}[$i];
290
        my $name = $self->{sth}{NAME}[$i];
291
        $self->{_type_map}{$type} ||= [];
292
        push @{$self->{_type_map}{$type}}, $name;
293
        $self->{_pos}{$name} ||= [];
294
        push @{$self->{_pos}{$name}}, $i;
295
        $self->{_columns}{$name} = 1;
296
    }
297
    $self->{_cache} = 1;
298
}
299

            
300
1;
301

            
302
=head1 NAME
303

            
304
DBIx::Custom::Next::Result - Result of select statement
305

            
306
=head1 SYNOPSIS
307

            
308
    # Result
309
    my $result = $dbi->select(table => 'book');
310

            
311
    # Fetch a row and put it into array reference
312
    while (my $row = $result->fetch) {
313
        my $author = $row->[0];
314
        my $title  = $row->[1];
315
    }
316
    
317
    # Fetch only a first row and put it into array reference
318
    my $row = $result->fetch_first;
319
    
320
    # Fetch all rows and put them into array of array reference
321
    my $rows = $result->fetch_all;
322

            
323
    # Fetch a row and put it into hash reference
324
    while (my $row = $result->fetch_hash) {
325
        my $title  = $row->{title};
326
        my $author = $row->{author};
327
    }
328
    
329
    # Fetch only a first row and put it into hash reference
330
    my $row = $result->fetch_hash_first;
331
    my $row = $result->one; # Same as fetch_hash_first
332
    
333
    # Fetch all rows and put them into array of hash reference
334
    my $rows = $result->fetch_hash_all;
335
    my $rows = $result->all; # Same as fetch_hash_all
336

            
337
=head1 ATTRIBUTES
338

            
339
=head2 C<dbi>
340

            
341
    my $dbi = $result->dbi;
342
    $result = $result->dbi($dbi);
343

            
344
L<DBIx::Custom::Next> object.
345

            
346
=head2 C<sth>
347

            
348
    my $sth = $reuslt->sth
349
    $result = $result->sth($sth);
350

            
351
Statement handle of L<DBI>.
352

            
353
=head1 METHODS
354

            
355
L<DBIx::Custom::Next::Result> inherits all methods from L<Object::Simple>
356
and implements the following new ones.
357

            
358
=head2 C<all>
359

            
360
    my $rows = $result->all;
361

            
362
Same as C<fetch_hash_all>.
363

            
364
=head2 C<fetch>
365

            
366
    my $row = $result->fetch;
367

            
368
Fetch a row and put it into array reference.
369

            
370
=head2 C<fetch_all>
371

            
372
    my $rows = $result->fetch_all;
373

            
374
Fetch all rows and put them into array of array reference.
375

            
376
=head2 C<fetch_first>
377

            
378
    my $row = $result->fetch_first;
379

            
380
Fetch only a first row and put it into array reference,
381
and finish statment handle.
382

            
383
=head2 C<fetch_hash>
384

            
385
    my $row = $result->fetch_hash;
386

            
387
Fetch a row and put it into hash reference.
388

            
389
=head2 C<fetch_hash_all>
390

            
391
    my $rows = $result->fetch_hash_all;
392

            
393
Fetch all rows and put them into array of hash reference.
394

            
395
=head2 C<fetch_hash_first>
396
    
397
    my $row = $result->fetch_hash_first;
398

            
399
Fetch only a first row and put it into hash reference,
400
and finish statment handle.
401

            
402
=head2 C<fetch_hash_multi>
403

            
404
    my $rows = $result->fetch_hash_multi(5);
405
    
406
Fetch multiple rows and put them into array of hash reference.
407

            
408
=head2 C<fetch_multi>
409

            
410
    my $rows = $result->fetch_multi(5);
411
    
412
Fetch multiple rows and put them into array of array reference.
413

            
414
=head2 C<filter>
415

            
416
    $result->filter(title  => sub { uc $_[0] }, author => 'to_upper');
417
    $result->filter([qw/title author/] => 'to_upper');
418

            
419
Set filter for column.
420
You can use subroutine or filter name as filter.
421
This filter is executed after C<type_rule> filter.
422

            
423
=head2 C<header>
424

            
425
    my $header = $result->header;
426

            
427
Get header column names.
428

            
429
=head2 C<one>
430

            
431
    my $row = $result->one;
432

            
433
Same as C<fetch_hash_first>.
434

            
435
=head2 C<stash>
436

            
437
    my $stash = $result->stash;
438
    my $foo = $result->stash->{foo};
439
    $result->stash->{foo} = $foo;
440

            
441
Stash is hash reference for data.
442

            
443
=head2 C<type_rule>
444
    
445
    # Merge type rule
446
    $result->type_rule(
447
        # DATE
448
        9 => sub { ... },
449
        # DATETIME or TIMESTAMP
450
        11 => sub { ... }
451
    );
452

            
453
    # Replace type rule(by reference)
454
    $result->type_rule([
455
        # DATE
456
        9 => sub { ... },
457
        # DATETIME or TIMESTAMP
458
        11 => sub { ... }
459
    ]);
460

            
461
This is same as L<DBIx::Custom::Next>'s C<type_rule>'s <from>.
462

            
463
=head2 C<type_rule_off>
464

            
465
    $result = $result->type_rule_off;
466

            
467
Turn C<from1> and C<from2> type rule off.
468
By default, type rule is on.
469

            
470
=head2 C<type_rule_on>
471

            
472
    $result = $result->type_rule_on;
473

            
474
Turn C<from1> and C<from2> type rule on.
475
By default, type rule is on.
476

            
477
=head2 C<type_rule1_off>
478

            
479
    $result = $result->type_rule1_off;
480

            
481
Turn C<from1> type rule off.
482
By default, type rule is on.
483

            
484
=head2 C<type_rule1_on>
485

            
486
    $result = $result->type_rule1_on;
487

            
488
Turn C<from1> type rule on.
489
By default, type rule is on.
490

            
491
=head2 C<type_rule2_off>
492

            
493
    $result = $result->type_rule2_off;
494

            
495
Turn C<from2> type rule off.
496
By default, type rule is on.
497

            
498
=head2 C<type_rule2_on>
499

            
500
    $result = $result->type_rule2_on;
501

            
502
Turn C<from2> type rule on.
503
By default, type rule is on.
504

            
505
=cut