DBIx-Custom / lib / DBI / Custom.pm /
Newer Older
951 lines | 24.552kb
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 query cache system
yuki-kimoto authored on 2009-11-02
173
    my $class = ref $self;
add test
yuki-kimoto authored on 2009-10-17
174
    
add various thins
yuki-kimoto authored on 2009-10-29
175
    # Create query from SQL template
add prepare
yuki-kimoto authored on 2009-10-31
176
    my $sql_template = $self->sql_template;
add test
yuki-kimoto authored on 2009-10-17
177
    
add query cache system
yuki-kimoto authored on 2009-11-02
178
    # Try to get cached query
179
    my $query = $class->_query_caches->{$template};
180
    
181
    # Create query
182
    unless ($query) {
183
        $query = eval{$sql_template->create_query($template)};
184
        croak($@) if $@;
185
        
186
        $query = DBI::Custom::Query->new($query);
187
        
188
        $class->_add_query_cache($template, $query);
189
    }
add various thins
yuki-kimoto authored on 2009-10-29
190
    
cleanup
yuki-kimoto authored on 2009-10-31
191
    # Connect if not
add tests
yuki-kimoto authored on 2009-10-31
192
    $self->connect unless $self->connected;
try varioud way
yuki-kimoto authored on 2009-10-17
193
    
add various thins
yuki-kimoto authored on 2009-10-29
194
    # Prepare statement handle
add tests
yuki-kimoto authored on 2009-10-31
195
    my $sth = $self->prepare($query->{sql});
add tests
yuki-kimoto authored on 2009-10-18
196
    
add no_bind_filters
yuki-kimoto authored on 2009-10-30
197
    # Set statement handle
add various thins
yuki-kimoto authored on 2009-10-29
198
    $query->sth($sth);
add tests
yuki-kimoto authored on 2009-10-18
199
    
add no_bind_filters
yuki-kimoto authored on 2009-10-30
200
    # Set bind filter
201
    $query->bind_filter($self->bind_filter);
202
    
203
    # Set no filter keys when binding
204
    $query->no_bind_filters($self->no_bind_filters);
add tests
yuki-kimoto authored on 2009-10-31
205
    
add no_bind_filters
yuki-kimoto authored on 2009-10-30
206
    # Set fetch filter
207
    $query->fetch_filter($self->fetch_filter);
208
    
209
    # Set no filter keys when fetching
210
    $query->no_fetch_filters($self->no_fetch_filters);
211
    
add various thins
yuki-kimoto authored on 2009-10-29
212
    return $query;
