Showing 7 changed files with 189 additions and 65 deletions
+3
Changes
... ...
@@ -1,3 +1,6 @@
1
+0.1631
2
+  added experimental DBIx::Custom::Result end_filter method
3
+  experimental extended select method's where option
1 4
 0.1630
2 5
   fix test bug
3 6
 0.1629
+1 -1
lib/DBIx/Custom.pm
... ...
@@ -1,6 +1,6 @@
1 1
 package DBIx::Custom;
2 2
 
3
-our $VERSION = '0.1630';
3
+our $VERSION = '0.1631';
4 4
 
5 5
 use 5.008001;
6 6
 use strict;
+94 -34
lib/DBIx/Custom/Guides.pod
... ...
@@ -165,7 +165,7 @@ The following SQL is executed.
165 165
 C<filter> argument can be specified.
166 166
 see also "METHODS" section.
167 167
 
168
-=head2 3. Fetch row
168
+=head2 3. Result manipulation
169 169
 
170 170
 C<select()> method return L<DBIx::Custom::Result> object.
171 171
 You can fetch row by various methods.
... ...
@@ -229,7 +229,7 @@ If you want to access statement handle of L<DBI>, use C<sth> attribute.
229 229
 
230 230
     my $sth = $result->sth;
231 231
 
232
-=head2 4. Hash parameter binding
232
+=head2 4. Parameter binding
233 233
 
234 234
 L<DBIx::Custom> provides hash parameter binding.
235 235
 
... ...
@@ -288,52 +288,70 @@ already perl escaped charactor, so you must write '\\'.
288 288
 
289 289
 =head2 5. Filtering
290 290
 
291
-Usually, Perl string is kept as internal string.
292
-If you want to save the string to database, You must encode the string.
293
-Filtering system help you to convert a data to another data
294
-when you save to the data and get the data form database.
295
-
296
-If you want to register filter, use C<register_filter()> method.
291
+If you want to filter the value, you can do this. For example,
292
+L<Time::Piece> object to database date format, or reverse.
297 293
 
