DBIx-Custom / lib / DBI / Custom.pm /
Newer Older
466 lines | 10.563kb
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;
add tests
yuki-kimoto authored on 2009-10-25
8
use DBI::Custom::SQL::Template;
add tests
yuki-kimoto authored on 2009-10-25
9
use DBI::Custom::Result;
add tests
yuki-kimoto authored on 2009-10-25
10

            
11
### Class-Object Accessors
update document
yuki-kimoto authored on 2009-10-27
12
sub user        : ClassObjectAttr { initialize => {clone => 'scalar'} }
13
sub password    : ClassObjectAttr { initialize => {clone => 'scalar'} }
14
sub data_source : ClassObjectAttr { initialize => {clone => 'scalar'} }
catch up Object::Simple upda...
yuki-kimoto authored on 2009-10-26
15

            
update document
yuki-kimoto authored on 2009-10-27
16
sub dbi_option : ClassObjectAttr { initialize => {clone => 'hash', 
17
                                                  default => sub { {} } } }
catch up Object::Simple upda...
yuki-kimoto authored on 2009-10-26
18

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

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

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

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

            
add tests
yuki-kimoto authored on 2009-10-25
45
### Object Accessor
add tests
yuki-kimoto authored on 2009-10-18
46
sub dbh          : Attr {}
add tests
yuki-kimoto authored on 2009-10-25
47

            
48

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

            
60
# Auto commit
update document
yuki-kimoto authored on 2009-10-27
61
sub _auto_commit {
add various
yuki-kimoto authored on 2009-10-18
62
    my $self = shift;
63
    
64
    croak("Cannot change AutoCommit becouse of not connected")
65
        unless $self->dbh;
66
    
67
    if (@_) {
68
        $self->dbh->{AutoCommit} = $_[0];
69
        return $self;
70
    }
71
    return $self->dbh->{AutoCommit};
72
}
add test
yuki-kimoto authored on 2009-10-16
73

            
add various things
yuki-kimoto authored on 2009-10-17
74
# Connect
add some method
yuki-kimoto authored on 2009-10-14
75
sub connect {
76
    my $self = shift;
update document
yuki-kimoto authored on 2009-10-27
77
    my $data_source = $self->data_source;
78
    my $user        = $self->user;
79
    my $password    = $self->password;
80
    my $dbi_option  = $self->dbi_option;
add test
yuki-kimoto authored on 2009-10-16
81
    
add some method
yuki-kimoto authored on 2009-10-14
82
    my $dbh = DBI->connect(
update document
yuki-kimoto authored on 2009-10-27
83
        $data_source,
84
        $user,
85
        $password,
add some method
yuki-kimoto authored on 2009-10-14
86
        {
87
            RaiseError => 1,
88
            PrintError => 0,
89
            AutoCommit => 1,
update document
yuki-kimoto authored on 2009-10-27
90
            %{$dbi_option || {} }
add some method
yuki-kimoto authored on 2009-10-14
91
        }
92
    );
93
    
94
    $self->dbh($dbh);
add various
yuki-kimoto authored on 2009-10-18
95
    return $self;
add some method
yuki-kimoto authored on 2009-10-14
96
}
first commit
yuki-kimoto authored on 2009-10-13
97

            
add tests
yuki-kimoto authored on 2009-10-25
98
# DESTROY
add tests
yuki-kimoto authored on 2009-10-18
99
sub DESTROY {
100
    my $self = shift;
add tests
yuki-kimoto authored on 2009-10-18
101
    $self->disconnect if $self->connected;
add tests
yuki-kimoto authored on 2009-10-18
102
}
103

            
add various things
yuki-kimoto authored on 2009-10-17
104
# Is connected?
105
sub connected {
106
    my $self = shift;
add tests
yuki-kimoto authored on 2009-10-18
107
    return exists $self->{dbh} && eval {$self->{dbh}->can('prepare')};
add various things
yuki-kimoto authored on 2009-10-17
108
}
109

            
110
# Disconnect
111
sub disconnect {
112
    my $self = shift;
add tests
yuki-kimoto authored on 2009-10-18
113
    if ($self->connected) {
add various things
yuki-kimoto authored on 2009-10-17
114
        $self->dbh->disconnect;
115
        delete $self->{dbh};
116
    }
117
}
118

            
119
# Reconnect
120
sub reconnect {
121
    my $self = shift;
add tests
yuki-kimoto authored on 2009-10-18
122
    $self->disconnect if $self->connected;
add various things
yuki-kimoto authored on 2009-10-17
123
    $self->connect;
124
}
125

            
try various
yuki-kimoto authored on 2009-10-21
126
# Run tranzaction
127
sub run_tranzaction {
128
    my ($self, $tranzaction) = @_;
129
    
update document
yuki-kimoto authored on 2009-10-27
130
    $self->_auto_commit(0);
try various
yuki-kimoto authored on 2009-10-21
131
    
132
    eval {
133
        $tranzaction->();
134
        $self->dbh->commit;
135
    };
136
    
137
    if ($@) {
138
        my $tranzaction_error = $@;
139
        
140
        $self->dbh->rollback or croak("$@ and rollback also failed");
141
        croak("$tranzaction_error");
142
    }
update document
yuki-kimoto authored on 2009-10-27
143
    $self->_auto_commit(1);
add tests
yuki-kimoto authored on 2009-10-18
144
}
145

            
cleanup
yuki-kimoto authored on 2009-10-18
146
# Create SQL from SQL template
update document
yuki-kimoto authored on 2009-10-27
147
sub _create_sql {
add test
yuki-kimoto authored on 2009-10-17
148
    my $self = shift;
149
    
150
    my ($sql, @bind) = $self->sql_template->create_sql(@_);
151
    
152
    return ($sql, @bind);
153
}
154

            
cleanup
yuki-kimoto authored on 2009-10-18
155
# Prepare and execute SQL
add some method
yuki-kimoto authored on 2009-10-14
156
sub query {
try varioud way
yuki-kimoto authored on 2009-10-17
157
    my ($self, $template, $values, $filter)  = @_;
158
    
add tests
yuki-kimoto authored on 2009-10-18
159
    my $sth_options;
160
    
161
    # Rearrange when argumets is hash referecne 
162
    if (ref $template eq 'HASH') {
163
        my $args = $template;
164
        ($template, $values, $filter, $sth_options)
165
          = @{$args}{qw/template values filter sth_options/};
166
    }
167
    
try varioud way
yuki-kimoto authored on 2009-10-17
168
    $filter ||= $self->bind_filter;
169
    
update document
yuki-kimoto authored on 2009-10-27
170
    my ($sql, @bind_values) = $self->_create_sql($template, $values, $filter);
add tests
yuki-kimoto authored on 2009-10-18
171
    
172
    $self->connect unless $self->connected;
173
    
add various things
yuki-kimoto authored on 2009-10-17
174
    my $sth = $self->dbh->prepare($sql);
add tests
yuki-kimoto authored on 2009-10-18
175
    
176
    if ($sth_options) {
177
        foreach my $key (keys %$sth_options) {
178
            $sth->{$key} = $sth_options->{$key};
179
        }
180
    }
181
    
cleanup
yuki-kimoto authored on 2009-10-18
182
    # Execute
update document
yuki-kimoto authored on 2009-10-27
183
    my $ret_val = $sth->execute(@bind_values);
add various things
yuki-kimoto authored on 2009-10-17
184
    
cleanup
yuki-kimoto authored on 2009-10-18
185
    # Return resultset if select statement is executed
add various things
yuki-kimoto authored on 2009-10-17
186
    if ($sth->{NUM_OF_FIELDS}) {
187
        my $result_class = $self->result_class;
add various
yuki-kimoto authored on 2009-10-18
188
        my $result = $result_class->new({
189
            sth => $sth,
190
            fetch_filter => $self->fetch_filter
191
        });
add various things
yuki-kimoto authored on 2009-10-17
192
        return $result;
193
    }
add tests
yuki-kimoto authored on 2009-10-18
194
    return $ret_val;
add test
yuki-kimoto authored on 2009-10-17
195
}
196

            
cleanup
yuki-kimoto authored on 2009-10-18
197
# Prepare and execute raw SQL
add test
yuki-kimoto authored on 2009-10-17
198
sub query_raw_sql {
cleanup
yuki-kimoto authored on 2009-10-18
199
    my ($self, $sql, @bind_values) = @_;
add tests
yuki-kimoto authored on 2009-10-18
200
    
cleanup
yuki-kimoto authored on 2009-10-18
201
    # Connect
add various
yuki-kimoto authored on 2009-10-18
202
    $self->connect unless $self->connected;
cleanup
yuki-kimoto authored on 2009-10-18
203
    
204
    # Add semicolon if not exist;
add tests
yuki-kimoto authored on 2009-10-18
205
    $sql .= ';' unless $sql =~ /;$/;
cleanup
yuki-kimoto authored on 2009-10-18
206
    
207
    # Prepare
add various things
yuki-kimoto authored on 2009-10-17
208
    my $sth = $self->dbh->prepare($sql);
cleanup
yuki-kimoto authored on 2009-10-18
209
    
210
    # Execute
update document
yuki-kimoto authored on 2009-10-27
211
    my $ret_val = $sth->execute(@bind_values);
cleanup
yuki-kimoto authored on 2009-10-18
212
    
update document
yuki-kimoto authored on 2009-10-27
213
    # Return resultset if select statement is executed
214
    if ($sth->{NUM_OF_FIELDS}) {
215
        my $result_class = $self->result_class;
216
        my $result = $result_class->new({
217
            sth => $sth,
218
            fetch_filter => $self->fetch_filter
219
        });
220
        return $result;
221
    }
222
    return $ret_val;
add test
yuki-kimoto authored on 2009-10-17
223
}
224

            
225
Object::Simple->build_class;
226

            
first commit
yuki-kimoto authored on 2009-10-13
227
=head1 NAME
228

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

            
231
=head1 VERSION
232

            
add test
yuki-kimoto authored on 2009-10-16
233
Version 0.0101
first commit
yuki-kimoto authored on 2009-10-13
234

            
235
=cut
236

            
237
=head1 SYNOPSIS
238

            
add test
yuki-kimoto authored on 2009-10-16
239
  my $dbi = DBI::Custom->new;
