DBIx-Custom / lib / DBIx / Custom.pm /
Newer Older
969 lines | 23.756kb
cleanup
yuki-kimoto authored on 2009-12-22
1
package DBIx::Custom;
2

            
3
use strict;
4
use warnings;
5

            
remove run_transaction().
yuki-kimoto authored on 2010-01-30
6
use base 'Object::Simple';
many change
yuki-kimoto authored on 2010-02-11
7

            
packaging one directory
yuki-kimoto authored on 2009-11-16
8
use Carp 'croak';
9
use DBI;
10
use DBIx::Custom::Result;
many many changes
yuki-kimoto authored on 2010-04-30
11
use DBIx::Custom::SQLTemplate;
cleanup
yuki-kimoto authored on 2010-02-11
12
use DBIx::Custom::Query;
update document
yuki-kimoto authored on 2010-05-27
13
use Encode qw/encode_utf8 decode_utf8/;
packaging one directory
yuki-kimoto authored on 2009-11-16
14

            
catch up with Object::Simple...
yuki-kimoto authored on 2010-01-18
15
__PACKAGE__->attr('dbh');
cleanup
yuki-kimoto authored on 2010-04-28
16
__PACKAGE__->attr([qw/user password data_source/]);
update document
yuki-kimoto authored on 2010-05-27
17
__PACKAGE__->attr([qw/default_query_filter default_fetch_filter/]);
packaging one directory
yuki-kimoto authored on 2009-11-16
18

            
removed register_format()
yuki-kimoto authored on 2010-05-26
19
__PACKAGE__->dual_attr('filters', default => sub { {} },
20
                                  inherit => 'hash_copy');
21
__PACKAGE__->register_filter(
update document
yuki-kimoto authored on 2010-05-27
22
    encode_utf8 => sub { encode_utf8($_[0]) },
23
    decode_utf8 => sub { decode_utf8($_[0]) }
removed register_format()
yuki-kimoto authored on 2010-05-26
24
);
packaging one directory
yuki-kimoto authored on 2009-11-16
25

            
cleanup
yuki-kimoto authored on 2010-04-28
26
__PACKAGE__->attr(result_class => 'DBIx::Custom::Result');
removed register_format()
yuki-kimoto authored on 2010-05-26
27
__PACKAGE__->attr(sql_template => sub { DBIx::Custom::SQLTemplate->new });
28

            
packaging one directory
yuki-kimoto authored on 2009-11-16
29
sub connect {
removed register_format()
yuki-kimoto authored on 2010-05-26
30
    my $proto = shift;
31
    
32
    # Create
33
    my $self = ref $proto ? $proto : $proto->new(@_);
update document
yuki-kimoto authored on 2010-01-30
34
    
35
    # Information
packaging one directory
yuki-kimoto authored on 2009-11-16
36
    my $data_source = $self->data_source;
37
    my $user        = $self->user;
38
    my $password    = $self->password;
39
    
update document
yuki-kimoto authored on 2010-01-30
40
    # Connect
packaging one directory
yuki-kimoto authored on 2009-11-16
41
    my $dbh = eval{DBI->connect(
42
        $data_source,
43
        $user,
44
        $password,
45
        {
46
            RaiseError => 1,
47
            PrintError => 0,
48
            AutoCommit => 1,
49
        }
50
    )};
51
    
update document
yuki-kimoto authored on 2010-01-30
52
    # Connect error
packaging one directory
yuki-kimoto authored on 2009-11-16
53
    croak $@ if $@;
54
    
update document
yuki-kimoto authored on 2010-01-30
55
    # Database handle
packaging one directory
yuki-kimoto authored on 2009-11-16
56
    $self->dbh($dbh);
update document
yuki-kimoto authored on 2010-01-30
57
    
packaging one directory
yuki-kimoto authored on 2009-11-16
58
    return $self;
59
}
60

            
61
sub disconnect {
62
    my $self = shift;
update document
yuki-kimoto authored on 2010-01-30
63
    
removed reconnect method
yuki-kimoto authored on 2010-05-28
64
    # Disconnect
65
    $self->dbh->disconnect;
66
    $self->dbh(undef);
update document
yuki-kimoto authored on 2010-01-30
67
    
68
    return $self;
packaging one directory
yuki-kimoto authored on 2009-11-16
69
}
70

            
removed register_format()
yuki-kimoto authored on 2010-05-26
71
our %VALID_INSERT_ARGS = map { $_ => 1 } qw/table param append filter/;
cleanup insert
yuki-kimoto authored on 2010-04-28
72

            
packaging one directory
yuki-kimoto authored on 2009-11-16
73
sub insert {
removed register_format()
yuki-kimoto authored on 2010-05-26
74
    my $self = shift;
cleanup insert
yuki-kimoto authored on 2010-04-28
75
    
76
    # Arguments
removed register_format()
yuki-kimoto authored on 2010-05-26
77
    my $args = ref $_[0] eq 'HASH' ? $_[0] : {@_};
78

            
cleanup insert
yuki-kimoto authored on 2010-04-28
79
    # Check arguments
80
    foreach my $name (keys %$args) {
81
        croak "\"$name\" is invalid name"
82
          unless $VALID_INSERT_ARGS{$name};
83
    }
84
    
removed register_format()
yuki-kimoto authored on 2010-05-26
85
    # Arguments
86
    my $table  = $args->{table} || '';
87
    my $param  = $args->{param} || {};
88
    my $append = $args->{append} || '';
89
    my $filter = $args->{filter};
packaging one directory
yuki-kimoto authored on 2009-11-16
90
    
91
    # Insert keys
removed register_format()
yuki-kimoto authored on 2010-05-26
92
    my @insert_keys = keys %$param;
packaging one directory
yuki-kimoto authored on 2009-11-16
93
    
94
    # Not exists insert keys
95
    croak("Key-value pairs for insert must be specified to 'insert' second argument")
96
      unless @insert_keys;
97
    
98
    # Templte for insert
99
    my $template = "insert into $table {insert " . join(' ', @insert_keys) . '}';
removed register_format()
yuki-kimoto authored on 2010-05-26
100
    $template .= " $append" if $append;
packaging one directory
yuki-kimoto authored on 2009-11-16
101
    
102
    # Execute query
removed register_format()
yuki-kimoto authored on 2010-05-26
103
    my $ret_val = $self->execute($template, param  => $param, 
104
                                            filter => $filter);
packaging one directory
yuki-kimoto authored on 2009-11-16
105
    
106
    return $ret_val;
107
}
108

            
cleanup update and update_al...
yuki-kimoto authored on 2010-04-28
109
our %VALID_UPDATE_ARGS
removed register_format()
yuki-kimoto authored on 2010-05-26
110
  = map { $_ => 1 } qw/table param where append filter allow_update_all/;