213
}
214

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

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

            
add tests
yuki-kimoto authored on 2009-10-31
375
# Run tranzaction
376
sub run_tranzaction {
377
    my ($self, $tranzaction) = @_;
378
    
379
    # Check auto commit
380
    croak("AutoCommit must be true before tranzaction start")
381
      unless $self->_auto_commit;
382
    
383
    # Auto commit off
384
    $self->_auto_commit(0);
385
    
386
    # Run tranzaction
387
    eval {$tranzaction->()};
388
    
389
    # Tranzaction error
390
    my $tranzaction_error = $@;
391
    
392
    # Tranzaction is failed.
393
    if ($tranzaction_error) {
394
        # Rollback
395
        eval{$self->dbh->rollback};
396
        
397
        # Rollback error
398
        my $rollback_error = $@;
399
        
400
        # Auto commit on
401
        $self->_auto_commit(1);
402
        
403
        if ($rollback_error) {
404
            # Rollback is failed
405
            croak("${tranzaction_error}Rollback is failed : $rollback_error");
406
        }
407
        else {
408
            # Rollback is success
409
            croak("${tranzaction_error}Rollback is success");
410
        }
411
    }
412
    # Tranzaction is success
413
    else {
414
        # Commit
415
        eval{$self->dbh->commit};
416
        my $commit_error = $@;
417
        
418
        # Auto commit on
419
        $self->_auto_commit(1);
420
        
421
        # Commit is failed
422
        croak($commit_error) if $commit_error;
423
    }
424
}
add various thins
yuki-kimoto authored on 2009-10-29
425

            
add methods
yuki-kimoto authored on 2009-11-02
426
# Get last insert id
427
sub last_insert_id {
428
    my $self = shift;
429
    
430
    # Not connected
431
    croak("Not yet connect to database")
432
      unless $self->connected;
433
    
434
    return $self->dbh->last_insert_id(@_);
435
}
436

            
437
# Insert
438
sub insert {
add tests
yuki-kimoto authored on 2009-11-02
439
    my ($self, $table, $insert_params, $query_edit_cb) = @_;
add tests
yuki-kimoto authored on 2009-11-03
440
    $table         ||= '';
add methods
yuki-kimoto authored on 2009-11-02
441
    $insert_params ||= {};
442
    
443
    # Insert keys
444
    my @insert_keys = keys %$insert_params;
445
    
446
    # Not exists insert keys
add tests
yuki-kimoto authored on 2009-11-03
447
    croak("Key-value pairs for insert must be specified to 'insert' second argument")
add methods
yuki-kimoto authored on 2009-11-02
448
      unless @insert_keys;
449
    
450
    # Templte for insert
451
    my $template = "insert into $table {insert " . join(' ', @insert_keys) . '}';
452
    
453
    # Create query
454
    my $query = $self->create_query($template);
455
    
add tests
yuki-kimoto authored on 2009-11-02
456
    # Query edit callback must be code reference
457
    croak("Query edit callback must be code reference")
458
      if $query_edit_cb && ref $query_edit_cb ne 'CODE';
add methods
yuki-kimoto authored on 2009-11-02
459
    
add tests
yuki-kimoto authored on 2009-11-02
460
    # Query edit if need
461
    $query_edit_cb->($query) if $query_edit_cb;
add methods
yuki-kimoto authored on 2009-11-02
462
    
463
    # Execute query
464
    my $ret_val = $self->execute($query, $insert_params);
465
    
466
    return $ret_val;
467
}
468

            
add tests
yuki-kimoto authored on 2009-11-03
469
# Update
add methods
yuki-kimoto authored on 2009-11-02
470
sub update {
471
    my ($self, $table, $update_params,
add tests
yuki-kimoto authored on 2009-11-02
472
        $where_params, $query_edit_cb, $options) = @_;
add methods
yuki-kimoto authored on 2009-11-02
473
    
add tests
yuki-kimoto authored on 2009-11-03
474
    $table         ||= '';
add methods
yuki-kimoto authored on 2009-11-02
475
    $update_params ||= {};
476
    $where_params  ||= {};
477
    
478
    # Update keys
add tests
yuki-kimoto authored on 2009-11-03
479
    my @update_keys = keys %$update_params;
add methods
yuki-kimoto authored on 2009-11-02
480
    
481
    # Not exists update kyes
add tests
yuki-kimoto authored on 2009-11-03
482
    croak("Key-value pairs for update must be specified to 'update' second argument")
add methods
yuki-kimoto authored on 2009-11-02
483
      unless @update_keys;
484
    
485
    # Where keys
486
    my @where_keys = keys %$where_params;
487
    
488
    # Not exists where keys
add tests
yuki-kimoto authored on 2009-11-03
489
    croak("Key-value pairs for where clause must be specified to 'update' third argument")
add methods
yuki-kimoto authored on 2009-11-02
490
      if !@where_keys && !$options->{allow_update_all};
491
    
492
    # Update clause
493
    my $update_clause = '{update ' . join(' ', @update_keys) . '}';
494
    
495
    # Where clause
add tests
yuki-kimoto authored on 2009-11-03
496
    my $where_clause = '';
497
    if (@where_keys) {
498
        $where_clause = 'where ';
499
        foreach my $where_key (@where_keys) {
500
            $where_clause .= "{= $where_key} && ";
501
        }
502
        $where_clause =~ s/ && $//;
add methods
yuki-kimoto authored on 2009-11-02
503
    }
504
    
505
    # Template for update
506
    my $template = "update $table $update_clause $where_clause";
507
    
508
    # Create query
509
    my $query = $self->create_query($template);
510
    
add tests
yuki-kimoto authored on 2009-11-02
511
    # Query edit callback must be code reference
512
    croak("Query edit callback must be code reference")
513
      if $query_edit_cb && ref $query_edit_cb ne 'CODE';
add methods
yuki-kimoto authored on 2009-11-02
514
    
add tests
yuki-kimoto authored on 2009-11-02
515
    # Query edit if need
516
    $query_edit_cb->($query) if $query_edit_cb;
add methods
yuki-kimoto authored on 2009-11-02
517
    
518
    # Rearrange parammeters
519
    my $params = {'#update' => $update_params, %$where_params};
520
    
521
    # Execute query
522
    my $ret_val = $self->execute($query, $params);
523
    
524
    return $ret_val;
525
}
526

            
527
# Update all rows
528
sub update_all {
add tests
yuki-kimoto authored on 2009-11-02
529
    my ($self, $table, $update_params, $query_edit_cb) = @_;
add methods
yuki-kimoto authored on 2009-11-02
530
    
add tests
yuki-kimoto authored on 2009-11-02
531
    return $self->update($table, $update_params, {}, $query_edit_cb,
add methods
yuki-kimoto authored on 2009-11-02
532
                         {allow_update_all => 1});
533
}
534

            
535
# Delete
536
sub delete {
add tests
yuki-kimoto authored on 2009-11-02
537
    my ($self, $table, $where_params, $query_edit_cb, $options) = @_;
add tests
yuki-kimoto authored on 2009-11-03
538
    $table        ||= '';
add methods
yuki-kimoto authored on 2009-11-02
539
    $where_params ||= {};
540
    
541
    # Where keys
542
    my @where_keys = keys %$where_params;
543
    
544
    # Not exists where keys
add tests
yuki-kimoto authored on 2009-11-03
545
    croak("Key-value pairs for where clause must be specified to 'delete' second argument")
546
      if !@where_keys && !$options->{allow_delete_all};
add methods
yuki-kimoto authored on 2009-11-02
547
    
548
    # Where clause
add tests
yuki-kimoto authored on 2009-11-03
549
    my $where_clause = '';
550
    if (@where_keys) {
551
        $where_clause = 'where ';
552
        foreach my $where_key (@where_keys) {
553
            $where_clause .= "{= $where_key} && ";
554
        }
555
        $where_clause =~ s/ && $//;
add methods
yuki-kimoto authored on 2009-11-02
556
    }
557
    
558
    # Template for delete
559
    my $template = "delete from $table $where_clause";
560
    
561
    # Create query
562
    my $query = $self->create_query($template);
563
    
add tests
yuki-kimoto authored on 2009-11-02
564
    # Query edit callback must be code reference
565
    croak("Query edit callback must be code reference")
566
      if $query_edit_cb && ref $query_edit_cb ne 'CODE';
add methods
yuki-kimoto authored on 2009-11-02
567
    
add tests
yuki-kimoto authored on 2009-11-02
568
    # Query edit if need
569
    $query_edit_cb->($query) if $query_edit_cb;
add methods
yuki-kimoto authored on 2009-11-02
570
    
571
    # Execute query
572
    my $ret_val = $self->execute($query, $where_params);
573
    
574
    return $ret_val;
575
}
576

            
577
# Delete all rows
578
sub delete_all {
add tests
yuki-kimoto authored on 2009-11-03
579
    my ($self, $table) = @_;
580
    return $self->delete($table, {}, undef, {allow_delete_all => 1});
add methods
yuki-kimoto authored on 2009-11-02
581
}
582

            
add query cache system
yuki-kimoto authored on 2009-11-02
583
sub _query_caches     : ClassAttr { type => 'hash',
584
                                    auto_build => sub {shift->_query_caches({}) } }