298 294
     $dbi->register_filter(
299
-        to_upper_case => sub {
300
-            my $value = shift;
301
-            return uc $value;
295
+        tp_to_date => sub {
296
+            return shift->strftime('%Y-%m-%d');
297
+        },
298
+        date_to_tp => sub {
299
+            return Time::Piece->strptime(shift, '%Y-%m-%d');
302 300
         }
303 301
     );
304 302
 
303
+In this example, L<Time::Piece> object is converted to 'yyyy-mm-dd' format
304
+, and reverse.
305
+
306
+You can apply this filter to use C<apply_filter()> method.
307
+
308
+    $dbi->apply_filter('book',
309
+        puplication_date => {out => 'tp_to_date', in => 'date_to_tp'},
310
+        someting_date => {out => 'tp_to_date', in => 'date_to_tp'}
311
+    );
312
+
313
+In this case, C<book>'s C<publication_date> is automatically converted.
314
+C<out> means Perl to Database, C<in> means Database to Perl.
305 315
 
316
+These applied filters have effect C<insert>, C<update>, C<update_all>,
317
+C<delete>, C<delete_all>, C<select>
306 318
 
307
-You can specify these filters to C<filter> argument of C<execute()> method.
319
+    my $tp = Time::Piece::localtime;
320
+    $dbi->insert(
321
+        table => 'book',
322
+        param => {name => 'Perl', publication_date => $tp}
323
+    );
324
+    
325
+    my $result = $dbi->select(table => 'book');
326
+    my $tp = $result->{publication_date};
327
+    
328
+
329
+Note that this has'nt C<execute> method by default.
330
+If you want to have effect C<execute()> method, use C<table>
331
+option.
308 332
 
309 333
     my $result = $dbi->execute(
310
-        "select * from book where {= author} and {like title};"
311
-        param  => {author => 'Ken', title => '%Perl%'},
312
-        filter => {author => 'to_upper_case, title => 'encode_utf8'}
334
+        "select * from book where {= id};",
335
+         param => {id => 5},
336
+         table => ['book']
313 337
     );
314 338
 
315
-C<filter> argument can be specified to suger methods, such as
316
-C<insert()>, C<update()>, C<update_all()>,
317
-C<delete()>, C<delete_all()>, C<select()>.
318 339
 
319
-    # insert(), having filter argument
320
-    $dbi->insert(table  => 'book',
321
-                 param  => {title => 'Perl', author => 'Ken'},
322
-                 filter => {title => 'encode_utf8'});
340
+You can also specify registered filters to C<filter> option of
341
+C<insert()>, C<update()>, C<update_all()>, C<delete()>, C<delete_all()>,
342
+C<select()> C<execute()>. This is overwirte applied filter.
323 343
     
324
-    # select(), having filter argument
325
-    my $result = $dbi->select(
326
-        table  => 'book',
327
-        column => [qw/author title/],
328
-        where  => {author => 'Ken'},
329
-        append => 'order by id limit 1',
330
-        filter => {title => 'encode_utf8'}
344
+    $dbi->insert(
345
+        table => 'book',
346
+        param => {name => 'Perl', publication_date => $tp},
347
+        filter => {publication_date => 'tp_to_date'}
331 348
     );
332 349
 
333
-You can also specify filter when the row is fetched. This is reverse of bind filter.
350
+You can also specify C<DBIx::Custom::Result> object.
351
+This is overwrite applied filter.
334 352
 
335 353
     my $result = $dbi->select(table => 'book');
336
-    $result->filter({title => 'decode_utf8', author => 'to_upper_case'});
354
+    $result->filter(publication_date => 'date_to_tp');
337 355
 
338 356
 B<Filter examples>
339 357
 
... ...
@@ -380,8 +398,50 @@ SQLite
380 398
     date_to_tp => sub {
381 399
         return Time::Piece->strptime(shift, $FORMATS->{db_date});
382 400
     }
383
-    
384
-=head2 6. Get high performance
401
+
402
+=head2 6.Create table object
403
+
404
+You can create table object which have methods.
405
+
406
+    $dbi->table('book');
407
+
408
+This class have C<insert()>, C<update()>, C<update_all()>,
409
+C<delete>, C<delete_all>, C<select().
410
+These is same as C<DBIx::Custom>'s methods except that 
411
+you don't have to specify table.
412
+
413
+    $dbi->table('book')->insert(
414
+        param => {author => 'Taro', name => 'Perl'}
415
+    );
416
+
417
+You can define method for table.
418
+
419
+    $dbi->table('book',
420
+        insert_multi => sub {
421
+            my $self = shift;
422
+            my $table = $self->name;
423
+            my $dbi = $self->dbi;
424
+            
425
+            # Do something
426
+        },
427
+        cross_summary => sub {
428
+            my $self = shift;
429
+            my $table = $self->name;
430
+            my $dbi = $self->dbi;
431
+            
432
+            # Do something
433
+        }
434
+    );
435
+
436
+Each method receive L<DBIx::Custom::Table> object as first argument.
437
+This class have C<name()> to get table name and C<dbi()>
438
+to get L<DBIx::Custom> object.
439
+
440
+Defined method is called from table class.
441
+
442
+    $dbi->table('book')->insert_multi(param => $param);
443
+
444
+=head2 7. Get high performance
385 445
 
386 446
 =head3 Use execute() method instead suger methods
387 447
 
... ...
@@ -418,7 +478,7 @@ Execute query repeatedly.
418 478
 
419 479
 This is faster than C<insert()> method.
420 480
 
421
-=head2 7. More features
481
+=head2 8. More features
422 482
 
423 483
 =head3 Get DBI object
424 484
 
+53 -6
lib/DBIx/Custom/Result.pm
... ...
@@ -25,19 +25,46 @@ sub filter {
25 25
             }
26 26
         }
27 27
         
28
-        $self->{filter} = {%{$self->filter || {}}, %$filter};
28
+        $self->{filter} = {%{$self->filter}, %$filter};
29 29
         
30 30
         return $self;
31 31
     }
32 32
     
33
-    return $self->{filter};
33
+    return $self->{filter} ||= {};
34
+}
35
+
36
+sub end_filter {
37
+    my $self = shift;
38
+    
39
+    if (@_) {
40
+        my $end_filter = ref $_[0] eq 'HASH' ? $_[0] : {@_};
41
+        
42
+        foreach my $column (keys %$end_filter) {
43
+            my $fname = $end_filter->{$column};
44
+            unless (ref $fname eq 'CODE') {
45
+              croak qq{"$fname" is not registered"}
46
+                unless exists $self->filters->{$fname};
47
+              
48
+              $end_filter->{$column} = $self->filters->{$fname};
49
+            }
50
+        }
51
+        
52
+        $self->{end_filter} = {%{$self->end_filter}, %$end_filter};
53
+        
54
+        return $self;
55
+    }
56
+    
57
+    return $self->{end_filter} ||= {};
34 58
 }
35 59
 
36 60
 sub fetch {
37 61
     my $self = shift;
38 62
     
39 63
     # Filter
40
-    my $filter  = $self->{filter}  || {};
64
+    my $filter = $self->filter;
65
+    
66
+    # End filter
67
+    my $end_filter = $self->end_filter;
41 68
     
42 69
     # Fetch
43 70
     my @row = $self->{sth}->fetchrow_array;
... ...
@@ -54,9 +81,11 @@ sub fetch {
54 81
         my $f  = exists $filter->{$column}
55 82
                ? $filter->{$column}
56 83
                : $self->default_filter;
84
+        my $ef = $end_filter->{$column};
57 85
         
58 86
         # Filtering
59 87
         $row[$i] = $f->($row[$i]) if $f;
88
+        $row[$i] = $ef->($row[$i]) if $ef;
60 89
     }
61 90
 
62 91
     return \@row;
... ...
@@ -92,7 +121,10 @@ sub fetch_hash {
92 121
     my $self = shift;
93 122
     
94 123
     # Filter
95
-    my $filter  = $self->filter  || {};
124
+    my $filter  = $self->filter;
125
+    
126
+    # End filter
127
+    my $end_filter = $self->end_filter;
96 128
     
97 129
     # Fetch
98 130
     my $row = $self->{sth}->fetchrow_arrayref;
... ...
@@ -110,9 +142,11 @@ sub fetch_hash {
110 142
         my $f  = exists $filter->{$column}
111 143
                ? $filter->{$column}
112 144
                : $self->default_filter;
145
+        my $ef = $end_filter->{$column};
113 146
         
114 147
         # Filtering
115 148
         $row_hash->{$column} = $f ? $f->($row->[$i]) : $row->[$i];
149
+        $row_hash->{$column} = $ef->($row_hash->{$column}) if $ef;
116 150
     }
117 151
     
118 152
     return $row_hash;
... ...
@@ -296,6 +330,15 @@ Statement handle of L<DBI>.
296 330
 L<DBIx::Custom::Result> inherits all methods from L<Object::Simple>
297 331
 and implements the following new ones.
298 332
 
333
+=head2 C<(experimental) end_filter>
334
+
335
+    $result    = $result->end_filter(title  => 'to_upper_case',
336
+                                     author => 'to_upper_case');
337
+
338
+End filters.
339
+These each filters is executed after the filters applied by C<apply_filter> of
340
+L<DBIx::Custom> or C<filter> method.
341
+
299 342
 =head2 C<fetch>
300 343
 
301 344
     my $row = $result->fetch;
... ...
@@ -348,8 +391,12 @@ Row count must be specified.
348 391
 
349 392
 =head2 C<filter>
350 393
 
351
-    $result    = $result->filter(title  => 'decode_utf8',
352
-                                 author => 'decode_utf8');
394
+    $result    = $result->filter(title  => 'to_upper_case',
395
+                                 author => 'to_upper_case');
396
+
397
+Filters.
398
+These each filters override the filters applied by C<apply_filter> of
399
+L<DBIx::Custom>.
353 400
 
354 401
 =head2 C<(deprecated) default_filter>
355 402
 
+1 -1
t/dbix-custom-core-mysql-private.t
... ...
@@ -34,7 +34,7 @@ use Scalar::Util 'blessed';
34 34
     );
35 35
     $dbi->connect;
36 36
     ok(!$dbi->dbh->{AutoCommit});
37
-    ok($dbi->dbh->{mysql_enable_utf8});
37
+    #ok($dbi->dbh->{mysql_enable_utf8});
38 38
 }
39 39
 
40 40
 sub connect_info {
+17
t/dbix-custom-core-sqlite.t
... ...
@@ -769,3 +769,20 @@ $dbi = MyDBI->new($NEW_ARGS->{0});
769 769
 $dbi->execute($CREATE_TABLE->{0});
770 770
 $dbi->insert(table => 'table1', param => {key1 => 1, key2 => 2});
771 771
 is($dbi->select(table => 'table1')->fetch_hash_first->{key1}, 1, $test);
772
+
773
+
774
+test 'end_filter';
775
+$dbi = DBIx::Custom->connect($NEW_ARGS->{0});
776
+$dbi->execute($CREATE_TABLE->{0});
777
+$dbi->insert(table => 'table1', param => {key1 => 1, key2 => 2});
778
+$result = $dbi->select(table => 'table1');
779
+$result->filter(key1 => sub { $_[0] * 2 }, key2 => sub { $_[0] * 4 });
780
+$result->end_filter(key1 => sub { $_[0] * 3 }, key2 => sub { $_[0] * 5 });
781
+$row = $result->fetch_first;
782
+is_deeply($row, [6, 40]);
783
+
784
+$result = $dbi->select(table => 'table1');
785
+$result->filter(key1 => sub { $_[0] * 2 }, key2 => sub { $_[0] * 4 });
786
+$result->end_filter(key1 => sub { $_[0] * 3 }, key2 => sub { $_[0] * 5 });
787
+$row = $result->fetch_hash_first;
788
+is_deeply($row, {key1 => 6, key2 => 40});
+20 -23
t/dbix-custom-result-sqlite.t
... ...
@@ -13,10 +13,7 @@ BEGIN {
13 13
     use_ok('DBIx::Custom::Result');
14 14
 }
15 15
 
16
-my $test;
17
-sub test {
18
-    $test = shift;
19
-}
16
+sub test { print "# $_[0]\n" }
20 17
 
21 18
 sub query {
22 19
     my ($dbh, $sql) = @_;
... ...
@@ -50,7 +47,7 @@ $result = query($dbh, $sql);
50 47
 while (my $row = $result->fetch) {
51 48
     push @rows, [@$row];
52 49
 }
53
-is_deeply(\@rows, [[1, 2], [3, 4]], $test);
50
+is_deeply(\@rows, [[1, 2], [3, 4]]);
54 51
 
55 52
 
56 53
 test 'fetch_hash';
... ...
@@ -59,28 +56,28 @@ $result = query($dbh, $sql);
59 56
 while (my $row = $result->fetch_hash) {
60 57
     push @rows, {%$row};
61 58
 }
62
-is_deeply(\@rows, [{key1 => 1, key2 => 2}, {key1 => 3, key2 => 4}], $test);
59
+is_deeply(\@rows, [{key1 => 1, key2 => 2}, {key1 => 3, key2 => 4}]);
63 60
 
64 61
 
65 62
 test 'fetch_first';
66 63
 $result = query($dbh, $sql);
67 64
 $row = $result->fetch_first;
68
-is_deeply($row, [1, 2], "$test : row");
65
+is_deeply($row, [1, 2], "row");
69 66
 $row = $result->fetch;
70
-ok(!$row, "$test : finished");
67
+ok(!$row, "finished");
71 68
 
72 69
 
73 70
 test 'fetch_hash_first';
74 71
 $result = query($dbh, $sql);
75 72
 $row = $result->fetch_hash_first;
76
-is_deeply($row, {key1 => 1, key2 => 2}, "$test : row");
73
+is_deeply($row, {key1 => 1, key2 => 2}, "row");
77 74
 $row = $result->fetch_hash;
78
-ok(!$row, "$test : finished");
75
+ok(!$row, "finished");
79 76
 
80 77
 $result = query($dbh, 'create table table2 (key1, key2);');
81 78
 $result = query($dbh, 'select * from table2');
82 79
 $row = $result->fetch_hash_first;
83
-ok(!$row, "$test : no row fetch");
80
+ok(!$row, "no row fetch");
84 81
 
85 82
 
86 83
 test 'fetch_multi';
... ...
@@ -90,12 +87,12 @@ $dbh->do("insert into table1 (key1, key2) values ('9', '10');");
90 87
 $result = query($dbh, $sql);
91 88
 $rows = $result->fetch_multi(2);
92 89
 is_deeply($rows, [[1, 2],
93
-                  [3, 4]], "$test : fetch_multi first");
90
+                  [3, 4]], "fetch_multi first");
94 91
 $rows = $result->fetch_multi(2);
95 92
 is_deeply($rows, [[5, 6],
96
-                  [7, 8]], "$test : fetch_multi secound");
93
+                  [7, 8]], "fetch_multi secound");
97 94
 $rows = $result->fetch_multi(2);