first commit
yuki-kimoto authored on 2009-10-13
240

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

            
update document
yuki-kimoto authored on 2009-10-27
243
=head2 user
244

            
245
    # Set and get database user name
246
    $self = $dbi->user($user);
247
    $user = $dbi->user;
248
    
249
    # Sample
250
    $dbi->user('taro');
251

            
252
=head2 password
253

            
254
    # Set and get database password
255
    $self     = $dbi->password($password);
256
    $password = $dbi->password;
257
    
258
    # Sample
259
    $dbi->password('lkj&le`@s');
260

            
261
=head2 data_source
262

            
263
    # Set and get database data source
264
    $self        = $dbi->data_source($data_soruce);
265
    $data_source = $dbi->data_source;
266
    
267
    # Sample(SQLite)
268
    $dbi->data_source(dbi:SQLite:dbname=$database);
269
    
270
    # Sample(MySQL);
271
    $dbi->data_source("dbi:mysql:dbname=$database");
272
    
273
    # Sample(PostgreSQL)
274
    $dbi->data_source("dbi:Pg:dbname=$database");
275

            
276
=head2 dbi_option
277

            
278
    # Set and get DBI option
279
    $self       = $dbi->dbi_option({$options => $value, ...});
280
    $dbi_option = $dbi->dbi_option;
