DBIx-Custom / lib / DBI / Custom.pm /
Newer Older
888 lines | 22.513kb
first commit
yuki-kimoto authored on 2009-10-13
1
package DBI::Custom;
2
use Object::Simple;
add test
yuki-kimoto authored on 2009-10-16
3

            
4
our $VERSION = '0.0101';
5

            
6
use Carp 'croak';
add some method
yuki-kimoto authored on 2009-10-14
7
use DBI;
cleanup
yuki-kimoto authored on 2009-10-29
8
use DBI::Custom::Query;
add tests
yuki-kimoto authored on 2009-10-31
9
use DBI::Custom::Result;
10
use DBI::Custom::SQL::Template;
11

            
add tests
yuki-kimoto authored on 2009-10-25
12

            
13
### Class-Object Accessors
update document
yuki-kimoto authored on 2009-10-27
14
sub user        : ClassObjectAttr { initialize => {clone => 'scalar'} }
15
sub password    : ClassObjectAttr { initialize => {clone => 'scalar'} }
16
sub data_source : ClassObjectAttr { initialize => {clone => 'scalar'} }
cleanup
yuki-kimoto authored on 2009-10-29
17
sub dbi_options : ClassObjectAttr { initialize => {clone => 'hash', 
add tests
yuki-kimoto authored on 2009-10-31
18
                                                   default => sub { {} } } }
