DBIx-Custom / lib / DBI / Custom.pm /
Newer Older
715 lines | 17.358kb
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;
first commit
yuki-kimoto authored on 2009-10-13
8

            
cleanup
yuki-kimoto authored on 2009-10-15
9
# Model
try various
yuki-kimoto authored on 2009-10-21
10
sub prototype : ClassAttr { auto_build => sub {
add test
yuki-kimoto authored on 2009-10-16
11
    my $class = shift;
cleanup
yuki-kimoto authored on 2009-10-15
12
    my $super = do {
13
        no strict 'refs';
14
        ${"${class}::ISA"}[0];
15
    };
cleanup
yuki-kimoto authored on 2009-10-21
16
    my $prototype = eval{$super->can('prototype')}
17
                         ? $super->prototype->clone
cleanup
yuki-kimoto authored on 2009-10-15
18
                         : $class->Object::Simple::new;
cleanup
yuki-kimoto authored on 2009-10-14
19
    
cleanup
yuki-kimoto authored on 2009-10-21
20
    $class->prototype($prototype);
try various
yuki-kimoto authored on 2009-10-21
21
}}
first commit
yuki-kimoto authored on 2009-10-13
22

            
cleanup
yuki-kimoto authored on 2009-10-15
23
# New
24
sub new {
25
    my $self = shift->Object::Simple::new(@_);
26
    my $class = ref $self;
cleanup
yuki-kimoto authored on 2009-10-21
27
    return bless {%{$class->prototype->clone}, %{$self}}, $class;
first commit
yuki-kimoto authored on 2009-10-13
28
}
29

            
cleanup
yuki-kimoto authored on 2009-10-21
30
# Initialize class
31
sub initialize_class {
cleanup
yuki-kimoto authored on 2009-10-15
32
    my ($class, $callback) = @_;
first commit
yuki-kimoto authored on 2009-10-13
33
    
cleanup
yuki-kimoto authored on 2009-10-21
34
    # Callback to initialize prototype
35
    $callback->($class->prototype);
first commit
yuki-kimoto authored on 2009-10-13
36
}
37

            
cleanup
yuki-kimoto authored on 2009-10-15
38
# Clone
39
sub clone {
cleanup
yuki-kimoto authored on 2009-10-14
40
    my $self = shift;
cleanup
yuki-kimoto authored on 2009-10-15
41
    my $new = $self->Object::Simple::new;
try various
yuki-kimoto authored on 2009-10-21
42
    
add test
yuki-kimoto authored on 2009-10-16
43
    $new->connect_info(%{$self->connect_info || {}});
try various
yuki-kimoto authored on 2009-10-21
44
    $new->connect_info->{options} = \%{$self->connect_info->{options}};
45
    
cleanup
yuki-kimoto authored on 2009-10-15
46
    $new->filters(%{$self->filters || {}});
add test
yuki-kimoto authored on 2009-10-16
47
    $new->bind_filter($self->bind_filter);
48
    $new->fetch_filter($self->fetch_filter);
add various things
yuki-kimoto authored on 2009-10-17
49
    $new->result_class($self->result_class);
try various
yuki-kimoto authored on 2009-10-21
50
    
51
    $new->sql_template($self->sql_template->clone);
cleanup
yuki-kimoto authored on 2009-10-14
52
}
53

            
cleanup
yuki-kimoto authored on 2009-10-15
54
# Attribute
55
sub connect_info       : Attr { type => 'hash',  auto_build => sub { shift->connect_info({}) } }
cleanup
yuki-kimoto authored on 2009-10-15
56

            
add tests
yuki-kimoto authored on 2009-10-18
57
sub bind_filter  : Attr {}
add test
yuki-kimoto authored on 2009-10-16
58
sub fetch_filter : Attr {}
cleanup
yuki-kimoto authored on 2009-10-15
59

            
add test
yuki-kimoto authored on 2009-10-16
60
sub filters : Attr { type => 'hash', deref => 1, auto_build => sub { shift->filters({}) } }
cleanup
yuki-kimoto authored on 2009-10-15
61
sub add_filter { shift->filters(@_) }
62

            
add tests
yuki-kimoto authored on 2009-10-18
63
sub result_class : Attr { auto_build => sub { shift->result_class('DBI::Custom::Result') }}
add tests
yuki-kimoto authored on 2009-10-18
64
sub dbh          : Attr {}
cleanup
yuki-kimoto authored on 2009-10-21
65
sub sql_template : Attr { auto_build => sub { shift->sql_template(DBI::Custom::SQL::Template->new) } }
add various
yuki-kimoto authored on 2009-10-18
66

            
67
# Auto commit
68
sub auto_commit {
69
    my $self = shift;
70
    
71
    croak("Cannot change AutoCommit becouse of not connected")
72
        unless $self->dbh;
73
    
74
    if (@_) {
75
        $self->dbh->{AutoCommit} = $_[0];
76
        return $self;
77
    }
78
    return $self->dbh->{AutoCommit};
79
}
add test
yuki-kimoto authored on 2009-10-16
80

            
try various
yuki-kimoto authored on 2009-10-21
81
sub valid_connect_info : Attr { default => sub {
82
    {map {$_ => 1} qw/data_source user password options/}
83
}}
cleanup
yuki-kimoto authored on 2009-10-14
84

            
add various things
yuki-kimoto authored on 2009-10-17
85
# Connect
add some method
yuki-kimoto authored on 2009-10-14
86
sub connect {
87
    my $self = shift;
88
    my $connect_info = $self->connect_info;
89
    
add test
yuki-kimoto authored on 2009-10-16
90
    foreach my $key (keys %{$self->connect_info}) {
add test module
yuki-kimoto authored on 2009-10-19
91
        croak("connect_info '$key' is wrong name")
try various
yuki-kimoto authored on 2009-10-21
92
          unless $self->valid_connect_info->{$key};
add test
yuki-kimoto authored on 2009-10-16
93
    }
94
    
add some method
yuki-kimoto authored on 2009-10-14
95
    my $dbh = DBI->connect(
add test
yuki-kimoto authored on 2009-10-16
96
        $connect_info->{data_source},
add some method
yuki-kimoto authored on 2009-10-14
97
        $connect_info->{user},
98
        $connect_info->{password},
99
        {
100
            RaiseError => 1,
101
            PrintError => 0,
102
            AutoCommit => 1,
103
            %{$connect_info->{options} || {} }
104
        }
105
    );
106
    
107
    $self->dbh($dbh);
add various
yuki-kimoto authored on 2009-10-18
108
    return $self;
add some method
yuki-kimoto authored on 2009-10-14
109
}
first commit
yuki-kimoto authored on 2009-10-13
110

            
add tests
yuki-kimoto authored on 2009-10-18
111
sub DESTROY {
112
    my $self = shift;
add tests
yuki-kimoto authored on 2009-10-18
113
    $self->disconnect if $self->connected;
add tests
yuki-kimoto authored on 2009-10-18
114
}
115

            
add various things
yuki-kimoto authored on 2009-10-17
116
# Is connected?
117
sub connected {
118
    my $self = shift;
add tests
yuki-kimoto authored on 2009-10-18
119
    return exists $self->{dbh} && eval {$self->{dbh}->can('prepare')};
add various things
yuki-kimoto authored on 2009-10-17
120
}
121

            
122
# Disconnect
123
sub disconnect {
124
    my $self = shift;
add tests
yuki-kimoto authored on 2009-10-18
125
    if ($self->connected) {
add various things
yuki-kimoto authored on 2009-10-17
126
        $self->dbh->disconnect;
127
        delete $self->{dbh};
128
    }
129
}
130

            
131
# Reconnect
132
sub reconnect {
133
    my $self = shift;
add tests
yuki-kimoto authored on 2009-10-18
134
    $self->disconnect if $self->connected;
add various things
yuki-kimoto authored on 2009-10-17
135
    $self->connect;
136
}
137

            
try various
yuki-kimoto authored on 2009-10-21
138
# Run tranzaction
139
sub run_tranzaction {
140
    my ($self, $tranzaction) = @_;
141
    
142
    $self->auto_commit(0);
143
    
144
    eval {
145
        $tranzaction->();
146
        $self->dbh->commit;
147
    };
148
    
149
    if ($@) {
150
        my $tranzaction_error = $@;
151
        
152
        $self->dbh->rollback or croak("$@ and rollback also failed");
153
        croak("$tranzaction_error");
154
    }
155
    $self->auto_commit(1);
add tests
yuki-kimoto authored on 2009-10-18
156
}
157

            
add tests
yuki-kimoto authored on 2009-10-18
158
sub dbh_option {
159
    my $self = shift;
160
    croak("Not connected") unless $self->connected;
161
    my $dbh = $self->dbh;
162
    if (@_ > 1) {
163
        $dbh->{$_[0]} = $_[1];
164
        return $self;
165
    }
166
    return $dbh->{$_[0]}
167
}
168

            
cleanup
yuki-kimoto authored on 2009-10-18
169
# Create SQL from SQL template
add test
yuki-kimoto authored on 2009-10-17
170
sub create_sql {
171
    my $self = shift;
172
    
173
    my ($sql, @bind) = $self->sql_template->create_sql(@_);
174
    
175
    return ($sql, @bind);
176
}
177

            
cleanup
yuki-kimoto authored on 2009-10-18
178
# Prepare and execute SQL
add some method
yuki-kimoto authored on 2009-10-14
179
sub query {
try varioud way
yuki-kimoto authored on 2009-10-17
180
    my ($self, $template, $values, $filter)  = @_;
181
    
add tests
yuki-kimoto authored on 2009-10-18
182
    my $sth_options;
183
    
184
    # Rearrange when argumets is hash referecne 
185
    if (ref $template eq 'HASH') {
186
        my $args = $template;
187
        ($template, $values, $filter, $sth_options)
188
          = @{$args}{qw/template values filter sth_options/};
189
    }
190
    
try varioud way
yuki-kimoto authored on 2009-10-17
191
    $filter ||= $self->bind_filter;
192
    
add various things
yuki-kimoto authored on 2009-10-17
193
    my ($sql, @bind) = $self->create_sql($template, $values, $filter);
add tests
yuki-kimoto authored on 2009-10-18
194
    
195
    $self->connect unless $self->connected;
196
    
add various things
yuki-kimoto authored on 2009-10-17
197
    my $sth = $self->dbh->prepare($sql);
add tests
yuki-kimoto authored on 2009-10-18
198
    
199
    if ($sth_options) {
200
        foreach my $key (keys %$sth_options) {
201
            $sth->{$key} = $sth_options->{$key};
202
        }
203
    }
204
    
cleanup
yuki-kimoto authored on 2009-10-18
205
    # Execute
add tests
yuki-kimoto authored on 2009-10-18
206
    my $ret_val = $sth->execute(@bind);
add various things
yuki-kimoto authored on 2009-10-17
207
    
cleanup
yuki-kimoto authored on 2009-10-18
208
    # Return resultset if select statement is executed
add various things
yuki-kimoto authored on 2009-10-17
209
    if ($sth->{NUM_OF_FIELDS}) {
210
        my $result_class = $self->result_class;
add various
yuki-kimoto authored on 2009-10-18
211
        my $result = $result_class->new({
212
            sth => $sth,
213
            fetch_filter => $self->fetch_filter
214
        });
add various things
yuki-kimoto authored on 2009-10-17
215
        return $result;
216
    }
add tests
yuki-kimoto authored on 2009-10-18
217
    return $ret_val;
add test
yuki-kimoto authored on 2009-10-17
218
}
219

            
cleanup
yuki-kimoto authored on 2009-10-18
220
# Prepare and execute raw SQL
add test
yuki-kimoto authored on 2009-10-17
221
sub query_raw_sql {
cleanup
yuki-kimoto authored on 2009-10-18
222
    my ($self, $sql, @bind_values) = @_;
add tests
yuki-kimoto authored on 2009-10-18
223
    
cleanup
yuki-kimoto authored on 2009-10-18
224
    # Connect
add various
yuki-kimoto authored on 2009-10-18
225
    $self->connect unless $self->connected;
cleanup
yuki-kimoto authored on 2009-10-18
226
    
227
    # Add semicolon if not exist;
add tests
yuki-kimoto authored on 2009-10-18
228
    $sql .= ';' unless $sql =~ /;$/;
cleanup
yuki-kimoto authored on 2009-10-18
229
    
230
    # Prepare
add various things
yuki-kimoto authored on 2009-10-17
231
    my $sth = $self->dbh->prepare($sql);
cleanup
yuki-kimoto authored on 2009-10-18
232
    
233
    # Execute
234
    $sth->execute(@bind_values);
235
    
add various things
yuki-kimoto authored on 2009-10-17
236
    return $sth;
add test
yuki-kimoto authored on 2009-10-17
237
}
238

            
239
Object::Simple->build_class;
240

            
add various things
yuki-kimoto authored on 2009-10-17
241
package DBI::Custom::Result;
242
use Object::Simple;
243

            
cleanup
yuki-kimoto authored on 2009-10-21
244
# Attributes
add various
yuki-kimoto authored on 2009-10-18
245
sub sth          : Attr {}
246
sub fetch_filter : Attr {}
add various things
yuki-kimoto authored on 2009-10-17
247

            
cleanup
yuki-kimoto authored on 2009-10-21
248

            
cleanup
yuki-kimoto authored on 2009-10-19
249
# Fetch (array)
add various
yuki-kimoto authored on 2009-10-18
250
sub fetch {
251
    my ($self, $type) = @_;
252
    my $sth = $self->sth;
add various
yuki-kimoto authored on 2009-10-18
253
    my $fetch_filter = $self->fetch_filter;
cleanup
yuki-kimoto authored on 2009-10-19
254
    
255
    # Fetch
256
    my $row = $sth->fetchrow_arrayref;
257
    
258
    # Cannot fetch
259
    return unless $row;
260
    
261
    # Filter
262
    if ($fetch_filter) {
add tests
yuki-kimoto authored on 2009-10-19
263
        my $keys  = $sth->{NAME_lc};
264
        my $types = $sth->{TYPE};
cleanup
yuki-kimoto authored on 2009-10-19
265
        for (my $i = 0; $i < @$keys; $i++) {
cleanup
yuki-kimoto authored on 2009-10-21
266
            $row->[$i]= $fetch_filter->($keys->[$i], $row->[$i], $types->[$i],
267
                                        $sth, $i);
add various
yuki-kimoto authored on 2009-10-18
268
        }
add various
yuki-kimoto authored on 2009-10-18
269
    }
cleanup
yuki-kimoto authored on 2009-10-19
270
    return wantarray ? @$row : $row;
271
}
272

            
273
# Fetch (hash)
274
sub fetch_hash {
275
    my $self = shift;
276
    my $sth = $self->sth;
277
    my $fetch_filter = $self->fetch_filter;
278
    
279
    # Fetch
add tests
yuki-kimoto authored on 2009-10-19
280
    my $row = $sth->fetchrow_arrayref;
cleanup
yuki-kimoto authored on 2009-10-19
281
    
282
    # Cannot fetch
283
    return unless $row;
284
    
add tests
yuki-kimoto authored on 2009-10-19
285
    # Keys
286
    my $keys  = $sth->{NAME_lc};
287
    
cleanup
yuki-kimoto authored on 2009-10-19
288
    # Filter
add tests
yuki-kimoto authored on 2009-10-19
289
    my $row_hash = {};
cleanup
yuki-kimoto authored on 2009-10-19
290
    if ($fetch_filter) {
add tests
yuki-kimoto authored on 2009-10-19
291
        my $types = $sth->{TYPE};
292
        for (my $i = 0; $i < @$keys; $i++) {
cleanup
yuki-kimoto authored on 2009-10-21
293
            $row_hash->{$keys->[$i]} = $fetch_filter->($keys->[$i], $row->[$i],
294
                                                       $types->[$i], $sth, $i);
add various
yuki-kimoto authored on 2009-10-18
295
        }
add various
yuki-kimoto authored on 2009-10-18
296
    }
cleanup
yuki-kimoto authored on 2009-10-21
297
    
298
    # No filter
add tests
yuki-kimoto authored on 2009-10-19
299
    else {
300
        for (my $i = 0; $i < @$keys; $i++) {
301
            $row_hash->{$keys->[$i]} = $row->[$i];
302
        }
303
    }
304
    return wantarray ? %$row_hash : $row_hash;
add various
yuki-kimoto authored on 2009-10-18
305
}
add various things
yuki-kimoto authored on 2009-10-17
306

            
cleanup
yuki-kimoto authored on 2009-10-19
307
# Fetch all (array)
add various
yuki-kimoto authored on 2009-10-18
308
sub fetch_all {
cleanup
yuki-kimoto authored on 2009-10-19
309
    my $self = shift;
add various
yuki-kimoto authored on 2009-10-18
310
    
cleanup
yuki-kimoto authored on 2009-10-19
311
    my $rows = [];
add tests
yuki-kimoto authored on 2009-10-19
312
    while(my @row = $self->fetch) {
313
        push @$rows, [@row];
add various
yuki-kimoto authored on 2009-10-18
314
    }
cleanup
yuki-kimoto authored on 2009-10-19
315
    return wantarray ? @$rows : $rows;
316
}
317

            
318
# Fetch all (hash)
319
sub fetch_all_hash {
320
    my $self = shift;
321
    
322
    my $rows = [];
323
    while(my %row = $self->fetch_hash) {
324
        push @$rows, {%row};
add various
yuki-kimoto authored on 2009-10-18
325
    }
cleanup
yuki-kimoto authored on 2009-10-19
326
    return wantarray ? @$rows : $rows;
add various
yuki-kimoto authored on 2009-10-18
327
}
add various things
yuki-kimoto authored on 2009-10-17
328

            
cleanup
yuki-kimoto authored on 2009-10-21
329
# Finish
add various
yuki-kimoto authored on 2009-10-18
330
sub finish { shift->sth->finish }
add various things
yuki-kimoto authored on 2009-10-17
331

            
cleanup
yuki-kimoto authored on 2009-10-21
332
# Error
333
sub error { 
334
    my $self = shift;
335
    my $sth  = $self->sth;
336
    wantarray ? ($sth->errstr, $sth->err, $sth->state) : $sth->errstr;
337
}
338

            
add various things
yuki-kimoto authored on 2009-10-17
339
Object::Simple->build_class;
340

            
341

            
cleanup
yuki-kimoto authored on 2009-10-21
342
package DBI::Custom::SQL::Template;
add test
yuki-kimoto authored on 2009-10-17
343
use Object::Simple;
try various way
yuki-kimoto authored on 2009-10-17
344
use Carp 'croak';
add test
yuki-kimoto authored on 2009-10-17
345

            
try various
yuki-kimoto authored on 2009-10-21
346
sub clone {
347
    my $self = shift;
348
    my $new = $self->Object::Simple::new;
349
    
350
    $new->tag_start($self->tag_start);
351
    $new->tag_end($self->tag_end);
352
    $new->bind_filter($self->bind_filter);
353
    $new->upper_case($self->upper_case);
354
    $new->tag_syntax($self->tag_syntax);
355
}
356

            
try varioud way
yuki-kimoto authored on 2009-10-17
357
### Attributes;
try various way
yuki-kimoto authored on 2009-10-17
358
sub tag_start   : Attr { default => '{' }
359
sub tag_end     : Attr { default => '}' }
360
sub template    : Attr {};
361
sub tree        : Attr { auto_build => sub { shift->tree([]) } }
362
sub bind_filter : Attr {}
363
sub values      : Attr {}
364
sub upper_case  : Attr {default => 0}
try varioud way
yuki-kimoto authored on 2009-10-17
365

            
add test
yuki-kimoto authored on 2009-10-17
366
sub create_sql {
try varioud way
yuki-kimoto authored on 2009-10-17
367
    my ($self, $template, $values, $filter)  = @_;
368
    
try various way
yuki-kimoto authored on 2009-10-17
369
    $filter ||= $self->bind_filter;
370
    
try varioud way
yuki-kimoto authored on 2009-10-17
371
    $self->parse($template);
372
    
try various way
yuki-kimoto authored on 2009-10-17
373
    my ($sql, @bind) = $self->build_sql({bind_filter => $filter, values => $values});
try varioud way
yuki-kimoto authored on 2009-10-17
374
    
375
    return ($sql, @bind);
376
}
377

            
try various
yuki-kimoto authored on 2009-10-21
378
sub tag_syntax : Attr { default => <<'EOS' };
add test module
yuki-kimoto authored on 2009-10-19
379
{? name}         ?
try varioud way
yuki-kimoto authored on 2009-10-17
380
{= name}         name = ?
try various way
yuki-kimoto authored on 2009-10-17
381
{<> name}        name <> ?
try varioud way
yuki-kimoto authored on 2009-10-17
382

            
383
{< name}         name < ?
384
{> name}         name > ?
385
{>= name}        name >= ?
386
{<= name}        name <= ?
387

            
388
{like name}      name like ?
389
{in name}        name in [?, ?, ..]
390

            
391
{insert_values}  (key1, key2, key3) values (?, ?, ?)
392
{update_values}  set key1 = ?, key2 = ?, key3 = ?
393
EOS
394

            
395
sub parse {
396
    my ($self, $template) = @_;
397
    $self->template($template);
398
    
399
    # Clean start;
400
    delete $self->{tree};
401
    
402
    # Tags
403
    my $tag_start = quotemeta $self->tag_start;
404
    my $tag_end   = quotemeta $self->tag_end;
first commit
yuki-kimoto authored on 2009-10-13
405
    
try varioud way
yuki-kimoto authored on 2009-10-17
406
    # Tokenize
407
    my $state = 'text';
408
    
409
    # Save original template
410
    my $original_template = $template;
411
    
412
    # Text
413
    while ($template =~ s/([^$tag_start]*?)$tag_start([^$tag_end].*?)$tag_end//sm) {
try various way
yuki-kimoto authored on 2009-10-17
414
        my $text = $1;
try varioud way
yuki-kimoto authored on 2009-10-17
415
        my $tag  = $2;
416
        
try various way
yuki-kimoto authored on 2009-10-17
417
        push @{$self->tree}, {type => 'text', args => [$text]} if $text;
try varioud way
yuki-kimoto authored on 2009-10-17
418
        
419
        if ($tag) {
420
            
try various way
yuki-kimoto authored on 2009-10-17
421
            my ($tag_name, @args) = split /\s+/, $tag;
try varioud way
yuki-kimoto authored on 2009-10-17
422
            
try various way
yuki-kimoto authored on 2009-10-17
423
            $tag ||= '';
try various
yuki-kimoto authored on 2009-10-21
424
            unless ($self->tag_processors->{$tag_name}) {
425
                my $tag_syntax = $self->tag_syntax;
426
                croak("Tag '$tag' in SQL template is not exist.\n\n" .
427
                      "SQL template tag syntax\n" .
428
                      "$tag_syntax\n\n" .
429
                      "Your SQL template is \n$original_template\n\n");
430
            }
try varioud way
yuki-kimoto authored on 2009-10-17
431
            
try various way
yuki-kimoto authored on 2009-10-17
432
            push @{$self->tree}, {type => 'tag', tag_name => $tag_name, args => [@args]};
try varioud way
yuki-kimoto authored on 2009-10-17
433
        }
434
    }
435
    
try various way
yuki-kimoto authored on 2009-10-17
436
    push @{$self->tree}, {type => 'text', args => [$template]} if $template;
first commit
yuki-kimoto authored on 2009-10-13
437
}
438

            
try various way
yuki-kimoto authored on 2009-10-17
439
sub build_sql {
440
    my ($self, $args) = @_;
441
    
442
    my $tree        = $args->{tree} || $self->tree;
443
    my $bind_filter = $args->{bind_filter} || $self->bind_filter;
444
    my $values      = exists $args->{values} ? $args->{values} : $self->values;
445
    
try various
yuki-kimoto authored on 2009-10-21
446
    my @bind_values_all;
try various way
yuki-kimoto authored on 2009-10-17
447
    my $sql = '';
448
    foreach my $node (@$tree) {
449
        my $type     = $node->{type};
450
        my $tag_name = $node->{tag_name};
451
        my $args     = $node->{args};
452
        
453
        if ($type eq 'text') {
454
            # Join text
455
            $sql .= $args->[0];
456
        }
457
        elsif ($type eq 'tag') {
try various
yuki-kimoto authored on 2009-10-21
458
            my $tag_processor = $self->tag_processors->{$type};
459
            
460
            croak("Tag processor '$type' must be code reference")
461
              unless ref $tag_processor eq 'CODE';
462
            
463
            my ($expand, @bind_values)
464
              = $self->tag_processors->{$type}->($tag_name, $args, $values,
465
                                                 $bind_filter, $self);
466
            
467
            unless ($self->place_holder_count($expand) eq @bind_values) {
468
                require Data::Dumper;
try various way
yuki-kimoto authored on 2009-10-17
469
                
try various
yuki-kimoto authored on 2009-10-21
470
                my $bind_values_dump
471
                  = Data::Dumper->Dump([\@bind_values], ['@bind_values']);
try various way
yuki-kimoto authored on 2009-10-17
472
                
try various
yuki-kimoto authored on 2009-10-21
473
                croak("Place holder count must be same as bind value count\n" .
474
                      "Tag        : $tag_name\n" .
475
                      "Expand     : $expand\n" .
476
                      "Bind values: $bind_values_dump\n");
try various way
yuki-kimoto authored on 2009-10-17
477
            }
try various
yuki-kimoto authored on 2009-10-21
478
            push @bind_values_all, @bind_values;
479
            $sql .= $expand;
try various way
yuki-kimoto authored on 2009-10-17
480
        }
481
    }
482
    $sql .= ';' unless $sql =~ /;$/;
try various
yuki-kimoto authored on 2009-10-21
483
    return ($sql, @bind_values_all);
484
}
485

            
486
sub _placeholder_count {
487
    my ($self, $expand) = @_;
488
    $expand ||= '';
489
    
490
    my $count = 0;
491
    my $pos   = 0;
492
    while ((my $pos = index $expand, $pos) != -1) {
493
        $count++;
494
    }
495
    return $count;
try various way
yuki-kimoto authored on 2009-10-17
496
}
try varioud way
yuki-kimoto authored on 2009-10-17
497

            
cleanup
yuki-kimoto authored on 2009-10-21
498
sub tag_processors : Attr {type => 'hash', deref => 1, auto_build => sub { 
499
    shift->tag_processors(
try various
yuki-kimoto authored on 2009-10-21
500
        '?'             => \&DBI::Custom::SQL::Template::TagProcessor::expand_place_holder,
501
        '='             => \&DBI::Custom::SQL::Template::TagProcessor::expand_place_holder,
502
        '<>'            => \&DBI::Custom::SQL::Template::TagProcessor::expand_place_holder,
503
        '<'             => \&DBI::Custom::SQL::Template::TagProcessor::expand_place_holder,
504
        '>='            => \&DBI::Custom::SQL::Template::TagProcessor::expand_place_holder,
505
        '<='            => \&DBI::Custom::SQL::Template::TagProcessor::expand_place_holder,
506
        'like'          => \&DBI::Custom::SQL::Template::TagProcessor::expand_place_holder,
507
        'in'            => \&DBI::Custom::SQL::Template::TagProcessor::expand_place_holder,
508
        'insert_values' => \&DBI::Custom::SQL::Template::TagProcessor::expand_insert_values,
509
        'update_set'    => \&DBI::Custom::SQL::Template::TagProcessor::expand_update_set
cleanup
yuki-kimoto authored on 2009-10-21
510
    );
511
}}
512

            
513
sub add_tag_processor {
try various
yuki-kimoto authored on 2009-10-21
514
    my $class = shift;
515
    my $tag_processors = ref $_[0] eq 'HASH' ? $_[0] : {@_};
516
    $class->tag_processor(%{$class->tag_processor}, %{$tag_processors});
cleanup
yuki-kimoto authored on 2009-10-21
517
}
try varioud way
yuki-kimoto authored on 2009-10-17
518

            
first commit
yuki-kimoto authored on 2009-10-13
519
Object::Simple->build_class;
520

            
cleanup
yuki-kimoto authored on 2009-10-21
521

            
522
package DBI::Custom::SQL::Template::TagProcessor;
523

            
524
sub expand_place_holder {
525
    my ($tag_name, $args, $values, $bind_filter, $sql_tmpl_obj) = @_;
526
    
527
    my $key = $args->[0];
528
    
529
    my @bind_values;
530
    # Filter Value
531
    if ($tag_name eq 'in') {
532
        $values->{$key} = [$values->{$key}] unless ref $values->{$key} eq 'ARRAY';
533
        if ($bind_filter) {
534
            for (my $i = 0; $i < @$values; $i++) {
535
                push @bind_values, scalar $bind_filter->($key, $values->{$key}->[$i]);
536
            }
537
        }
538
        else {
539
            for (my $i = 0; $i < @$values; $i++) {
540
                push @bind_values, $values->{$key}->[$i];
541
            }
542
        }
543
    }
544
    else {
545
        if ($bind_filter) {
546
            push @bind_values, scalar $bind_filter->($key, $values->{$key});
547
        }
548
        else {
549
            push @bind_values, $values->{$key};
550
        }
551
    }
try various
yuki-kimoto authored on 2009-10-21
552
    
cleanup
yuki-kimoto authored on 2009-10-21
553
    if ($bind_filter) {
554
        if ($tag_name eq 'in') {
555
            for (my $i = 0; $i < @$values; $i++) {
556
                push @bind_values, scalar $bind_filter->($key, $values->{$key}->[$i]);
557
            }
558
        }
559
        else {
560
            push @bind_values, scalar $bind_filter->($key, $values->{$key});
561
        }
562
    }
563
    else {
564
        push @bind_values, $values->{$key};
565
    }
566
    
567
    $tag_name = uc $tag_name if $sql_tmpl_obj->upper_case;
568
    
569
    my $expand;
570
    if ($tag_name eq '?') {
571
        $expand = '?';
572
    }
573
    elsif ($tag_name eq 'in') {
574
        $expand = '(';
575
        for (my $i = 0; $i < @$values; $i++) {
576
            $expand .= '?, ';
577
        }
578
        $expand =~ s/, $'//;
579
        $expand .= ')';
580
    }
581
    else {
582
        $expand = "$key $tag_name ?";
583
    }
584
    
try various
yuki-kimoto authored on 2009-10-21
585
    return ($expand, @bind_values);
586
}
587

            
588
sub expand_insert_values {
589
    my ($tag_name, $args, $values, $bind_filter, $sql_tmpl_obj) = @_;
590
    
591
    my $insert_keys = '(';
592
    my $place_holders = '(';
593
    
594
    $values = $args->[0] ? $values->{$args->[0]} : $values->{insert_values};
595
    
596
    my @bind_values;
597
    foreach my $key (sort keys %$values) {
598
        $bind_filter ? push @bind_values, scalar $bind_filter->($key, $values->{$key})
599
                     : push @bind_values, $values->{$key};
600
        
601
        $insert_keys   .= "$key, ";
602
        $place_holders .= "?, ";
603
    }
604
    
605
    $insert_keys =~ s/, $//;
606
    $insert_keys .= ')';
607
    
608
    $place_holders =~ s/, $//;
609
    $place_holders .= ')';
610
    
611
    my $expand = $sql_tmpl_obj->uppser_case ? "$insert_keys VALUES $place_holders"
612
                                            : "$insert_keys values $place_holders";
613
    
614
    return ($expand, @bind_values);
615
}
616

            
617
sub expand_update_set {
618
    my ($tag_name, $args, $values, $bind_filter, $sql_tmpl_obj) = @_;
619
    
620
    my $expand = $sql_tmpl_obj->uppser_case ? 'SET ' : 'set ';
621
    $values = $args->[0] ? $values->{$args->[0]} : $values->{update_set};
622
    
623
    my @bind_values;
624
    foreach my $key (sort keys %$values) {
625
        $bind_filter ? push @bind_values, scalar $bind_filter->($key, $values->{$key})
626
                     : push @bind_values, $values->{$key};
627
        
628
        $expand .= "$key = ?, ";
629
    }
630
    $expand =~ s/, $//;
631
    return ($expand, @bind_values);
cleanup
yuki-kimoto authored on 2009-10-21
632
}
633

            
634

            
add various things
yuki-kimoto authored on 2009-10-17
635
package DBI::Custom;
636
1;
637

            
first commit
yuki-kimoto authored on 2009-10-13
638
=head1 NAME
639

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

            
642
=head1 VERSION
643

            
add test
yuki-kimoto authored on 2009-10-16
644
Version 0.0101
first commit
yuki-kimoto authored on 2009-10-13
645

            
646
=cut
647

            
648
=head1 SYNOPSIS
649

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

            
add test
yuki-kimoto authored on 2009-10-16
652
=head1 METHODS
first commit
yuki-kimoto authored on 2009-10-13
653

            
add test
yuki-kimoto authored on 2009-10-16
654
=head2 add_filter
first commit
yuki-kimoto authored on 2009-10-13
655

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

            
add test
yuki-kimoto authored on 2009-10-16
658
=head2 clone
first commit
yuki-kimoto authored on 2009-10-13
659

            
add test
yuki-kimoto authored on 2009-10-16
660
=head2 connect
first commit
yuki-kimoto authored on 2009-10-13
661

            
add test
yuki-kimoto authored on 2009-10-16
662
=head2 connect_info
first commit
yuki-kimoto authored on 2009-10-13
663

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

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

            
add test
yuki-kimoto authored on 2009-10-16
668
=head2 filters
first commit
yuki-kimoto authored on 2009-10-13
669

            
cleanup
yuki-kimoto authored on 2009-10-21
670
=head2 initialize_class
first commit
yuki-kimoto authored on 2009-10-13
671

            
cleanup
yuki-kimoto authored on 2009-10-21
672
=head2 prototype
first commit
yuki-kimoto authored on 2009-10-13
673

            
add test
yuki-kimoto authored on 2009-10-16
674
=head2 new
675

            
676
=head2 query
first commit
yuki-kimoto authored on 2009-10-13
677

            
add test
yuki-kimoto authored on 2009-10-17
678
=head2 create_sql
679

            
680
=head2 query_raw_sql
681

            
682
=head2 sql_template
683

            
add tests
yuki-kimoto authored on 2009-10-18
684
=head2 auto_commit
685

            
686
=head2 connected
687

            
688
=head2 dbh_option
689

            
690
=head2 disconnect
691

            
692
=head2 reconnect
693

            
694
=head2 result_class
695

            
add various
yuki-kimoto authored on 2009-10-18
696
=head2 commit
first commit
yuki-kimoto authored on 2009-10-13
697

            
add various
yuki-kimoto authored on 2009-10-18
698
=head2 rollback
first commit
yuki-kimoto authored on 2009-10-13
699

            
700

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

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

            
705
=head1 COPYRIGHT & LICENSE
706

            
707
Copyright 2009 Yuki Kimoto, all rights reserved.
708

            
709
This program is free software; you can redistribute it and/or modify it
710
under the same terms as Perl itself.
711

            
712

            
713
=cut
714

            
715
1; # End of DBI::Custom