281

            
282
    # Sample
283
    $dbi->dbi_option({PrintError => 0, RaiseError => 1});
284

            
285
dbi_option is used when you connect database by using connect.
286

            
287
=head2 sql_template
288

            
289
    # Set and get SQL::Template object
290
    $self         = $dbi->sql_template($sql_template);
291
    $sql_template = $dbi->sql_template;
292
    
293
    # Sample
294
    $dbi->sql_template(DBI::Cutom::SQL::Template->new);
295

            
296
=head2 filters
297

            
298
    # Set and get filters
299
    $self    = $dbi->filters($filters);
300
    $filters = $dbi->filters;
first commit
yuki-kimoto authored on 2009-10-13
301

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

            
update document
yuki-kimoto authored on 2009-10-27
304
    # Set and get binding filter
305
    $self        = $dbi->bind_filter($bind_filter);
306
    $bind_filter = $dbi->bind_filter
first commit
yuki-kimoto authored on 2009-10-13
307

            
update document
yuki-kimoto authored on 2009-10-27
308
    # Sample
309
    $dbi->bind_filter($self->filters->{default_bind_filter});
310
    
first commit
yuki-kimoto authored on 2009-10-13
311

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

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

            
update document
yuki-kimoto authored on 2009-10-27
316
    # Set and get Fetch filter
317
    $self         = $dbi->fetch_filter($fetch_filter);
318
    $fetch_filter = $dbi->fetch_filter;
first commit
yuki-kimoto authored on 2009-10-13
319

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

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

            
update document
yuki-kimoto authored on 2009-10-27
325
    # Set and get resultset class
326
    $self         = $dbi->result_class($result_class);
327
    $result_class = $dbi->result_class;
328
    
329
    # Sample
330
    $dbi->result_class('DBI::Custom::Result');
add test
yuki-kimoto authored on 2009-10-17
331

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

            
update document
yuki-kimoto authored on 2009-10-27
334
    # Get database handle
335
    $dbh = $self->dbh;