catch up Object::Simple upda...
yuki-kimoto authored on 2009-10-26
19

            
update document
yuki-kimoto authored on 2009-10-27
20
sub bind_filter  : ClassObjectAttr { initialize => {clone => 'scalar'} }
21
sub fetch_filter : ClassObjectAttr { initialize => {clone => 'scalar'} }
catch up Object::Simple upda...
yuki-kimoto authored on 2009-10-26
22

            
add no_bind_filters
yuki-kimoto authored on 2009-10-30
23
sub no_bind_filters   : ClassObjectAttr { initialize => {clone => 'array'} }
24
sub no_fetch_filters  : ClassObjectAttr { initialize => {clone => 'array'} }
add various thins
yuki-kimoto authored on 2009-10-29
25

            
catch up Object::Simple upda...
yuki-kimoto authored on 2009-10-26
26
sub filters : ClassObjectAttr {
27
    type => 'hash',
28
    deref => 1,
29
    initialize => {
add tests
yuki-kimoto authored on 2009-10-25
30
        clone   => 'hash',
31
        default => sub { {} }
catch up Object::Simple upda...
yuki-kimoto authored on 2009-10-26
32
    }
33
}
first commit
yuki-kimoto authored on 2009-10-13
34

            
catch up Object::Simple upda...
yuki-kimoto authored on 2009-10-26
35
sub result_class : ClassObjectAttr {
36
    initialize => {
add tests
yuki-kimoto authored on 2009-10-25
37
        clone   => 'scalar',
38
        default => 'DBI::Custom::Result'
catch up Object::Simple upda...
yuki-kimoto authored on 2009-10-26
39
    }
40
}
cleanup
yuki-kimoto authored on 2009-10-14
41

            
catch up Object::Simple upda...
yuki-kimoto authored on 2009-10-26
42
sub sql_template : ClassObjectAttr {
43
    initialize => {
update document
yuki-kimoto authored on 2009-10-27
44
        clone   => sub {$_[0] ? $_[0]->clone : undef},
catch up Object::Simple upda...
yuki-kimoto authored on 2009-10-26
45
        default => sub {DBI::Custom::SQL::Template->new}
46
    }
47
}
cleanup
yuki-kimoto authored on 2009-10-15
48

            
add tests
yuki-kimoto authored on 2009-10-25
49
### Object Accessor
add tests
yuki-kimoto authored on 2009-10-18
50
sub dbh          : Attr {}
add tests
yuki-kimoto authored on 2009-10-25
51

            
52

            
53
### Methods
add various thins
yuki-kimoto authored on 2009-10-29
54

            
add tests
yuki-kimoto authored on 2009-10-25
55
# Add filter
56
sub add_filter {
57
    my $invocant = shift;
58
    
59
    my %old_filters = $invocant->filters;
60
    my %new_filters = ref $_[0] eq 'HASH' ? %{$_[0]} : @_;
61
    $invocant->filters(%old_filters, %new_filters);
update document
yuki-kimoto authored on 2009-10-27
62
    return $invocant;
add tests
yuki-kimoto authored on 2009-10-25
63
}
add various
yuki-kimoto authored on 2009-10-18
64

            
65
# Auto commit
update document
yuki-kimoto authored on 2009-10-27
66
sub _auto_commit {
add various
yuki-kimoto authored on 2009-10-18
67
    my $self = shift;
68
    
add tests
yuki-kimoto authored on 2009-10-31
69
    croak("Not yet connect to database") unless $self->dbh;
add various
yuki-kimoto authored on 2009-10-18
70
    
71
    if (@_) {
72
        $self->dbh->{AutoCommit} = $_[0];
73
        return $self;
74
    }
75
    return $self->dbh->{AutoCommit};
76
}
add test
yuki-kimoto authored on 2009-10-16
77

            
add various things
yuki-kimoto authored on 2009-10-17
78
# Connect
add some method
yuki-kimoto authored on 2009-10-14
79
sub connect {
80
    my $self = shift;
update document
yuki-kimoto authored on 2009-10-27
81
    my $data_source = $self->data_source;
82
    my $user        = $self->user;
83
    my $password    = $self->password;
cleanup
yuki-kimoto authored on 2009-10-29
84
    my $dbi_options  = $self->dbi_options;
add test
yuki-kimoto authored on 2009-10-16
85
    
add tests
yuki-kimoto authored on 2009-10-31
86
    my $dbh = eval{DBI->connect(
update document
yuki-kimoto authored on 2009-10-27
87
        $data_source,
88
        $user,
89
        $password,
add some method
yuki-kimoto authored on 2009-10-14
90
        {
91
            RaiseError => 1,
92
            PrintError => 0,
93
            AutoCommit => 1,
cleanup
yuki-kimoto authored on 2009-10-29
94
            %{$dbi_options || {} }
add some method
yuki-kimoto authored on 2009-10-14
95
        }
add tests
yuki-kimoto authored on 2009-10-31
96
    )};
97
    
98
    croak $@ if $@;
add some method
yuki-kimoto authored on 2009-10-14
99
    
100
    $self->dbh($dbh);
add various
yuki-kimoto authored on 2009-10-18
101
    return $self;
add some method
yuki-kimoto authored on 2009-10-14
102
}
first commit
yuki-kimoto authored on 2009-10-13
103

            
add tests
yuki-kimoto authored on 2009-10-25
104
# DESTROY
add tests
yuki-kimoto authored on 2009-10-18
105
sub DESTROY {
106
    my $self = shift;
add tests
yuki-kimoto authored on 2009-10-18
107
    $self->disconnect if $self->connected;
add tests
yuki-kimoto authored on 2009-10-18
108
}
109

            
add various things
yuki-kimoto authored on 2009-10-17
110
# Is connected?
111
sub connected {
112
    my $self = shift;
cleanup
yuki-kimoto authored on 2009-10-31
113
    return ref $self->{dbh} eq 'DBI::db';
add various things
yuki-kimoto authored on 2009-10-17
114
}
115

            
116
# Disconnect
117
sub disconnect {
118
    my $self = shift;
add tests
yuki-kimoto authored on 2009-10-18
119
    if ($self->connected) {
add various things
yuki-kimoto authored on 2009-10-17
120
        $self->dbh->disconnect;
121
        delete $self->{dbh};
122
    }
123
}
124

            
125
# Reconnect
126
sub reconnect {
127
    my $self = shift;
add tests
yuki-kimoto authored on 2009-10-18
128
    $self->disconnect if $self->connected;
add various things
yuki-kimoto authored on 2009-10-17
129
    $self->connect;
130
}
131

            
cleanup
yuki-kimoto authored on 2009-10-31
132
# Prepare statement handle
add prepare
yuki-kimoto authored on 2009-10-31
133
sub prepare {
134
    my ($self, $sql) = @_;
cleanup
yuki-kimoto authored on 2009-10-31
135
    
136
    # Connect if not
add tests
yuki-kimoto authored on 2009-10-31
137
    $self->connect unless $self->connected;
add prepare
yuki-kimoto authored on 2009-10-31
138
    
cleanup
yuki-kimoto authored on 2009-10-31
139
    # Prepare
add prepare
yuki-kimoto authored on 2009-10-31
140
    my $sth = eval{$self->dbh->prepare($sql)};
add tests
yuki-kimoto authored on 2009-10-31
141
    
142
    # Error
143
    croak("$@<Your SQL>\n$sql") if $@;
144
    
add prepare
yuki-kimoto authored on 2009-10-31
145
    return $sth;
146
}
147

            
cleanup
yuki-kimoto authored on 2009-10-31
148
# Execute SQL directly
add prepare
yuki-kimoto authored on 2009-10-31
149
sub do{
150
    my ($self, $sql, @bind_values) = @_;
cleanup
yuki-kimoto authored on 2009-10-31
151
    
152
    # Connect if not
add tests
yuki-kimoto authored on 2009-10-31
153
    $self->connect unless $self->connected;
add prepare
yuki-kimoto authored on 2009-10-31
154
    
cleanup
yuki-kimoto authored on 2009-10-31
155
    # Do
add tests
yuki-kimoto authored on 2009-10-31
156
    my $ret_val = eval{$self->dbh->do($sql, @bind_values)};
157
    
158
    # Error
159
    if ($@) {
160
        my $error = $@;
161
        require Data::Dumper;
162
        
163
        my $bind_value_dump
164
          = Data::Dumper->Dump([\@bind_values], ['*bind_valuds']);
165
        
166
        croak("$error<Your SQL>\n$sql\n<Your bind values>\n$bind_value_dump\n");
167
    }
add prepare
yuki-kimoto authored on 2009-10-31
168
}
169

            
cleanup
yuki-kimoto authored on 2009-10-31
170
# Create query
add various thins
yuki-kimoto authored on 2009-10-29
171
sub create_query {
172
    my ($self, $template) = @_;
add test
yuki-kimoto authored on 2009-10-17
173
    
add various thins
yuki-kimoto authored on 2009-10-29
174
    # Create query from SQL template
add prepare
yuki-kimoto authored on 2009-10-31
175
    my $sql_template = $self->sql_template;
176
    my $query = eval{$sql_template->create_query($template)};
177
    croak($@) if $@;
add test
yuki-kimoto authored on 2009-10-17
178
    
add various thins
yuki-kimoto authored on 2009-10-29
179
    # Create Query object;
cleanup
yuki-kimoto authored on 2009-10-29
180
    $query = DBI::Custom::Query->new($query);
add various thins
yuki-kimoto authored on 2009-10-29
181
    
cleanup
yuki-kimoto authored on 2009-10-31
182
    # Connect if not
add tests
yuki-kimoto authored on 2009-10-31
183
    $self->connect unless $self->connected;
try varioud way
yuki-kimoto authored on 2009-10-17
184
    
add various thins
yuki-kimoto authored on 2009-10-29
185
    # Prepare statement handle
add tests
yuki-kimoto authored on 2009-10-31
186
    my $sth = $self->prepare($query->{sql});
add tests
yuki-kimoto authored on 2009-10-18
187
    
add no_bind_filters
yuki-kimoto authored on 2009-10-30
188
    # Set statement handle
add various thins
yuki-kimoto authored on 2009-10-29
189
    $query->sth($sth);
add tests
yuki-kimoto authored on 2009-10-18
190
    
add no_bind_filters
yuki-kimoto authored on 2009-10-30
191
    # Set bind filter
192
    $query->bind_filter($self->bind_filter);
193
    
194
    # Set no filter keys when binding
195
    $query->no_bind_filters($self->no_bind_filters);
add tests
yuki-kimoto authored on 2009-10-31
196
    
add no_bind_filters
yuki-kimoto authored on 2009-10-30
197
    # Set fetch filter
198
    $query->fetch_filter($self->fetch_filter);
199
    
200
    # Set no filter keys when fetching
201
    $query->no_fetch_filters($self->no_fetch_filters);
202
    
add various thins
yuki-kimoto authored on 2009-10-29
203
    return $query;
204
}
205

            
cleanup
yuki-kimoto authored on 2009-10-31
206
# Execute query
add various thins
yuki-kimoto authored on 2009-10-29
207
sub execute {
208
    my ($self, $query, $params)  = @_;
add tests
yuki-kimoto authored on 2009-10-29
209
    $params ||= {};
try varioud way
yuki-kimoto authored on 2009-10-17
210
    
add tests
yuki-kimoto authored on 2009-10-31
211
    # First argument is SQL template
212
    if (!ref $query) {
213
        my $template = $query;
214
        $query = $self->create_query($template);
215
        my $query_edit_cb = $_[3];
216
        $query_edit_cb->($query) if ref $query_edit_cb eq 'CODE';
217
    }
218
    
add various thins
yuki-kimoto authored on 2009-10-29
219
    # Create bind value
220
    my $bind_values = $self->_build_bind_values($query, $params);
add tests
yuki-kimoto authored on 2009-10-18
221
    
cleanup
yuki-kimoto authored on 2009-10-18
222
    # Execute
cleanup
yuki-kimoto authored on 2009-10-29
223
    my $sth = $query->sth;
add tests
yuki-kimoto authored on 2009-10-31
224
    my $ret_val = eval{$sth->execute(@$bind_values)};
cleanup
yuki-kimoto authored on 2009-10-31
225
    
226
    # Execute error
add tests
yuki-kimoto authored on 2009-10-31
227
    if (my $execute_error = $@) {
add tests
yuki-kimoto authored on 2009-10-31
228
        require Data::Dumper;
229
        my $sql         = $query->{sql} || '';
230
        my $params_dump = Data::Dumper->Dump([$params], ['*params']);
231
        
add tests
yuki-kimoto authored on 2009-10-31
232
        croak("$execute_error<Your SQL>\n$sql\n<Your parameters>\n$params_dump");
add tests
yuki-kimoto authored on 2009-10-31
233
    }
add various things
yuki-kimoto authored on 2009-10-17
234
    
cleanup
yuki-kimoto authored on 2009-10-18
235
    # Return resultset if select statement is executed
add various things
yuki-kimoto authored on 2009-10-17
236
    if ($sth->{NUM_OF_FIELDS}) {
cleanup
yuki-kimoto authored on 2009-10-31
237
        
238
        # Get result class
add various things
yuki-kimoto authored on 2009-10-17
239
        my $result_class = $self->result_class;
cleanup
yuki-kimoto authored on 2009-10-31
240
        
241
        # Create result
add various
yuki-kimoto authored on 2009-10-18
242
        my $result = $result_class->new({
add no_bind_filters
yuki-kimoto authored on 2009-10-30
243
            sth              => $sth,
244
            fetch_filter     => $query->fetch_filter,
245
            no_fetch_filters => $query->no_fetch_filters
add various
yuki-kimoto authored on 2009-10-18
246
        });
add various things
yuki-kimoto authored on 2009-10-17
247
        return $result;
248
    }
add tests
yuki-kimoto authored on 2009-10-18
249
    return $ret_val;
add test
yuki-kimoto authored on 2009-10-17
250
}
251

            
cleanup
yuki-kimoto authored on 2009-10-31
252
# Build binding values
add various thins
yuki-kimoto authored on 2009-10-29
253
sub _build_bind_values {
254
    my ($self, $query, $params) = @_;
add no_bind_filters
yuki-kimoto authored on 2009-10-30
255
    my $key_infos           = $query->key_infos;
256
    my $bind_filter         = $query->bind_filter;
257
    my $no_bind_filters_map = $query->_no_bind_filters_map || {};
cleanup
yuki-kimoto authored on 2009-10-18
258
    
add various thins
yuki-kimoto authored on 2009-10-29
259
    # binding values
260
    my @bind_values;
cleanup
yuki-kimoto authored on 2009-10-18
261
    
add tests
yuki-kimoto authored on 2009-10-31
262
    # Create bind values
cleanup
yuki-kimoto authored on 2009-10-29
263
    foreach my $key_info (@$key_infos) {
cleanup
yuki-kimoto authored on 2009-10-31
264
        # Set variable
265
        my $access_keys  = $key_info->{access_keys};
cleanup
yuki-kimoto authored on 2009-10-29
266
        my $original_key = $key_info->{original_key} || '';
267
        my $table        = $key_info->{table}        || '';
268
        my $column       = $key_info->{column}       || '';
add various thins
yuki-kimoto authored on 2009-10-29
269
        
cleanup
yuki-kimoto authored on 2009-10-31
270
        # Key is found?
add tests
yuki-kimoto authored on 2009-10-31
271
        my $found;
cleanup
yuki-kimoto authored on 2009-10-31
272
        
273
        # Build bind values
add various thins
yuki-kimoto authored on 2009-10-29
274
        ACCESS_KEYS :
275
        foreach my $access_key (@$access_keys) {
cleanup
yuki-kimoto authored on 2009-10-31
276
            # Root parameter
add various thins
yuki-kimoto authored on 2009-10-29
277
            my $root_params = $params;
cleanup
yuki-kimoto authored on 2009-10-31
278
            
279
            # Search corresponding value
add various thins
yuki-kimoto authored on 2009-10-29
280
            for (my $i = 0; $i < @$access_key; $i++) {
cleanup
yuki-kimoto authored on 2009-10-31
281
                # Current key
282
                my $current_key = $access_key->[$i];
add various thins
yuki-kimoto authored on 2009-10-29
283
                
cleanup
yuki-kimoto authored on 2009-10-31
284
                # Last key
add various thins
yuki-kimoto authored on 2009-10-29
285
                if ($i == @$access_key - 1) {
cleanup
yuki-kimoto authored on 2009-10-31
286
                    # Key is array reference
287
                    if (ref $current_key eq 'ARRAY') {
288
                        # Filtering 
289
                        if ($bind_filter &&
290
                            !$no_bind_filters_map->{$original_key})
291
                        {
add no_bind_filters
yuki-kimoto authored on 2009-10-30
292
                            push @bind_values, 
cleanup
yuki-kimoto authored on 2009-10-31
293
                                 $bind_filter->($original_key, 
294
                                                $root_params->[$current_key->[0]],
cleanup
yuki-kimoto authored on 2009-10-30
295
                                                $table, $column);
add various thins
yuki-kimoto authored on 2009-10-29
296
                        }
cleanup
yuki-kimoto authored on 2009-10-31
297
                        # Not filtering
add various thins
yuki-kimoto authored on 2009-10-29
298
                        else {
cleanup
yuki-kimoto authored on 2009-10-31
299
                            push @bind_values,
300
                                 scalar $root_params->[$current_key->[0]];
add various thins
yuki-kimoto authored on 2009-10-29
301
                        }
302
                    }
cleanup
yuki-kimoto authored on 2009-10-31
303
                    # Key is string
add various thins
yuki-kimoto authored on 2009-10-29
304
                    else {
cleanup
yuki-kimoto authored on 2009-10-31
305
                        # Key is not found
306
                        next ACCESS_KEYS
307
                          unless exists $root_params->{$current_key};
308
                        
309
                        # Filtering
310
                        if ($bind_filter &&
311
                            !$no_bind_filters_map->{$original_key}) 
312
                        {
add no_bind_filters
yuki-kimoto authored on 2009-10-30
313
                            push @bind_values,
cleanup
yuki-kimoto authored on 2009-10-31
314
                                 $bind_filter->($original_key,
315
                                                $root_params->{$current_key}, 
cleanup
yuki-kimoto authored on 2009-10-30
316
                                                $table, $column);
add various thins
yuki-kimoto authored on 2009-10-29
317
                        }
cleanup
yuki-kimoto authored on 2009-10-31
318
                        # Not filtering
add various thins
yuki-kimoto authored on 2009-10-29
319
                        else {
cleanup
yuki-kimoto authored on 2009-10-31
320
                            push @bind_values,
321
                                 scalar $root_params->{$current_key};
add various thins
yuki-kimoto authored on 2009-10-29
322
                        }
323
                    }
cleanup
yuki-kimoto authored on 2009-10-31
324
                    
325
                    # Key is found
add tests
yuki-kimoto authored on 2009-10-31
326
                    $found = 1;
add various thins
yuki-kimoto authored on 2009-10-29
327
                }
cleanup
yuki-kimoto authored on 2009-10-31
328
                # First or middle key
add various thins
yuki-kimoto authored on 2009-10-29
329
                else {
cleanup
yuki-kimoto authored on 2009-10-31
330
                    # Key is array reference
331
                    if (ref $current_key eq 'ARRAY') {
332
                        # Go next key
333
                        $root_params = $root_params->[$current_key->[0]];
334
                    }
335
                    # Key is string
336
                    else {
337
                        # Not found
338
                        next ACCESS_KEYS
339
                          unless exists $root_params->{$current_key};
340
                        
341
                        # Go next key
342
                        $root_params = $root_params->{$current_key};
343
                    }
add various thins
yuki-kimoto authored on 2009-10-29
344
                }
345
            }
346
        }
add tests
yuki-kimoto authored on 2009-10-31
347
        
cleanup
yuki-kimoto authored on 2009-10-31
348
        # Key is not found
add tests
yuki-kimoto authored on 2009-10-31
349
        unless ($found) {
350
            require Data::Dumper;
add tests
yuki-kimoto authored on 2009-10-31
351
            my $key_info_dump  = Data::Dumper->Dump([$key_info], ['*key_info']);
add tests
yuki-kimoto authored on 2009-10-31
352
            my $params_dump    = Data::Dumper->Dump([$params], ['*params']);
add tests
yuki-kimoto authored on 2009-10-31
353
            croak("Corresponding key is not found in your parameters\n" . 
add tests
yuki-kimoto authored on 2009-10-31
354
                  "<Key information>\n$key_info_dump\n\n" .
355
                  "<Your parameters>\n$params_dump\n");
356
        }
update document
yuki-kimoto authored on 2009-10-27
357
    }
add tests
yuki-kimoto authored on 2009-10-31
358
    return \@bind_values;
add test
yuki-kimoto authored on 2009-10-17
359
}
360

            
add tests
yuki-kimoto authored on 2009-10-31
361
# Run tranzaction
362
sub run_tranzaction {
363
    my ($self, $tranzaction) = @_;
364
    
365
    # Check auto commit
366
    croak("AutoCommit must be true before tranzaction start")
367
      unless $self->_auto_commit;
368
    
369
    # Auto commit off
370
    $self->_auto_commit(0);
371
    
372
    # Run tranzaction
373
    eval {$tranzaction->()};
374
    
375
    # Tranzaction error
376
    my $tranzaction_error = $@;
377
    
378
    # Tranzaction is failed.
379
    if ($tranzaction_error) {
380
        # Rollback
381
        eval{$self->dbh->rollback};
382
        
383
        # Rollback error
384
        my $rollback_error = $@;
385
        
386
        # Auto commit on
387
        $self->_auto_commit(1);
388
        
389
        if ($rollback_error) {
390
            # Rollback is failed
391
            croak("${tranzaction_error}Rollback is failed : $rollback_error");
392
        }
393
        else {
394
            # Rollback is success
395
            croak("${tranzaction_error}Rollback is success");
396
        }
397
    }
398
    # Tranzaction is success
399
    else {
400
        # Commit
401
        eval{$self->dbh->commit};
402
        my $commit_error = $@;
403
        
404
        # Auto commit on
405
        $self->_auto_commit(1);
406
        
407
        # Commit is failed
408
        croak($commit_error) if $commit_error;
409
    }
410
}
add various thins
yuki-kimoto authored on 2009-10-29
411

            
add methods
yuki-kimoto authored on 2009-11-02
412
# Get last insert id
413
sub last_insert_id {
414
    my $self = shift;
415
    
416
    # Not connected
417
    croak("Not yet connect to database")
418
      unless $self->connected;
419
    
420
    return $self->dbh->last_insert_id(@_);
421
}
422

            
423
# Insert
424
sub insert {
425
    my ($self, $table, $insert_params, $edit_query_cb) = @_;
426
    $insert_params ||= {};
427
    
428
    # Insert keys
429
    my @insert_keys = keys %$insert_params;
430
    
431
    # Not exists insert keys
432
    croak("Insert key must be specified")
433
      unless @insert_keys;
434
    
435
    # Templte for insert
436
    my $template = "insert into $table {insert " . join(' ', @insert_keys) . '}';
437
    
438
    # Create query
439
    my $query = $self->create_query($template);
440
    
441
    # Edit query callback must be code reference
442
    croak("Edit query callback must be code reference")
443
      if $edit_query_cb && !ref $edit_query_cb eq 'CODE';
444
    
445
    # Edit query if need
446
    $edit_query_cb->($query) if ref $edit_query_cb eq 'CODE';
447
    
448
    # Execute query
449
    my $ret_val = $self->execute($query, $insert_params);
450
    
451
    return $ret_val;
452
}
453

            
454
sub update {
455
    my ($self, $table, $update_params,
456
        $where_params, $edit_query_cb, $options) = @_;
457
    
458
    $update_params ||= {};
459
    $where_params  ||= {};
460
    
461
    # Update keys
462
    my @update_keys = keys %$where_params;
463
    
464
    # Not exists update kyes
465
    croak("Update key must be specified")
466
      unless @update_keys;
467
    
468
    # Where keys
469
    my @where_keys = keys %$where_params;
470
    
471
    # Not exists where keys
472
    croak("Where key must be specified")
473
      if !@where_keys && !$options->{allow_update_all};
474
    
475
    # Update clause
476
    my $update_clause = '{update ' . join(' ', @update_keys) . '}';
477
    
478
    # Where clause
479
    my $where_clause = 'where ';
480
    foreach my $where_key (@where_keys) {
481
        $where_clause .= "{= $where_key} && ";
482
    }
483
    $where_clause =~ s/ && $//;
484
    
485
    # Template for update
486
    my $template = "update $table $update_clause $where_clause";
487
    
488
    # Create query
489
    my $query = $self->create_query($template);
490
    
491
    # Edit query callback must be code reference
492
    croak("Edit query callback must be code reference")
493
      if $edit_query_cb && !ref $edit_query_cb eq 'CODE';
494
    
495
    # Edit query if need
496
    $edit_query_cb->($query) if $edit_query_cb;
497
    
498
    # Rearrange parammeters
499
    my $params = {'#update' => $update_params, %$where_params};
500
    
501
    # Execute query
502
    my $ret_val = $self->execute($query, $params);
503
    
504
    return $ret_val;
505
}
506

            
507
# Update all rows
508
sub update_all {
509
    my ($self, $table, $update_params, $edit_query_cb) = @_;
510
    
511
    return $self->update($table, $update_params, {}, $edit_query_cb,
512
                         {allow_update_all => 1});
513
}
514

            
515
# Delete
516
sub delete {
517
    my ($self, $table, $where_params, $edit_query_cb, $options) = @_;
518
    $where_params ||= {};
519
    
520
    # Where keys
521
    my @where_keys = keys %$where_params;
522
    
523
    # Not exists where keys
524
    croak("Where key must be specified")
525
      if !@where_keys && !$options->{allow_update_all};
526
    
527
    # Where clause
528
    my $where_clause = 'where ';
529
    foreach my $where_key (@where_keys) {
530
        $where_clause .= "{= $where_key} && ";
531
    }
532
    $where_clause =~ s/ && $//;
533
    
534
    # Template for delete
535
    my $template = "delete from $table $where_clause";
536
    
537
    # Create query
538
    my $query = $self->create_query($template);
539
    
540
    # Edit query callback must be code reference
541
    croak("Edit query callback must be code reference")
542
      if $edit_query_cb && !ref $edit_query_cb eq 'CODE';
543
    
544
    # Edit query if need
545
    $edit_query_cb->($query) if $edit_query_cb;
546
    
547
    # Execute query
548
    my $ret_val = $self->execute($query, $where_params);
549
    
550
    return $ret_val;
551
}
552

            
553
# Delete all rows
554
sub delete_all {
555
    my ($self, $table, $edit_query_cb) = @_;
556
    return $self->delete($table, {}, $edit_query_cb, {allow_delete_all => 1});
557
}
558

            
559

            
add test
yuki-kimoto authored on 2009-10-17
560
Object::Simple->build_class;
561

            
first commit
yuki-kimoto authored on 2009-10-13
562
=head1 NAME
563

            
add test
yuki-kimoto authored on 2009-10-17
564
DBI::Custom - Customizable simple DBI
first commit
yuki-kimoto authored on 2009-10-13
565

            
566
=head1 VERSION
567

            
add test
yuki-kimoto authored on 2009-10-16
568
Version 0.0101
first commit
yuki-kimoto authored on 2009-10-13
569

            
cleanup
yuki-kimoto authored on 2009-10-31
570
=head1 CAUTION
571

            
572
This module is now experimental stage.
573

            
574
I want you to try this module
575
because I want this module stable, and not to damage your DB data by this module bug.
576

            
577
Please tell me bug if you find
first commit
yuki-kimoto authored on 2009-10-13
578

            
579
=head1 SYNOPSIS
580

            
add test
yuki-kimoto authored on 2009-10-16
581
  my $dbi = DBI::Custom->new;