585
                                    
586
sub _query_cache_keys : ClassAttr { type => 'array',
587
                                    auto_build => sub {shift->_query_cache_keys([])} }
588
                                    
589
sub query_cache_max   : ClassAttr { auto_build => sub {shift->query_cache_max(50)} }
590

            
591
# Add query cahce
592
sub _add_query_cache {
593
    my ($class, $template, $query) = @_;
594
    my $query_cache_keys = $class->_query_cache_keys;
595
    my $query_caches     = $class->_query_caches;
596
    
597
    return $class if $query_caches->{$template};
598
    
599
    $query_caches->{$template} = $query;
600
    push @$query_cache_keys, $template;
601
    
602
    my $overflow = @$query_cache_keys - $class->query_cache_max;
603
    
604
    for (my $i = 0; $i < $overflow; $i++) {
605
        my $template = shift @$query_cache_keys;
606
        delete $query_caches->{$template};
607
    }
608
    
609
    return $class;
610
}
add methods
yuki-kimoto authored on 2009-11-02
611

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

            
first commit
yuki-kimoto authored on 2009-10-13
614
=head1 NAME
615

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

            
618
=head1 VERSION
619

            
add test
yuki-kimoto authored on 2009-10-16
620
Version 0.0101
first commit
yuki-kimoto authored on 2009-10-13
621

            
cleanup
yuki-kimoto authored on 2009-10-31
622
=head1 CAUTION
623

            
624
This module is now experimental stage.
625

            
626
I want you to try this module
627
because I want this module stable, and not to damage your DB data by this module bug.
628

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

            
631
=head1 SYNOPSIS
632

            
add test
yuki-kimoto authored on 2009-10-16
633
  my $dbi = DBI::Custom->new;