98
-is_deeply($rows, [[9, 10]], "$test : fetch_multi third");
95
+is_deeply($rows, [[9, 10]], "fetch_multi third");
99 96
 $rows = $result->fetch_multi(2);
100 97
 ok(!$rows);
101 98
 
... ...
@@ -103,19 +100,19 @@ ok(!$rows);
103 100
 test 'fetch_multi error';
104 101
 $result = query($dbh, $sql);
105 102
 eval {$result->fetch_multi};
106
-like($@, qr/Row count must be specified/, "$test : Not specified row count");
103
+like($@, qr/Row count must be specified/, "Not specified row count");
107 104
 
108 105
 
109 106
 test 'fetch_hash_multi';
110 107
 $result = query($dbh, $sql);
111 108
 $rows = $result->fetch_hash_multi(2);
112 109
 is_deeply($rows, [{key1 => 1, key2 => 2},
113
-                  {key1 => 3, key2 => 4}], "$test : fetch_multi first");
110
+                  {key1 => 3, key2 => 4}], "fetch_multi first");
114 111
 $rows = $result->fetch_hash_multi(2);
115 112
 is_deeply($rows, [{key1 => 5, key2 => 6},
116
-                  {key1 => 7, key2 => 8}], "$test : fetch_multi secound");
113
+                  {key1 => 7, key2 => 8}], "fetch_multi secound");
117 114
 $rows = $result->fetch_hash_multi(2);