add various thins
yuki-kimoto authored on 2009-10-29
582
  
583
  my $query = $dbi->create_query($template);
584
  $dbi->execute($query);
first commit
yuki-kimoto authored on 2009-10-13
585

            
update document
yuki-kimoto authored on 2009-10-27
586
=head1 CLASS-OBJECT ACCESSORS
first commit
yuki-kimoto authored on 2009-10-13
587

            
update document
yuki-kimoto authored on 2009-10-27
588
=head2 user
589

            
590
    # Set and get database user name
591
    $self = $dbi->user($user);
592
    $user = $dbi->user;
593
    
594
    # Sample
595
    $dbi->user('taro');
596

            
597
=head2 password
598

            
599
    # Set and get database password
600
    $self     = $dbi->password($password);
601
    $password = $dbi->password;
602
    
603
    # Sample
604
    $dbi->password('lkj&le`@s');
605

            
606
=head2 data_source
607

            
608
    # Set and get database data source
609
    $self        = $dbi->data_source($data_soruce);
610
    $data_source = $dbi->data_source;
611
    
612
    # Sample(SQLite)
613
    $dbi->data_source(dbi:SQLite:dbname=$database);
614
    
615
    # Sample(MySQL);
616
    $dbi->data_source("dbi:mysql:dbname=$database");