add various thins
yuki-kimoto authored on 2009-10-29
634
  
635
  my $query = $dbi->create_query($template);
636
  $dbi->execute($query);
first commit
yuki-kimoto authored on 2009-10-13
637

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

            
update document
yuki-kimoto authored on 2009-10-27
640
=head2 user
641

            
642
    # Set and get database user name
643
    $self = $dbi->user($user);
644
    $user = $dbi->user;
645
    
646
    # Sample
647
    $dbi->user('taro');
648

            
649
=head2 password
650

            
651
    # Set and get database password
652
    $self     = $dbi->password($password);
653
    $password = $dbi->password;
654
    
655
    # Sample
656
    $dbi->password('lkj&le`@s');
657

            
658
=head2 data_source
659

            
660
    # Set and get database data source
661
    $self        = $dbi->data_source($data_soruce);
662
    $data_source = $dbi->data_source;
663
    
664
    # Sample(SQLite)
665
    $dbi->data_source(dbi:SQLite:dbname=$database);
666
    
667
    # Sample(MySQL);
668
    $dbi->data_source("dbi:mysql:dbname=$database");
669
    
670
    # Sample(PostgreSQL)
671
    $dbi->data_source("dbi:Pg:dbname=$database");
cleanup
yuki-kimoto authored on 2009-10-29
672
    
673
=head2 database
674

            
675
    # Set and get database name
676
    $self     = $dbi->database($database);
677
    $database = $dbi->database;
update document
yuki-kimoto authored on 2009-10-27
678

            
cleanup
yuki-kimoto authored on 2009-10-29
679
=head2 dbi_options
update document
yuki-kimoto authored on 2009-10-27
680

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

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

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

            
add prepare
yuki-kimoto authored on 2009-10-31
690
=head2 prepare
691

            
692
    $sth = $dbi->prepare($sql);
693

            
694
This method is same as DBI::prepare
695

            
696
=head2 do
697

            
698
    $dbi->do($sql, @bind_values);
699

            
700
This method is same as DBI::do
701

            
update document
yuki-kimoto authored on 2009-10-27
702
=head2 sql_template
703

            
704
    # Set and get SQL::Template object
705
    $self         = $dbi->sql_template($sql_template);
706
    $sql_template = $dbi->sql_template;
707
    
708
    # Sample
709
    $dbi->sql_template(DBI::Cutom::SQL::Template->new);
710

            
711
=head2 filters
712

            
713
    # Set and get filters
714
    $self    = $dbi->filters($filters);
715
    $filters = $dbi->filters;
first commit
yuki-kimoto authored on 2009-10-13
716

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

            
update document
yuki-kimoto authored on 2009-10-27
719
    # Set and get binding filter
720
    $self        = $dbi->bind_filter($bind_filter);
721
    $bind_filter = $dbi->bind_filter
first commit
yuki-kimoto authored on 2009-10-13
722

            
update document
yuki-kimoto authored on 2009-10-27
723
    # Sample
724
    $dbi->bind_filter($self->filters->{default_bind_filter});
725
    
first commit
yuki-kimoto authored on 2009-10-13
726

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

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

            
update document
yuki-kimoto authored on 2009-10-27
731
    # Set and get Fetch filter
732
    $self         = $dbi->fetch_filter($fetch_filter);
733
    $fetch_filter = $dbi->fetch_filter;
first commit
yuki-kimoto authored on 2009-10-13
734

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

            
add no_bind_filters
yuki-kimoto authored on 2009-10-30
738
=head2 no_bind_filters
739

            
740
    # Set and get no filter keys when binding
741
    $self            = $dbi->no_bind_filters($no_bind_filters);
742
    $no_bind_filters = $dbi->no_bind_filters;