cleanup update and update_al...
yuki-kimoto authored on 2010-04-28
111

            
packaging one directory
yuki-kimoto authored on 2009-11-16
112
sub update {
removed register_format()
yuki-kimoto authored on 2010-05-26
113
    my $self = shift;
114

            
115
    my $args = ref $_[0] eq 'HASH' ? $_[0] : {@_};
cleanup update and update_al...
yuki-kimoto authored on 2010-04-28
116
    
117
    # Check arguments
118
    foreach my $name (keys %$args) {
119
        croak "\"$name\" is invalid name"
120
          unless $VALID_UPDATE_ARGS{$name};
121
    }
122
    
123
    # Arguments
removed register_format()
yuki-kimoto authored on 2010-05-26
124
    my $table            = $args->{table} || '';
125
    my $param            = $args->{param} || {};
126
    my $where            = $args->{where} || {};
cleanup update and update_al...
yuki-kimoto authored on 2010-04-28
127
    my $append_statement = $args->{append} || '';
many many changes
yuki-kimoto authored on 2010-04-30
128
    my $filter           = $args->{filter};
cleanup update and update_al...
yuki-kimoto authored on 2010-04-28
129
    my $allow_update_all = $args->{allow_update_all};
packaging one directory
yuki-kimoto authored on 2009-11-16
130
    
131
    # Update keys
removed register_format()
yuki-kimoto authored on 2010-05-26
132
    my @update_keys = keys %$param;
packaging one directory
yuki-kimoto authored on 2009-11-16
133
    
134
    # Not exists update kyes
135
    croak("Key-value pairs for update must be specified to 'update' second argument")
136
      unless @update_keys;
137
    
138
    # Where keys
removed register_format()
yuki-kimoto authored on 2010-05-26
139
    my @where_keys = keys %$where;
packaging one directory
yuki-kimoto authored on 2009-11-16
140
    
141
    # Not exists where keys
142
    croak("Key-value pairs for where clause must be specified to 'update' third argument")
cleanup update and update_al...
yuki-kimoto authored on 2010-04-28
143
      if !@where_keys && !$allow_update_all;
packaging one directory
yuki-kimoto authored on 2009-11-16
144
    
145
    # Update clause
146
    my $update_clause = '{update ' . join(' ', @update_keys) . '}';
147
    
148
    # Where clause
149
    my $where_clause = '';
simplify filtering system
yuki-kimoto authored on 2010-05-01
150
    my $new_where = {};
many change
yuki-kimoto authored on 2010-04-30
151
    
packaging one directory
yuki-kimoto authored on 2009-11-16
152
    if (@where_keys) {
153
        $where_clause = 'where ';
154
        foreach my $where_key (@where_keys) {
simplify filtering system
yuki-kimoto authored on 2010-05-01
155
            
156
            $where_clause .= "{= $where_key} and ";
packaging one directory
yuki-kimoto authored on 2009-11-16
157
        }
158
        $where_clause =~ s/ and $//;
159
    }
160
    
161
    # Template for update
162
    my $template = "update $table $update_clause $where_clause";
insert, update, delete appnd...
yuki-kimoto authored on 2009-11-16
163
    $template .= " $append_statement" if $append_statement;
packaging one directory
yuki-kimoto authored on 2009-11-16
164
    
165
    # Rearrange parammeters
removed register_format()
yuki-kimoto authored on 2010-05-26
166
    foreach my $wkey (@where_keys) {
simplify filtering system
yuki-kimoto authored on 2010-05-01
167
        
removed register_format()
yuki-kimoto authored on 2010-05-26
168
        if (exists $param->{$wkey}) {
169
            $param->{$wkey} = [$param->{$wkey}]
170
              unless ref $param->{$wkey} eq 'ARRAY';
simplify filtering system
yuki-kimoto authored on 2010-05-01
171
            
removed register_format()
yuki-kimoto authored on 2010-05-26
172
            push @{$param->{$wkey}}, $where->{$wkey};
simplify filtering system
yuki-kimoto authored on 2010-05-01
173
        }
add tests
yuki-kimoto authored on 2010-05-01
174
        else {
removed register_format()
yuki-kimoto authored on 2010-05-26
175
            $param->{$wkey} = $where->{$wkey};
add tests
yuki-kimoto authored on 2010-05-01
176
        }
simplify filtering system
yuki-kimoto authored on 2010-05-01
177
    }
packaging one directory
yuki-kimoto authored on 2009-11-16
178
    
179
    # Execute query
removed register_format()
yuki-kimoto authored on 2010-05-26
180
    my $ret_val = $self->execute($template, param  => $param, 
181
                                            filter => $filter);
packaging one directory
yuki-kimoto authored on 2009-11-16
182
    
183
    return $ret_val;
184
}
185

            
186
sub update_all {
removed register_format()
yuki-kimoto authored on 2010-05-26
187
    my $self = shift;;
cleanup update and update_al...
yuki-kimoto authored on 2010-04-28
188
    
removed register_format()
yuki-kimoto authored on 2010-05-26
189
    # Arguments
190
    my $args = ref $_[0] eq 'HASH' ? $_[0] : {@_};
191
        
refactoring select
yuki-kimoto authored on 2010-04-28
192
    # Allow all update
cleanup update and update_al...
yuki-kimoto authored on 2010-04-28
193
    $args->{allow_update_all} = 1;
insert, update, delete appnd...
yuki-kimoto authored on 2009-11-16
194
    
update document
yuki-kimoto authored on 2010-01-30
195
    # Update all rows
removed register_format()
yuki-kimoto authored on 2010-05-26
196
    return $self->update($args);
packaging one directory
yuki-kimoto authored on 2009-11-16
197
}
198

            
refactoring delete and delet...
yuki-kimoto authored on 2010-04-28
199
our %VALID_DELETE_ARGS
removed register_format()
yuki-kimoto authored on 2010-05-26
200
  = map { $_ => 1 } qw/table where append filter allow_delete_all/;