617
    
618
    # Sample(PostgreSQL)
619
    $dbi->data_source("dbi:Pg:dbname=$database");
cleanup
yuki-kimoto authored on 2009-10-29
620
    
621
=head2 database
622

            
623
    # Set and get database name
624
    $self     = $dbi->database($database);
625
    $database = $dbi->database;
update document
yuki-kimoto authored on 2009-10-27
626

            
cleanup
yuki-kimoto authored on 2009-10-29
627
=head2 dbi_options
update document
yuki-kimoto authored on 2009-10-27
628

            
629
    # Set and get DBI option
cleanup
yuki-kimoto authored on 2009-10-29
630
    $self       = $dbi->dbi_options({$options => $value, ...});
631
    $dbi_options = $dbi->dbi_options;
update document
yuki-kimoto authored on 2009-10-27
632

            
633
    # Sample
cleanup
yuki-kimoto authored on 2009-10-29
634
    $dbi->dbi_options({PrintError => 0, RaiseError => 1});
update document
yuki-kimoto authored on 2009-10-27
635

            
cleanup
yuki-kimoto authored on 2009-10-29
636
dbi_options is used when you connect database by using connect.
update document
yuki-kimoto authored on 2009-10-27
637

            
add prepare
yuki-kimoto authored on 2009-10-31
638
=head2 prepare
639

            
640
    $sth = $dbi->prepare($sql);