743

            
744
=head2 no_fetch_filters
cleanup
yuki-kimoto authored on 2009-10-29
745

            
add no_bind_filters
yuki-kimoto authored on 2009-10-30
746
    # Set and get no filter keys when fetching
747
    $self             = $dbi->no_fetch_filters($no_fetch_filters);
748
    $no_fetch_filters = $dbi->no_fetch_filters;
cleanup
yuki-kimoto authored on 2009-10-29
749

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

            
update document
yuki-kimoto authored on 2009-10-27
752
    # Set and get resultset class
753
    $self         = $dbi->result_class($result_class);
754
    $result_class = $dbi->result_class;
755
    
756
    # Sample
757
    $dbi->result_class('DBI::Custom::Result');
add test
yuki-kimoto authored on 2009-10-17
758

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

            
update document
yuki-kimoto authored on 2009-10-27
761
    # Get database handle
762
    $dbh = $self->dbh;
add test
yuki-kimoto authored on 2009-10-17
763

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

            
update document
yuki-kimoto authored on 2009-10-27
766
=head2 connect
767

            
768
    # Connect to database
769
    $self = $dbi->connect;
770
    
771
    # Sample
772
    $dbi = DBI::Custom->new(user => 'taro', password => 'lji8(', 
773
                            data_soruce => "dbi:mysql:dbname=$database");
774
    $dbi->connect;
add tests
yuki-kimoto authored on 2009-10-18
775

            
776
=head2 disconnect
777

            
update document
yuki-kimoto authored on 2009-10-27
778
    # Disconnect database
779
    $dbi->disconnect;
780

            
781
If database is already disconnected, this method do noting.
782

            
add tests
yuki-kimoto authored on 2009-10-18
783
=head2 reconnect
784

            
update document
yuki-kimoto authored on 2009-10-27
785
    # Reconnect
786
    $dbi->reconnect;
787

            
788
=head2 connected
789

            
790
    # Check connected
791
    $dbi->connected
792

            
793
=head2 add_filter
794

            
795
    # Add filter (hash ref or hash can be recieve)
796
    $self = $dbi->add_filter({$filter_name => $filter, ...});
797
    $self = $dbi->add_filter($filetr_name => $filter, ...);
798
    
799
    # Sample
800
    $dbi->add_filter(
801
        decode_utf8 => sub {
cleanup
yuki-kimoto authored on 2009-10-30
802
            my ($key, $value, $table, $column) = @_;
update document
yuki-kimoto authored on 2009-10-27
803
            return Encode::decode('UTF-8', $value);
804
        },
805
        datetime_to_string => sub {
cleanup
yuki-kimoto authored on 2009-10-30
806
            my ($key, $value, $table, $column) = @_;
update document
yuki-kimoto authored on 2009-10-27
807
            return $value->strftime('%Y-%m-%d %H:%M:%S')
808
        },
809
        default_bind_filter => sub {
cleanup
yuki-kimoto authored on 2009-10-30
810
            my ($key, $value, $table, $column) = @_;
update document
yuki-kimoto authored on 2009-10-27
811
            if (ref $value eq 'Time::Piece') {
cleanup
yuki-kimoto authored on 2009-10-30
812
                return $dbi->filters->{datetime_to_string}->($value);
update document
yuki-kimoto authored on 2009-10-27
813
            }
814
            else {
cleanup
yuki-kimoto authored on 2009-10-30
815
                return $dbi->filters->{decode_utf8}->($value);
update document
yuki-kimoto authored on 2009-10-27
816
            }
817
        },
818
        
819
        encode_utf8 => sub {
cleanup
yuki-kimoto authored on 2009-10-30
820
            my ($key, $value) = @_;
update document
yuki-kimoto authored on 2009-10-27
821
            return Encode::encode('UTF-8', $value);
822
        },
823
        string_to_datetime => sub {
cleanup
yuki-kimoto authored on 2009-10-30
824
            my ($key, $value) = @_;
update document
yuki-kimoto authored on 2009-10-27
825
            return DateTime::Format::MySQL->parse_datetime($value);
826
        },
827
        default_fetch_filter => sub {
cleanup
yuki-kimoto authored on 2009-10-30
828
            my ($key, $value, $type, $sth, $i) = @_;
update document
yuki-kimoto authored on 2009-10-27
829
            if ($type eq 'DATETIME') {
cleanup
yuki-kimoto authored on 2009-10-30
830
                return $dbi->filters->{string_to_datetime}->($value);
update document
yuki-kimoto authored on 2009-10-27
831
            }
832
            else {
cleanup
yuki-kimoto authored on 2009-10-30
833
                return $dbi->filters->{encode_utf8}->($value);
update document
yuki-kimoto authored on 2009-10-27
834
            }
835
        }
836
    );