refactoring delete and delet...
yuki-kimoto authored on 2010-04-28
201

            
packaging one directory
yuki-kimoto authored on 2009-11-16
202
sub delete {
removed register_format()
yuki-kimoto authored on 2010-05-26
203
    my $self = shift;
204
    
205
    # Arguments
206
    my $args = ref $_[0] eq 'HASH' ? $_[0] : {@_};
refactoring delete and delet...
yuki-kimoto authored on 2010-04-28
207
    
208
    # Check arguments
209
    foreach my $name (keys %$args) {
210
        croak "\"$name\" is invalid name"
211
          unless $VALID_DELETE_ARGS{$name};
212
    }
213
    
214
    # Arguments
removed register_format()
yuki-kimoto authored on 2010-05-26
215
    my $table            = $args->{table} || '';
216
    my $where            = $args->{where} || {};
refactoring delete and delet...
yuki-kimoto authored on 2010-04-28
217
    my $append_statement = $args->{append};
removed register_format()
yuki-kimoto authored on 2010-05-26
218
    my $filter           = $args->{filter};
refactoring delete and delet...
yuki-kimoto authored on 2010-04-28
219
    my $allow_delete_all = $args->{allow_delete_all};
packaging one directory
yuki-kimoto authored on 2009-11-16
220
    
221
    # Where keys
removed register_format()
yuki-kimoto authored on 2010-05-26
222
    my @where_keys = keys %$where;
packaging one directory
yuki-kimoto authored on 2009-11-16
223
    
224
    # Not exists where keys
225
    croak("Key-value pairs for where clause must be specified to 'delete' second argument")
refactoring delete and delet...
yuki-kimoto authored on 2010-04-28
226
      if !@where_keys && !$allow_delete_all;
packaging one directory
yuki-kimoto authored on 2009-11-16
227
    
228
    # Where clause
229
    my $where_clause = '';
230
    if (@where_keys) {
231
        $where_clause = 'where ';
removed register_format()
yuki-kimoto authored on 2010-05-26
232
        foreach my $wkey (@where_keys) {
233
            $where_clause .= "{= $wkey} and ";
packaging one directory
yuki-kimoto authored on 2009-11-16
234
        }
235
        $where_clause =~ s/ and $//;
236
    }
237
    
238
    # Template for delete
239
    my $template = "delete from $table $where_clause";
insert, update, delete appnd...
yuki-kimoto authored on 2009-11-16
240
    $template .= " $append_statement" if $append_statement;
packaging one directory
yuki-kimoto authored on 2009-11-16
241
    
242
    # Execute query
removed register_format()
yuki-kimoto authored on 2010-05-26
243
    my $ret_val = $self->execute($template, param  => $where, 
244
                                            filter => $filter);
packaging one directory
yuki-kimoto authored on 2009-11-16
245
    
246
    return $ret_val;
247
}
248

            
249
sub delete_all {
removed register_format()
yuki-kimoto authored on 2010-05-26
250
    my $self = shift;
251
    
252
    # Arguments
253
    my $args = ref $_[0] eq 'HASH' ? $_[0] : {@_};
refactoring delete and delet...
yuki-kimoto authored on 2010-04-28
254
    
refactoring select
yuki-kimoto authored on 2010-04-28
255
    # Allow all delete
refactoring delete and delet...
yuki-kimoto authored on 2010-04-28
256
    $args->{allow_delete_all} = 1;
insert, update, delete appnd...
yuki-kimoto authored on 2009-11-16
257
    
update document
yuki-kimoto authored on 2010-01-30
258
    # Delete all rows
removed register_format()
yuki-kimoto authored on 2010-05-26
259
    return $self->delete($args);
packaging one directory
yuki-kimoto authored on 2009-11-16
260
}
261

            
refactoring select
yuki-kimoto authored on 2010-04-28
262
our %VALID_SELECT_ARGS
added commit method
yuki-kimoto authored on 2010-05-27
263
  = map { $_ => 1 } qw/table column where append relation filter param/;