118
-is_deeply($rows, [{key1 => 9, key2 => 10}], "$test : fetch_multi third");
115
+is_deeply($rows, [{key1 => 9, key2 => 10}], "fetch_multi third");
119 116
 $rows = $result->fetch_hash_multi(2);
120 117
 ok(!$rows);
121 118
 
... ...
@@ -123,7 +120,7 @@ ok(!$rows);
123 120
 test 'fetch_multi error';
124 121
 $result = query($dbh, $sql);
125 122
 eval {$result->fetch_hash_multi};
126
-like($@, qr/Row count must be specified/, "$test : Not specified row count");
123
+like($@, qr/Row count must be specified/, "Not specified row count");
127 124
 
128 125
 $dbh->do('delete from table1');
129 126
 $dbh->do("insert into table1 (key1, key2) values ('1', '2');");
... ...
@@ -132,12 +129,12 @@ $dbh->do("insert into table1 (key1, key2) values ('3', '4');");
132 129
 test 'fetch_all';
133 130
 $result = query($dbh, $sql);
134 131
 $rows = $result->fetch_all;
135
-is_deeply($rows, [[1, 2], [3, 4]], $test);
132
+is_deeply($rows, [[1, 2], [3, 4]]);
136 133
 
137 134
 test 'fetch_hash_all';