641

            
642
This method is same as DBI::prepare
643

            
644
=head2 do
645

            
646
    $dbi->do($sql, @bind_values);
647

            
648
This method is same as DBI::do
649

            
update document
yuki-kimoto authored on 2009-10-27
650
=head2 sql_template
651

            
652
    # Set and get SQL::Template object
653
    $self         = $dbi->sql_template($sql_template);
654
    $sql_template = $dbi->sql_template;
655
    
656
    # Sample
657
    $dbi->sql_template(DBI::Cutom::SQL::Template->new);
658

            
659
=head2 filters
660

            
661
    # Set and get filters
662
    $self    = $dbi->filters($filters);
663
    $filters = $dbi->filters;
first commit
yuki-kimoto authored on 2009-10-13
664

            
add test
yuki-kimoto authored on 2009-10-16
665
=head2 bind_filter
first commit
yuki-kimoto authored on 2009-10-13
666

            
update document
yuki-kimoto authored on 2009-10-27
667
    # Set and get binding filter
668
    $self        = $dbi->bind_filter($bind_filter);
669
    $bind_filter = $dbi->bind_filter
first commit
yuki-kimoto authored on 2009-10-13
670

            
update document
yuki-kimoto authored on 2009-10-27
671
    # Sample
672
    $dbi->bind_filter($self->filters->{default_bind_filter});