refactoring select
yuki-kimoto authored on 2010-04-28
264

            
packaging one directory
yuki-kimoto authored on 2009-11-16
265
sub select {
removed register_format()
yuki-kimoto authored on 2010-05-26
266
    my $self = shift;;
packaging one directory
yuki-kimoto authored on 2009-11-16
267
    
removed register_format()
yuki-kimoto authored on 2010-05-26
268
    my $args = ref $_[0] eq 'HASH' ? $_[0] : {@_};
packaging one directory
yuki-kimoto authored on 2009-11-16
269
    
refactoring select
yuki-kimoto authored on 2010-04-28
270
    # Check arguments
271
    foreach my $name (keys %$args) {
272
        croak "\"$name\" is invalid name"
273
          unless $VALID_SELECT_ARGS{$name};
274
    }
packaging one directory
yuki-kimoto authored on 2009-11-16
275
    
refactoring select
yuki-kimoto authored on 2010-04-28
276
    # Arguments
removed register_format()
yuki-kimoto authored on 2010-05-26
277
    my $tables = $args->{table} || [];
278
    $tables = [$tables] unless ref $tables eq 'ARRAY';
added commit method
yuki-kimoto authored on 2010-05-27
279
    my $columns  = $args->{column} || [];
280
    my $where    = $args->{where} || {};
281
    my $relation = $args->{relation};
282
    my $append   = $args->{append};
283
    my $filter   = $args->{filter};
284
    my $param    = $args->{param} || {};
packaging one directory
yuki-kimoto authored on 2009-11-16
285
    
286
    # SQL template for select statement
287
    my $template = 'select ';
288
    
added commit method
yuki-kimoto authored on 2010-05-27
289
    # Column clause
packaging one directory
yuki-kimoto authored on 2009-11-16
290
    if (@$columns) {
291
        foreach my $column (@$columns) {
292
            $template .= "$column, ";
293
        }
294
        $template =~ s/, $/ /;
295
    }
296
    else {
297
        $template .= '* ';
298
    }
299
    
added commit method
yuki-kimoto authored on 2010-05-27
300
    # Table
packaging one directory
yuki-kimoto authored on 2009-11-16
301
    $template .= 'from ';
302
    foreach my $table (@$tables) {
303
        $template .= "$table, ";
304
    }
305
    $template =~ s/, $/ /;
306
    
added commit method
yuki-kimoto authored on 2010-05-27
307
    # Where clause
308
    my @where_keys = keys %$where;
packaging one directory
yuki-kimoto authored on 2009-11-16
309
    if (@where_keys) {
310
        $template .= 'where ';
311
        foreach my $where_key (@where_keys) {
compile success
yuki-kimoto authored on 2010-05-01
312
            $template .= "{= $where_key} and ";
packaging one directory
yuki-kimoto authored on 2009-11-16
313
        }
314
    }
315
    $template =~ s/ and $//;
316
    
added commit method
yuki-kimoto authored on 2010-05-27
317
    # Relation
318
    if ($relation) {
319
        $template .= @where_keys ? "and " : "where ";
320
        foreach my $rkey (keys %$relation) {
321
            $template .= "$rkey = " . $relation->{$rkey} . " and ";
packaging one directory
yuki-kimoto authored on 2009-11-16
322
        }
323
    }
added commit method
yuki-kimoto authored on 2010-05-27
324
    $template =~ s/ and $//;
325
    
326
    # Append some statement
327
    $template .= " $append" if $append;
packaging one directory
yuki-kimoto authored on 2009-11-16
328
    
329
    # Execute query
added commit method
yuki-kimoto authored on 2010-05-27
330
    my $result = $self->execute($template, param  => $where, 
removed register_format()
yuki-kimoto authored on 2010-05-26
331
                                           filter => $filter);
packaging one directory
yuki-kimoto authored on 2009-11-16
332
    
333
    return $result;
334
}
335

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
336
sub create_query {
337
    my ($self, $template) = @_;
version 0.0901
yuki-kimoto authored on 2009-12-17
338
    
removed reconnect method
yuki-kimoto authored on 2010-05-28
339
    # Create query from SQL template
340
    my $sql_template = $self->sql_template;
removed register_format()
yuki-kimoto authored on 2010-05-26
341
    
removed reconnect method
yuki-kimoto authored on 2010-05-28
342
    # Get cached query
343
    my $cache = $self->{_cache}->{$template};
version 0.0901
yuki-kimoto authored on 2009-12-17
344
    
removed reconnect method
yuki-kimoto authored on 2010-05-28
345
    # Create query
346
    my $query;
347
    if ($cache) {
348
        $query = DBIx::Custom::Query->new(
349
            sql       => $cache->sql,
350
            columns   => $cache->columns
351
        );
352
    }
353
    else {
354
        $query = eval{$sql_template->create_query($template)};
355
        croak($@) if $@;
356
        
357
        $self->{_cache}->{$template} = $query
358
          unless $self->{_cache}->{$template};
359
    }
version 0.0901
yuki-kimoto authored on 2009-12-17
360
    
removed reconnect method
yuki-kimoto authored on 2010-05-28
361
    # Prepare statement handle
362
    my $sth = $self->dbh->prepare($query->{sql});
renamed fetch_rows to fetch_...
yuki-kimoto authored on 2010-05-01
363
    
removed reconnect method
yuki-kimoto authored on 2010-05-28
364
    # Set statement handle
365
    $query->sth($sth);
366
    
367
    return $query;
368
}
369

            
370
our %VALID_EXECUTE_ARGS = map { $_ => 1 } qw/param filter/;
371

            
372
sub execute{
373
    my $self  = shift;
374
    my $query = shift;
375
    
376
    # Arguments
377
    my $args = ref $_[0] eq 'HASH' ? $_[0] : {@_};
378
    
379
    # Check arguments
380
    foreach my $name (keys %$args) {
381
        croak "\"$name\" is invalid name"
382
          unless $VALID_EXECUTE_ARGS{$name};
383
    }
384
    
385
    my $params = $args->{param} || {};
386
    
387
    # First argument is SQL template
388
    unless (ref $query eq 'DBIx::Custom::Query') {
389
        my $template;
390
        
391
        if (ref $query eq 'ARRAY') {
392
            $template = $query->[0];
393
        }
394
        else { $template = $query }
395
        
396
        $query = $self->create_query($template);
397
    }
398
    
399
    my $filter = $args->{filter} || $query->filter || {};
400
    
401
    # Create bind value
402
    my $bind_values = $self->_build_bind_values($query, $params, $filter);
403
    
404
    # Execute
405
    my $sth      = $query->sth;
406
    my $affected = eval{$sth->execute(@$bind_values)};
407
    
408
    # Execute error
409
    if (my $execute_error = $@) {
410
        require Data::Dumper;
411
        my $sql              = $query->{sql} || '';
412
        my $params_dump      = Data::Dumper->Dump([$params], ['*params']);
413
        
414
        croak("$execute_error" . 
415
              "<Your SQL>\n$sql\n" . 
416
              "<Your parameters>\n$params_dump");
417
    }
418
    
419
    # Return resultset if select statement is executed
420
    if ($sth->{NUM_OF_FIELDS}) {
421
        
422
        # Get result class
423
        my $result_class = $self->result_class;
424
        
425
        # Create result
426
        my $result = $result_class->new({
427
            sth             => $sth,
428
            default_filter  => $self->default_fetch_filter,
429
            filters         => $self->filters
430
        });
431
        return $result;
432
    }
433
    return $affected;
434
}
435

            
436
sub _build_bind_values {
437
    my ($self, $query, $params, $filter) = @_;
438
    
439
    # binding values
440
    my @bind_values;
441
    
442
    # Build bind values
443
    my $count = {};
444
    foreach my $column (@{$query->columns}) {
445
        
446
        croak "\"$column\" is not exists in params"
447
          unless exists $params->{$column};
448
        
449
        # Value
450
        my $value = ref $params->{$column} eq 'ARRAY'
451
                  ? $params->{$column}->[$count->{$column} || 0]
452
                  : $params->{$column};
453
        
454
        # Filter
455
        $filter ||= {};
456
        
457
        # Filter name
458
        my $fname = $filter->{$column} || $self->default_query_filter || '';
459
        
460
        my $filter_func;
461
        if ($fname) {
462
            
463
            if (ref $fname eq 'CODE') {
464
                $filter_func = $fname;
465
            }
466
            else {
467
                my $filters = $self->filters;
468
                croak "Not exists filter \"$fname\"" unless exists $filters->{$fname};
469
                $filter_func = $filters->{$fname};
470
            }            
471
        }
472
        
473
        push @bind_values, $filter_func
474
                         ? $filter_func->($value)
475
                         : $value;
476
        
477
        # Count up 
478
        $count->{$column}++;
479
    }
480
    
481
    return \@bind_values;
482
}
483

            
484
sub register_filter {
485
    my $invocant = shift;
486
    
487
    # Add filter
488
    my $filters = ref $_[0] eq 'HASH' ? $_[0] : {@_};
489
    $invocant->filters({%{$invocant->filters}, %$filters});
490
    
491
    return $invocant;
492
}
493

            
494
sub auto_commit {
495
    my $self = shift;
496
    
497
    if (@_) {
498
        
499
        # Set AutoCommit
500
        $self->dbh->{AutoCommit} = $_[0];
501
        
502
        return $self;
503
    }
504
    return $self->dbh->{AutoCommit};
505
}
506

            
507
sub commit   { shift->dbh->commit }
508
sub rollback { shift->dbh->rollback }
509

            
510
sub DESTROY {
511
    my $self = shift;
512
    
513
    # Disconnect
514
    $self->disconnect if $self->dbh;
515
}
516

            
517
=head1 NAME
518

            
519
DBIx::Custom - DBI with hash parameter binding and filtering system
520

            
521
=head1 VERSION
522

            
523
Version 0.1503
524

            
525
=cut
526

            
527
our $VERSION = '0.1503';
528
$VERSION = eval $VERSION;
529

            
530
=head1 STABILITY
531

            
532
This module is not stable. Method name and functionality will be change.
533

            
534
=head1 SYNOPSYS
535
    