138 135
 $result = query($dbh, $sql);
139 136
 $rows = $result->fetch_hash_all;
140
-is_deeply($rows, [{key1 => 1, key2 => 2}, {key1 => 3, key2 => 4}], $test);
137
+is_deeply($rows, [{key1 => 1, key2 => 2}, {key1 => 3, key2 => 4}]);
141 138
 
142 139
 
143 140
 test 'fetch filter';
... ...
@@ -146,11 +143,11 @@ $result->filters({three_times => sub { $_[0] * 3}});
146 143
 $result->filter({key1 => 'three_times'});
147 144
 
148 145
 $rows = $result->fetch_all;
149
-is_deeply($rows, [[3, 2], [9, 4]], "$test array");
146
+is_deeply($rows, [[3, 2], [9, 4]], "array");
150 147
 
151 148
 $result = query($dbh, $sql);
152 149
 $result->filters({three_times => sub { $_[0] * 3}});
153 150
 $result->filter({key1 => 'three_times'});
154 151
 $rows = $result->fetch_hash_all;
155
-is_deeply($rows, [{key1 => 3, key2 => 2}, {key1 => 9, key2 => 4}], "$test hash");
152
+is_deeply($rows, [{key1 => 3, key2 => 2}, {key1 => 9, key2 => 4}], "hash");
156 153