673
    
first commit
yuki-kimoto authored on 2009-10-13
674

            
update document
yuki-kimoto authored on 2009-10-27
675
you can get DBI database handle if you need.
first commit
yuki-kimoto authored on 2009-10-13
676

            
add test
yuki-kimoto authored on 2009-10-16
677
=head2 fetch_filter
first commit
yuki-kimoto authored on 2009-10-13
678

            
update document
yuki-kimoto authored on 2009-10-27
679
    # Set and get Fetch filter
680
    $self         = $dbi->fetch_filter($fetch_filter);
681
    $fetch_filter = $dbi->fetch_filter;
first commit
yuki-kimoto authored on 2009-10-13
682

            
update document
yuki-kimoto authored on 2009-10-27
683
    # Sample
684
    $dbi->fetch_filter($self->filters->{default_fetch_filter});
add test
yuki-kimoto authored on 2009-10-16
685

            
add no_bind_filters
yuki-kimoto authored on 2009-10-30
686
=head2 no_bind_filters
687

            
688
    # Set and get no filter keys when binding
689
    $self            = $dbi->no_bind_filters($no_bind_filters);
690
    $no_bind_filters = $dbi->no_bind_filters;
691

            
692
=head2 no_fetch_filters
cleanup
yuki-kimoto authored on 2009-10-29
693

            
add no_bind_filters
yuki-kimoto authored on 2009-10-30
694
    # Set and get no filter keys when fetching