536
    # Connect
537
    my $dbi = DBIx::Custom->connect(data_source => "dbi:mysql:database=books",
538
                                    user => 'ken', password => '!LFKD%$&');
539
    
540
    # Disconnect
541
    $dbi->disconnect
542

            
543
    # Insert 
544
    $dbi->insert(table  => 'books',
545
                 param  => {title => 'perl', author => 'Ken'},
546
                 filter => {title => 'encode_utf8'});
547
    
548
    # Update 
549
    $dbi->update(table  => 'books', 
550
                 param  => {title => 'aaa', author => 'Ken'}, 
551
                 where  => {id => 5},
552
                 filter => {title => 'encode_utf8'});
553
    
554
    # Update all
555
    $dbi->update_all(table  => 'books',
556
                     param  => {title => 'aaa'},
557
                     filter => {title => 'encode_utf8'});
558
    
559
    # Delete
560
    $dbi->delete(table  => 'books',
561
                 where  => {author => 'Ken'},
562
                 filter => {title => 'encode_utf8'});
563
    
564
    # Delete all
565
    $dbi->delete_all(table => 'books');
566
    
567
    # Select
568
    my $result = $dbi->select(table => 'books');
renamed fetch_rows to fetch_...
yuki-kimoto authored on 2010-05-01
569
    
removed register_format()
yuki-kimoto authored on 2010-05-26
570
    # Select(more complex)
renamed fetch_rows to fetch_...
yuki-kimoto authored on 2010-05-01
571
    my $result = $dbi->select(
update document
yuki-kimoto authored on 2010-05-27
572
        table  => 'books',
573
        column => [qw/author title/],
574
        where  => {author => 'Ken'},
575
        append => 'order by id limit 1',
576
        filter => {tilte => 'encode_utf8'}
renamed fetch_rows to fetch_...
yuki-kimoto authored on 2010-05-01
577
    );
added commit method
yuki-kimoto authored on 2010-05-27
578
    
579
    # Select(Join table)
580
    my $result = $dbi->select(
581
        table => ['books', 'rental'],
582
        column => ['books.name as book_name']
583
        relation => {'books.id' => 'rental.book_id'}
584
    );
removed reconnect method
yuki-kimoto authored on 2010-05-28
585
    
removed register_format()
yuki-kimoto authored on 2010-05-26
586
    # Execute SQL
587
    $dbi->execute("select title from books");
588
    
589
    # Execute SQL with parameters and filter
590
    $dbi->execute("select id from books where {= author} && {like title}",
591
                  param  => {author => 'ken', title => '%Perl%'},
592
                  filter => {tilte => 'encode_utf8'});
removed reconnect method
yuki-kimoto authored on 2010-05-28
593

            
594
    # Create query and execute it
595
    my $query = $dbi->create_query(
596
        "select id from books where {= author} && {like title}"
597
    );
598
    $dbi->execute($query, param => {author => 'ken', title => '%Perl%'})
removed register_format()
yuki-kimoto authored on 2010-05-26
599
    
600
    # Default filter
601
    $dbi->default_query_filter('encode_utf8');
602
    $dbi->default_fetch_filter('decode_utf8');
603
    
604
    # Fetch
605
    while (my $row = $result->fetch) {
606
        # ...
607
    }
608
    
609
    # Fetch hash
610
    while (my $row = $result->fetch_hash) {
611
        
612
    }
613
    
update document
yuki-kimoto authored on 2010-05-27
614
    # DBI instance
615
    my $dbh = $dbi->dbh;