add test
yuki-kimoto authored on 2009-10-17
336

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

            
update document
yuki-kimoto authored on 2009-10-27
339
=head2 connect
340

            
341
    # Connect to database
342
    $self = $dbi->connect;
343
    
344
    # Sample
345
    $dbi = DBI::Custom->new(user => 'taro', password => 'lji8(', 
346
                            data_soruce => "dbi:mysql:dbname=$database");
347
    $dbi->connect;
add tests
yuki-kimoto authored on 2009-10-18
348

            
349
=head2 disconnect
350

            
update document
yuki-kimoto authored on 2009-10-27
351
    # Disconnect database
352
    $dbi->disconnect;
353

            
354
If database is already disconnected, this method do noting.
355

            
add tests
yuki-kimoto authored on 2009-10-18
356
=head2 reconnect
357

            
update document
yuki-kimoto authored on 2009-10-27
358
    # Reconnect
359
    $dbi->reconnect;
360

            
361
=head2 connected
362

            
363
    # Check connected
364
    $dbi->connected
365

            
366
=head2 add_filter
367

            
368
    # Add filter (hash ref or hash can be recieve)
369
    $self = $dbi->add_filter({$filter_name => $filter, ...});
370
    $self = $dbi->add_filter($filetr_name => $filter, ...);
371
    
372
    # Sample
373
    $dbi->add_filter(
374
        decode_utf8 => sub {
375
            my $value = shift;
376
            return Encode::decode('UTF-8', $value);
377
        },
378
        datetime_to_string => sub {
379
            my $value = shift;
380
            return $value->strftime('%Y-%m-%d %H:%M:%S')
381
        },
382
        default_bind_filter => sub {
383
            my ($value, $key, $filters) = @_;
384
            if (ref $value eq 'Time::Piece') {
385
                return $filters->{datetime_to_string}->($value);
386
            }
387
            else {
388
                return $filters->{decode_utf8}->($value);
389
            }
390
        },
391
        
392
        encode_utf8 => sub {
393
            my $value = shift;
394
            return Encode::encode('UTF-8', $value);
395
        },
396
        string_to_datetime => sub {
397
            my $value = shift;
398
            return DateTime::Format::MySQL->parse_datetime($value);
399
        },
400
        default_fetch_filter => sub {
401
            my ($value, $key, $filters, $type, $sth, $i) = @_;
402
            if ($type eq 'DATETIME') {
403
                return $self->filters->{string_to_datetime}->($value);
404
            }
405
            else {
406
                return $self->filters->{encode_utf8}->($value);
407
            }
408
        }
409
    );
410

            
411
add_filter add filter to filters
add tests
yuki-kimoto authored on 2009-10-18
412

            
update document
yuki-kimoto authored on 2009-10-27
413
=head2 query
414

            
415
    # Parse SQL template and execute SQL
416
    $result = $dbi->query($sql_template, $param);
417
    $result = $dbi->query($sql_template, $param, $bind_filter);
418
    
419
    # Sample
420
    $result = $dbi->query("select * from authors where {= name} && {= age}", 
421
                          {author => 'taro', age => 19});
422
    
423
    while (my @row = $result->fetch) {
424
        # do something
425
    }
426

            
427
See also L<DBI::Custom::SQL::Template>
428

            
429
=head2 query_raw_sql
430

            
431
    # Execute SQL
432
    $result = $dbi->query_raw_sql($sql, @bind_values);
433
    
434
    # Sample
435
    $result = $dbi->query("select * from table where name = ?, 
436
                          title = ?;", 'taro', 'perl');
437
    
438
    while (my @row = $result->fetch) {
439
        # do something
440
    }
441
    
cleanup
yuki-kimoto authored on 2009-10-22
442
=head2 run_tranzaction
first commit
yuki-kimoto authored on 2009-10-13
443

            
update document
yuki-kimoto authored on 2009-10-27
444
    # Run tranzaction
445
    $dbi->run_tranzaction(sub {
446
        # do something
447
    });
first commit
yuki-kimoto authored on 2009-10-13
448

            
update document
yuki-kimoto authored on 2009-10-27
449
If tranzaction is success, commit is execute. 
450
If tranzation is died, rollback is execute.
first commit
yuki-kimoto authored on 2009-10-13
451

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

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

            
456
=head1 COPYRIGHT & LICENSE
457

            
458
Copyright 2009 Yuki Kimoto, all rights reserved.
459

            
460
This program is free software; you can redistribute it and/or modify it
461
under the same terms as Perl itself.
462

            
463

            
464
=cut
465

            
466
1; # End of DBI::Custom