695
    $self             = $dbi->no_fetch_filters($no_fetch_filters);
696
    $no_fetch_filters = $dbi->no_fetch_filters;
cleanup
yuki-kimoto authored on 2009-10-29
697

            
update document
yuki-kimoto authored on 2009-10-27
698
=head2 result_class
first commit
yuki-kimoto authored on 2009-10-13
699

            
update document
yuki-kimoto authored on 2009-10-27
700
    # Set and get resultset class
701
    $self         = $dbi->result_class($result_class);
702
    $result_class = $dbi->result_class;
703
    
704
    # Sample
705
    $dbi->result_class('DBI::Custom::Result');
add test
yuki-kimoto authored on 2009-10-17
706

            
update document
yuki-kimoto authored on 2009-10-27
707
=head2 dbh
add test
yuki-kimoto authored on 2009-10-17
708

            
update document
yuki-kimoto authored on 2009-10-27
709
    # Get database handle
710
    $dbh = $self->dbh;
add test
yuki-kimoto authored on 2009-10-17
711

            
update document
yuki-kimoto authored on 2009-10-27
712
=head1 METHODS
add tests
yuki-kimoto authored on 2009-10-18
713

            
update document
yuki-kimoto authored on 2009-10-27
714
=head2 connect
715

            
716
    # Connect to database
717
    $self = $dbi->connect;
718
    
719
    # Sample
720
    $dbi = DBI::Custom->new(user => 'taro', password => 'lji8(', 
721
                            data_soruce => "dbi:mysql:dbname=$database");
722
    $dbi->connect;
add tests
yuki-kimoto authored on 2009-10-18
723

            
724
=head2 disconnect
725

            
update document
yuki-kimoto authored on 2009-10-27
726
    # Disconnect database
727
    $dbi->disconnect;
728

            
729
If database is already disconnected, this method do noting.
730

            
add tests
yuki-kimoto authored on 2009-10-18
731
=head2 reconnect
732

            
update document
yuki-kimoto authored on 2009-10-27
733
    # Reconnect
734
    $dbi->reconnect;
735

            
736
=head2 connected
737

            
738
    # Check connected
739
    $dbi->connected
740

            
741
=head2 add_filter
742

            
743
    # Add filter (hash ref or hash can be recieve)
744
    $self = $dbi->add_filter({$filter_name => $filter, ...});
745
    $self = $dbi->add_filter($filetr_name => $filter, ...);
746
    
747
    # Sample