removed reconnect method
yuki-kimoto authored on 2010-05-28
616

            
617
=head1 DESCRIPTION
618

            
619
L<DBIx::Custom> is useful L<DBI> extention.
620
This module have hash parameter binding and filtering system.
621

            
622
Normally, binding parameter is array.
623
L<DBIx::Custom> enable you to pass binding parameter as hash.
624

            
625
This module also provide filtering system.
626
You can filter the binding parameter
627
or the value of fetching row.
628

            
629
And have useful method such as insert(), update(), delete(), and select().
630

            
631
=head2 Features
632

            
633
=over 4
634

            
635
=item 1. Hash parameter binding.
636

            
637
=item 2. Value filtering.
638

            
639
=item 3. Useful methos such as insert(), update(), delete(), and select().
640

            
641
=back
642

            
update document
yuki-kimoto authored on 2010-01-30
643
=head1 ATTRIBUTES
packaging one directory
yuki-kimoto authored on 2009-11-16
644

            
645
=head2 user
646

            
update document
yuki-kimoto authored on 2010-05-27
647
Database user name.
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
648
    
version 0.0901
yuki-kimoto authored on 2009-12-17
649
    $dbi  = $dbi->user('Ken');
650
    $user = $dbi->user;
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
651
    
packaging one directory
yuki-kimoto authored on 2009-11-16
652
=head2 password
653

            
update document
yuki-kimoto authored on 2010-05-27
654
Database password.
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
655
    
version 0.0901
yuki-kimoto authored on 2009-12-17
656
    $dbi      = $dbi->password('lkj&le`@s');
657
    $password = $dbi->password;
packaging one directory
yuki-kimoto authored on 2009-11-16
658

            
659
=head2 data_source
660

            
update document
yuki-kimoto authored on 2010-05-27
661
Database data source.
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
662
    
version 0.0901
yuki-kimoto authored on 2009-12-17
663
    $dbi         = $dbi->data_source("dbi:mysql:dbname=$database");
664
    $data_source = $dbi->data_source;
packaging one directory
yuki-kimoto authored on 2009-11-16
665
    
removed reconnect method
yuki-kimoto authored on 2010-05-28
666
=head2 dbh
packaging one directory
yuki-kimoto authored on 2009-11-16
667

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
668
Database handle. This is the innstance of L<DBI>
669
    
670
    $dbi = $dbi->dbh($dbh);
671
    $dbh = $dbi->dbh;
packaging one directory
yuki-kimoto authored on 2009-11-16
672

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
673
You can use all methods of L<DBI>
packaging one directory
yuki-kimoto authored on 2009-11-16
674

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
675
    my $sth    = $dbi->dbh->prepare("...");
676
    my $errstr = $dbi->dbh->errstr;
677
    
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
678
=head2 filters
packaging one directory
yuki-kimoto authored on 2009-11-16
679

            
update document
yuki-kimoto authored on 2010-01-30
680
Filters
packaging one directory
yuki-kimoto authored on 2009-11-16
681

            
update document
yuki-kimoto authored on 2010-05-27
682
    $dbi     = $dbi->filters({%filters});
version 0.0901
yuki-kimoto authored on 2009-12-17
683
    $filters = $dbi->filters;
684

            
update document
yuki-kimoto authored on 2010-05-27
685
encode_utf8 and decode_utf8 is set to this attribute by default.
version 0.0901
yuki-kimoto authored on 2009-12-17
686

            
update document
yuki-kimoto authored on 2010-05-27
687
    $encode_utf8 = $dbi->filters->{encode_utf8};
688
    $decode_utf8 = $dbi->filters->{decode_utf8};
packaging one directory
yuki-kimoto authored on 2009-11-16
689

            
rename bind_filter to query_...
yuki-kimoto authored on 2010-04-28
690
=head2 default_query_filter
packaging one directory
yuki-kimoto authored on 2009-11-16
691

            
update document
yuki-kimoto authored on 2010-05-27
692
Default query filter.
packaging one directory
yuki-kimoto authored on 2009-11-16
693

            
update document
yuki-kimoto authored on 2010-05-27
694
    $dbi                  = $dbi->default_query_filter('encode_utf8');
rename bind_filter to query_...
yuki-kimoto authored on 2010-04-28
695
    $default_query_filter = $dbi->default_query_filter
packaging one directory
yuki-kimoto authored on 2009-11-16
696

            
cleanup
yuki-kimoto authored on 2010-04-28
697
=head2 default_fetch_filter
packaging one directory
yuki-kimoto authored on 2009-11-16
698

            
update document
yuki-kimoto authored on 2010-05-27
699
Fetching filter.
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
700

            
update document
yuki-kimoto authored on 2010-05-27
701
    $dbi                  = $dbi->default_fetch_filter('decode_utf8');
cleanup
yuki-kimoto authored on 2010-04-28
702
    $default_fetch_filter = $dbi->default_fetch_filter;
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
703

            
packaging one directory
yuki-kimoto authored on 2009-11-16
704
=head2 result_class
705

            
update document
yuki-kimoto authored on 2010-05-27
706
Result class.
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
707

            
version 0.0901
yuki-kimoto authored on 2009-12-17
708
    $dbi          = $dbi->result_class('DBIx::Custom::Result');
packaging one directory
yuki-kimoto authored on 2009-11-16
709
    $result_class = $dbi->result_class;
710

            
update document
yuki-kimoto authored on 2010-05-27
711
L<DBIx::Custom::Result> is set to this attribute by default.
update document
yuki-kimoto authored on 2010-01-30
712

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
713
=head2 sql_template
added commit method
yuki-kimoto authored on 2010-05-27
714

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
715
SQLTemplate instance. sql_template attribute must be 
716
the instance of L<DBIx::Cutom::SQLTemplate> subclass.
added commit method
yuki-kimoto authored on 2010-05-27
717

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
718
    $dbi          = $dbi->sql_template(DBIx::Cutom::SQLTemplate->new);
719
    $sql_template = $dbi->sql_template;