837

            
838
add_filter add filter to filters
add tests
yuki-kimoto authored on 2009-10-18
839

            
cleanup
yuki-kimoto authored on 2009-10-29
840
=head2 create_query
841
    
842
    # Create Query object from SQL template
843
    my $query = $dbi->create_query($template);
844
    
845
=head2 execute
update document
yuki-kimoto authored on 2009-10-27
846

            
847
    # Parse SQL template and execute SQL
cleanup
yuki-kimoto authored on 2009-10-29
848
    $result = $dbi->query($query, $params);
849
    $result = $dbi->query($template, $params); # Shorcut
update document
yuki-kimoto authored on 2009-10-27
850
    
851
    # Sample
852
    $result = $dbi->query("select * from authors where {= name} && {= age}", 
853
                          {author => 'taro', age => 19});
854
    
855
    while (my @row = $result->fetch) {
856
        # do something
857
    }
858

            
859
See also L<DBI::Custom::SQL::Template>
860

            
cleanup
yuki-kimoto authored on 2009-10-22
861
=head2 run_tranzaction
first commit
yuki-kimoto authored on 2009-10-13
862

            
update document
yuki-kimoto authored on 2009-10-27
863
    # Run tranzaction
864
    $dbi->run_tranzaction(sub {
865
        # do something
866
    });
first commit
yuki-kimoto authored on 2009-10-13
867

            
update document
yuki-kimoto authored on 2009-10-27
868
If tranzaction is success, commit is execute. 
869
If tranzation is died, rollback is execute.
first commit
yuki-kimoto authored on 2009-10-13
870

            
add methods
yuki-kimoto authored on 2009-11-02
871
=head2 insert
872

            
873
    # Insert
874
    $dbi->insert($table, $insert_values);
875
    
876
    # Sample
877
    $dbi->insert('books', {title => 'Perl', author => 'Taro'});
878

            
879
=head2 update
880

            
881
    # Update
882
    $dbi->update($table, $update_values, $where);
883
    
884
    # Sample
885
    $dbi->update('books', {title => 'Perl', author => 'Taro'}, {id => 5});
886

            
887
=head2 update_all
888

            
889
    # Update all rows
890
    $dbi->update($table, $updat_values);
891

            
892
=head2 delete
893

            
894
    # Delete
895
    $dbi->delete($table, $where);
896
    
897
    # Sample
898
    $dbi->delete('Books', {id => 5});
899

            
900
=head2 delete_all
901

            
902
    # Delete all rows
903
    $dbi->delete_all($table);
904

            
905
=head2 last_insert_id
906

            
907
    # Get last insert id
908
    $last_insert_id = $dbi->last_insert_id;
909
    
910
This method is same as DBI last_insert_id;
911

            
add query cache system
yuki-kimoto authored on 2009-11-02
912
=head1 Class Accessors
913

            
914
=head2 query_cache_max
915

            
916
    # Max query cache count
917
    $class           = $class->query_cache_max($query_cache_max);
918
    $query_cache_max = $class->query_cache_max;
919
    
920
    # Sample
921
    DBI::Custom->query_cache_max(50);
922

            
add tests
yuki-kimoto authored on 2009-10-31
923
=head1 CAUTION
924

            
925
DBI::Custom have DIB object internal.
926
This module is work well in the following DBI condition.
927

            
928
    1. AutoCommit is true
929
    2. RaiseError is true
930

            
931
By default, Both AutoCommit and RaiseError is true.
932
You must not change these mode not to damage your data.
933

            
934
If you change these mode, 
935
you cannot get correct error message, 
936
or run_tranzaction may fail.
937

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

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

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

            
first commit
yuki-kimoto authored on 2009-10-13
944
=head1 COPYRIGHT & LICENSE
945

            
946
Copyright 2009 Yuki Kimoto, all rights reserved.
947

            
948
This program is free software; you can redistribute it and/or modify it
949
under the same terms as Perl itself.
950

            
951
=cut