748
    $dbi->add_filter(
749
        decode_utf8 => sub {
cleanup
yuki-kimoto authored on 2009-10-30
750
            my ($key, $value, $table, $column) = @_;
update document
yuki-kimoto authored on 2009-10-27
751
            return Encode::decode('UTF-8', $value);
752
        },
753
        datetime_to_string => sub {
cleanup
yuki-kimoto authored on 2009-10-30
754
            my ($key, $value, $table, $column) = @_;
update document
yuki-kimoto authored on 2009-10-27
755
            return $value->strftime('%Y-%m-%d %H:%M:%S')
756
        },
757
        default_bind_filter => sub {
cleanup
yuki-kimoto authored on 2009-10-30
758
            my ($key, $value, $table, $column) = @_;
update document
yuki-kimoto authored on 2009-10-27
759
            if (ref $value eq 'Time::Piece') {
cleanup
yuki-kimoto authored on 2009-10-30
760
                return $dbi->filters->{datetime_to_string}->($value);
update document
yuki-kimoto authored on 2009-10-27
761
            }
762
            else {
cleanup
yuki-kimoto authored on 2009-10-30
763
                return $dbi->filters->{decode_utf8}->($value);
update document
yuki-kimoto authored on 2009-10-27
764
            }
765
        },
766
        
767
        encode_utf8 => sub {
cleanup
yuki-kimoto authored on 2009-10-30
768
            my ($key, $value) = @_;
update document
yuki-kimoto authored on 2009-10-27
769
            return Encode::encode('UTF-8', $value);
770
        },
771
        string_to_datetime => sub {
cleanup
yuki-kimoto authored on 2009-10-30
772
            my ($key, $value) = @_;
update document
yuki-kimoto authored on 2009-10-27
773
            return DateTime::Format::MySQL->parse_datetime($value);
774
        },
775
        default_fetch_filter => sub {
cleanup
yuki-kimoto authored on 2009-10-30
776
            my ($key, $value, $type, $sth, $i) = @_;
update document
yuki-kimoto authored on 2009-10-27
777
            if ($type eq 'DATETIME') {
cleanup
yuki-kimoto authored on 2009-10-30
778
                return $dbi->filters->{string_to_datetime}->($value);
update document
yuki-kimoto authored on 2009-10-27
779
            }
780
            else {
cleanup
yuki-kimoto authored on 2009-10-30
781
                return $dbi->filters->{encode_utf8}->($value);
update document
yuki-kimoto authored on 2009-10-27
782
            }
783
        }
784
    );
785

            
786
add_filter add filter to filters
add tests
yuki-kimoto authored on 2009-10-18
787

            
cleanup
yuki-kimoto authored on 2009-10-29
788
=head2 create_query
789
    
790
    # Create Query object from SQL template
791
    my $query = $dbi->create_query($template);
792
    
793
=head2 execute
update document
yuki-kimoto authored on 2009-10-27
794

            
795
    # Parse SQL template and execute SQL
cleanup
yuki-kimoto authored on 2009-10-29
796
    $result = $dbi->query($query, $params);
797
    $result = $dbi->query($template, $params); # Shorcut
update document
yuki-kimoto authored on 2009-10-27
798
    
799
    # Sample
800
    $result = $dbi->query("select * from authors where {= name} && {= age}", 
801
                          {author => 'taro', age => 19});
802
    
803
    while (my @row = $result->fetch) {
804
        # do something
805
    }
806

            
807
See also L<DBI::Custom::SQL::Template>
808

            
cleanup
yuki-kimoto authored on 2009-10-22
809
=head2 run_tranzaction
first commit
yuki-kimoto authored on 2009-10-13
810

            
update document
yuki-kimoto authored on 2009-10-27
811
    # Run tranzaction
812
    $dbi->run_tranzaction(sub {
813
        # do something
814
    });
first commit
yuki-kimoto authored on 2009-10-13
815

            
update document
yuki-kimoto authored on 2009-10-27
816
If tranzaction is success, commit is execute. 
817
If tranzation is died, rollback is execute.
first commit
yuki-kimoto authored on 2009-10-13
818

            
add methods
yuki-kimoto authored on 2009-11-02
819
=head2 insert
820

            
821
    # Insert
822
    $dbi->insert($table, $insert_values);
823
    
824
    # Sample
825
    $dbi->insert('books', {title => 'Perl', author => 'Taro'});
826

            
827
=head2 update
828

            
829
    # Update
830
    $dbi->update($table, $update_values, $where);
831
    
832
    # Sample
833
    $dbi->update('books', {title => 'Perl', author => 'Taro'}, {id => 5});
834

            
835
=head2 update_all
836

            
837
    # Update all rows
838
    $dbi->update($table, $updat_values);
839

            
840
=head2 delete
841

            
842
    # Delete
843
    $dbi->delete($table, $where);
844
    
845
    # Sample
846
    $dbi->delete('Books', {id => 5});
847

            
848
=head2 delete_all
849

            
850
    # Delete all rows
851
    $dbi->delete_all($table);
852

            
853
=head2 last_insert_id
854

            
855
    # Get last insert id
856
    $last_insert_id = $dbi->last_insert_id;
857
    
858
This method is same as DBI last_insert_id;
859

            
add tests
yuki-kimoto authored on 2009-10-31
860
=head1 CAUTION
861

            
862
DBI::Custom have DIB object internal.
863
This module is work well in the following DBI condition.
864

            
865
    1. AutoCommit is true
866
    2. RaiseError is true
867

            
868
By default, Both AutoCommit and RaiseError is true.
869
You must not change these mode not to damage your data.
870

            
871
If you change these mode, 
872
you cannot get correct error message, 
873
or run_tranzaction may fail.
874

            
add various
yuki-kimoto authored on 2009-10-18
875
=head1 AUTHOR
first commit
yuki-kimoto authored on 2009-10-13
876

            
add various
yuki-kimoto authored on 2009-10-18
877
Yuki Kimoto, C<< <kimoto.yuki at gmail.com> >>
first commit
yuki-kimoto authored on 2009-10-13
878

            
add tests
yuki-kimoto authored on 2009-10-31
879
Github L<http://github.com/yuki-kimoto>
880

            
first commit
yuki-kimoto authored on 2009-10-13
881
=head1 COPYRIGHT & LICENSE
882

            
883
Copyright 2009 Yuki Kimoto, all rights reserved.
884

            
885
This program is free software; you can redistribute it and/or modify it
886
under the same terms as Perl itself.
887

            
888
=cut