added commit method
yuki-kimoto authored on 2010-05-27
720

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
721
the instance of DBIx::Cutom::SQLTemplate is set to 
722
this attribute by default.
added commit method
yuki-kimoto authored on 2010-05-27
723

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
724
=head1 METHODS
added commit method
yuki-kimoto authored on 2010-05-27
725

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
726
This class is L<Object::Simple> subclass.
727
You can use all methods of L<Object::Simple>
added commit method
yuki-kimoto authored on 2010-05-27
728

            
packaging one directory
yuki-kimoto authored on 2009-11-16
729
=head2 connect
730

            
update document
yuki-kimoto authored on 2010-05-27
731
Connect to database.
732
    
733
    my $dbi = DBIx::Custom->connect(data_source => "dbi:mysql:database=books",
734
                                    user => 'ken', password => '!LFKD%$&');
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
735

            
update document
yuki-kimoto authored on 2010-05-27
736
"AutoCommit" and "RaiseError" option is true, 
737
and "PrintError" option is false by dfault.
packaging one directory
yuki-kimoto authored on 2009-11-16
738

            
739
=head2 disconnect
740

            
update document
yuki-kimoto authored on 2010-05-27
741
Disconnect database.
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
742

            
packaging one directory
yuki-kimoto authored on 2009-11-16
743
    $dbi->disconnect;
744

            
version 0.0901
yuki-kimoto authored on 2009-12-17
745
If database is already disconnected, this method do nothing.
packaging one directory
yuki-kimoto authored on 2009-11-16
746

            
747
=head2 insert
748

            
added commit method
yuki-kimoto authored on 2010-05-27
749
Insert row.
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
750

            
removed register_format()
yuki-kimoto authored on 2010-05-26
751
    $affected = $dbi->insert(table  => $table, 
752
                             param  => {%param},
753
                             append => $append,
754
                             filter => {%filter});
update document
yuki-kimoto authored on 2009-11-19
755

            
added commit method
yuki-kimoto authored on 2010-05-27
756
Retruned value is affected rows count.
packaging one directory
yuki-kimoto authored on 2009-11-16
757
    
removed reconnect method
yuki-kimoto authored on 2010-05-28
758
Example:
version 0.0901
yuki-kimoto authored on 2009-12-17
759

            
removed register_format()
yuki-kimoto authored on 2010-05-26
760
    # insert
761
    $dbi->insert(table  => 'books', 
762
                 param  => {title => 'Perl', author => 'Taro'},
763
                 append => "some statement",
764
                 filter => {title => 'encode_utf8'})
version 0.0901
yuki-kimoto authored on 2009-12-17
765

            
packaging one directory
yuki-kimoto authored on 2009-11-16
766
=head2 update
767

            
added commit method
yuki-kimoto authored on 2010-05-27
768
Update rows.
update document
yuki-kimoto authored on 2009-11-19
769

            
removed register_format()
yuki-kimoto authored on 2010-05-26
770
    $affected = $dbi->update(table  => $table, 
771
                             param  => {%params},
772
                             where  => {%where},
773
                             append => $append,
774
                             filter => {%filter})
version 0.0901
yuki-kimoto authored on 2009-12-17
775

            
added commit method
yuki-kimoto authored on 2010-05-27
776
Retruned value is affected rows count
update document
yuki-kimoto authored on 2009-11-19
777

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
778
Example:
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
779

            
removed register_format()
yuki-kimoto authored on 2010-05-26
780
    #update
781
    $dbi->update(table  => 'books',
782
                 param  => {title => 'Perl', author => 'Taro'},
783
                 where  => {id => 5},
784
                 append => "some statement",
added commit method
yuki-kimoto authored on 2010-05-27
785
                 filter => {title => 'encode_utf8'});
version 0.0901
yuki-kimoto authored on 2009-12-17
786

            
packaging one directory
yuki-kimoto authored on 2009-11-16
787
=head2 update_all
788

            
added commit method
yuki-kimoto authored on 2010-05-27
789
Update all rows.
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
790

            
removed register_format()
yuki-kimoto authored on 2010-05-26
791
    $affected = $dbi->update_all(table  => $table, 
792
                                 param  => {%params},
793
                                 filter => {%filter},
794
                                 append => $append);
update document
yuki-kimoto authored on 2009-11-19
795

            
added commit method
yuki-kimoto authored on 2010-05-27
796
Retruned value is affected rows count.
version 0.0901
yuki-kimoto authored on 2009-12-17
797

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
798
Example:
update document
yuki-kimoto authored on 2009-11-19
799

            
removed register_format()
yuki-kimoto authored on 2010-05-26
800
    # update_all
801
    $dbi->update_all(table  => 'books', 
802
                     param  => {author => 'taro'},
803
                     filter => {author => 'encode_utf8'});
packaging one directory
yuki-kimoto authored on 2009-11-16
804

            
805
=head2 delete
806

            
added commit method
yuki-kimoto authored on 2010-05-27
807
Delete rows.
update document
yuki-kimoto authored on 2009-11-19
808

            
removed register_format()
yuki-kimoto authored on 2010-05-26
809
    $affected = $dbi->delete(table  => $table,
810
                             where  => {%where},
added commit method
yuki-kimoto authored on 2010-05-27
811
                             append => $append,
removed register_format()
yuki-kimoto authored on 2010-05-26
812
                             filter => {%filter});
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
813

            
version 0.0901
yuki-kimoto authored on 2009-12-17
814
Retrun value is affected rows count
packaging one directory
yuki-kimoto authored on 2009-11-16
815
    
removed reconnect method
yuki-kimoto authored on 2010-05-28
816
Example:
packaging one directory
yuki-kimoto authored on 2009-11-16
817

            
removed register_format()
yuki-kimoto authored on 2010-05-26
818
    # delete
819
    $dbi->delete(table  => 'books',
820
                 where  => {id => 5},
821
                 append => 'some statement',
removed reconnect method
yuki-kimoto authored on 2010-05-28
822
                 filter => {id => 'encode_utf8'});
version 0.0901
yuki-kimoto authored on 2009-12-17
823

            
packaging one directory
yuki-kimoto authored on 2009-11-16
824
=head2 delete_all
825

            
added commit method
yuki-kimoto authored on 2010-05-27
826
Delete all rows.
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
827

            
removed register_format()
yuki-kimoto authored on 2010-05-26
828
    $affected = $dbi->delete_all(table => $table);
packaging one directory
yuki-kimoto authored on 2009-11-16
829

            
added commit method
yuki-kimoto authored on 2010-05-27
830
Retruned value is affected rows count.
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
831

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
832
Example:
removed register_format()
yuki-kimoto authored on 2010-05-26
833
    
834
    # delete_all
removed reconnect method
yuki-kimoto authored on 2010-05-28
835
    $dbi->delete_all(table => 'books');
packaging one directory
yuki-kimoto authored on 2009-11-16
836

            
837
=head2 select
838
    
added commit method
yuki-kimoto authored on 2010-05-27
839
Select rows.
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
840

            
added commit method
yuki-kimoto authored on 2010-05-27
841
    $result = $dbi->select(table    => $table,
842
                           column   => [@column],
843
                           where    => {%where},
844
                           append   => $append,
removed reconnect method
yuki-kimoto authored on 2010-05-28
845
                           relation => {%relation},
added commit method
yuki-kimoto authored on 2010-05-27
846
                           filter   => {%filter});
update document
yuki-kimoto authored on 2009-11-19
847

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
848
Return value is the instance of L<DBIx::Custom::Result>.
update document
yuki-kimoto authored on 2009-11-19
849

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
850
Example:
update document
yuki-kimoto authored on 2009-11-19
851

            
added commit method
yuki-kimoto authored on 2010-05-27
852
    # select * from books;
removed reconnect method
yuki-kimoto authored on 2010-05-28
853
    $result = $dbi->select(table => 'books');
packaging one directory
yuki-kimoto authored on 2009-11-16
854
    
update document
yuki-kimoto authored on 2009-11-19
855
    # select * from books where title = 'Perl';
removed reconnect method
yuki-kimoto authored on 2010-05-28
856
    $result = $dbi->select(table => 'books', where => {title => 1});
update document
yuki-kimoto authored on 2009-11-19
857
    
858
    # select title, author from books where id = 1 for update;
859
    $result = $dbi->select(
removed register_format()
yuki-kimoto authored on 2010-05-26
860
        table  => 'books',
removed reconnect method
yuki-kimoto authored on 2010-05-28
861
        column => ['title', 'author'],
removed register_format()
yuki-kimoto authored on 2010-05-26
862
        where  => {id => 1},
863
        appned => 'for update'
update document
yuki-kimoto authored on 2009-11-19
864
    );
865
    
added commit method
yuki-kimoto authored on 2010-05-27
866
    # select books.name as book_name from books, rental 
867
    # where books.id = rental.book_id;
868
    my $result = $dbi->select(
removed reconnect method
yuki-kimoto authored on 2010-05-28
869
        table    => ['books', 'rental'],
870
        column   => ['books.name as book_name']
added commit method
yuki-kimoto authored on 2010-05-27
871
        relation => {'books.id' => 'rental.book_id'}
update document
yuki-kimoto authored on 2009-11-19
872
    );
873

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
874
=head2 create_query
875
    
876
Create the instance of L<DBIx::Custom::Query>. 
877
This receive the string written by SQL template.
packaging one directory
yuki-kimoto authored on 2009-11-16
878

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
879
    my $query = $dbi->create_query("select * from authors where {= name} and {= age}");
880

            
881
=head2 execute
882

            
883
Execute the instace of L<DBIx::Custom::Query> or
884
the string written by SQL template.
885
Return value is the instance of L<DBIx::Custom::Result>.
886

            
887
    $result = $dbi->execute($query,    param => $params, filter => {%filter});
888
    $result = $dbi->execute($template, param => $params, filter => {%filter});
889

            
890
Example:
891

            
892
    $result = $dbi->execute("select * from authors where {= name} and {= age}", 
893
                            param => {name => 'taro', age => 19});
894
    
895
    while (my $row = $result->fetch) {
896
        # do something
897
    }
898

            
899
See also L<DBIx::Custom::SQLTemplate> to know how to write SQL template.
900

            
901
=head2 register_filter
902

            
903
Resister filter.
904
    
905
    $dbi->register_filter(%filters);
906
    
907
Example:
packaging one directory
yuki-kimoto authored on 2009-11-16
908

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
909
    $dbi->register_filter(
910
        encode_utf8 => sub {
911
            my $value = shift;
912
            
913
            require Encode;
914
            
915
            return Encode::encode('UTF-8', $value);
916
        },
917
        decode_utf8 => sub {
918
            my $value = shift;
919
            
920
            require Encode;
921
            
922
            return Encode::decode('UTF-8', $value)
923
        }
924
    );
925

            
926
=head2 auto_commit
927

            
928
Auto commit.
packaging one directory
yuki-kimoto authored on 2009-11-16
929

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
930
    $self        = $dbi->auto_commit(1);
931
    $auto_commit = $dbi->auto_commit;
932

            
933
This is equal to
934

            
935
    $dbi->dbh->{AutoCommit} = 1;
936
    $auto_commit = $dbi->dbh->{AutoCommit};
937

            
938
=head2 commit
939

            
940
Commit.
941

            
942
    $dbi->commit;
943

            
944
This is equal to
945

            
946
    $dbi->dbh->commit;
947

            
948
=head2 rollback
949

            
950
Rollback.
951

            
952
    $dbi->rollback
953

            
954
This is equal to
955

            
956
    $dbi->dbh->rollback;
957

            
958
=head1 AUTHOR
959

            
960
Yuki Kimoto, C<< <kimoto.yuki at gmail.com> >>
version 0.0901
yuki-kimoto authored on 2009-12-17
961

            
packaging one directory
yuki-kimoto authored on 2009-11-16
962
=head1 COPYRIGHT & LICENSE
963

            
964
Copyright 2009 Yuki Kimoto, all rights reserved.
965

            
966
This program is free software; you can redistribute it and/or modify it
967
under the same terms as Perl itself.
968

            
969
=cut