DBIx-Custom / lib / DBI / Custom.pm /
Newer Older
697 lines | 16.811kb
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-22
20
    $class->prototype(bless $prototype, $class);
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 {
cleanup
yuki-kimoto authored on 2009-10-22
25
    my $invocant = shift;
26
    my $class = ref $invocant || $invocant;
27
    my $prototype = $class->prototype;
28
    my $self = $class->Object::Simple::new(%{$prototype->clone}, @_);
29
    return bless $self, $class;
first commit
yuki-kimoto authored on 2009-10-13
30
}
31

            
cleanup
yuki-kimoto authored on 2009-10-15
32
# Clone
33
sub clone {
cleanup
yuki-kimoto authored on 2009-10-14
34
    my $self = shift;
cleanup
yuki-kimoto authored on 2009-10-15
35
    my $new = $self->Object::Simple::new;
try various
yuki-kimoto authored on 2009-10-21
36
    
cleanup
yuki-kimoto authored on 2009-10-22
37
    # Scalar copy
38
    foreach my $attr (qw/bind_filter fetch_filter result_class/) {
39
        $new->$attr($self->$attr);
40
    }
try various
yuki-kimoto authored on 2009-10-21
41
    
cleanup
yuki-kimoto authored on 2009-10-22
42
    # Hash ref copy
43
    foreach my $attr (qw/connect_info filters valid_connect_info/) {
44
        $new->$attr(\%{$self->$attr || {}});
45
    }
try various
yuki-kimoto authored on 2009-10-21
46
    
cleanup
yuki-kimoto authored on 2009-10-22
47
    # Other
48
    $new->connect_info->{options} = \%{$self->connect_info->{options}};
try various
yuki-kimoto authored on 2009-10-21
49
    $new->sql_template($self->sql_template->clone);
cleanup
yuki-kimoto authored on 2009-10-14
50
}
51

            
cleanup
yuki-kimoto authored on 2009-10-15
52
# Attribute
cleanup
yuki-kimoto authored on 2009-10-22
53
sub connect_info : Attr { type => 'hash',  default => sub { {} } }
add tests
yuki-kimoto authored on 2009-10-18
54
sub bind_filter  : Attr {}
add test
yuki-kimoto authored on 2009-10-16
55
sub fetch_filter : Attr {}
cleanup
yuki-kimoto authored on 2009-10-15
56

            
cleanup
yuki-kimoto authored on 2009-10-22
57
sub filters : Attr { type => 'hash', deref => 1, default => sub { {} } }
cleanup
yuki-kimoto authored on 2009-10-15
58
sub add_filter { shift->filters(@_) }
59

            
cleanup
yuki-kimoto authored on 2009-10-22
60
sub result_class : Attr { default => 'DBI::Custom::Result' }
add tests
yuki-kimoto authored on 2009-10-18
61
sub dbh          : Attr {}
cleanup
yuki-kimoto authored on 2009-10-22
62
sub sql_template : Attr { default => sub { DBI::Custom::SQL::Template->new } }
63
sub valid_connect_info : Attr { type => 'hash', deref => 1, default => sub {
64
    return {map {$_ => 1} qw/data_source user password options/}
65
}}
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

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

            
add tests
yuki-kimoto authored on 2009-10-18
107
sub DESTROY {
108
    my $self = shift;
add tests
yuki-kimoto authored on 2009-10-18
109
    $self->disconnect if $self->connected;
add tests
yuki-kimoto authored on 2009-10-18
110
}
111

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

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

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

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

            
cleanup
yuki-kimoto authored on 2009-10-18
154
# Create SQL from SQL template
add test
yuki-kimoto authored on 2009-10-17
155
sub create_sql {
156
    my $self = shift;
157
    
158
    my ($sql, @bind) = $self->sql_template->create_sql(@_);
159
    
160
    return ($sql, @bind);
161
}
162

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

            
cleanup
yuki-kimoto authored on 2009-10-18
205
# Prepare and execute raw SQL
add test
yuki-kimoto authored on 2009-10-17
206
sub query_raw_sql {
cleanup
yuki-kimoto authored on 2009-10-18
207
    my ($self, $sql, @bind_values) = @_;
add tests
yuki-kimoto authored on 2009-10-18
208
    
cleanup
yuki-kimoto authored on 2009-10-18
209
    # Connect
add various
yuki-kimoto authored on 2009-10-18
210
    $self->connect unless $self->connected;
cleanup
yuki-kimoto authored on 2009-10-18
211
    
212
    # Add semicolon if not exist;
add tests
yuki-kimoto authored on 2009-10-18
213
    $sql .= ';' unless $sql =~ /;$/;
cleanup
yuki-kimoto authored on 2009-10-18
214
    
215
    # Prepare
add various things
yuki-kimoto authored on 2009-10-17
216
    my $sth = $self->dbh->prepare($sql);
cleanup
yuki-kimoto authored on 2009-10-18
217
    
218
    # Execute
219
    $sth->execute(@bind_values);
220
    
add various things
yuki-kimoto authored on 2009-10-17
221
    return $sth;
add test
yuki-kimoto authored on 2009-10-17
222
}
223

            
224
Object::Simple->build_class;
225

            
cleanup
yuki-kimoto authored on 2009-10-22
226

            
add various things
yuki-kimoto authored on 2009-10-17
227
package DBI::Custom::Result;
228
use Object::Simple;
229

            
cleanup
yuki-kimoto authored on 2009-10-21
230
# Attributes
add various
yuki-kimoto authored on 2009-10-18
231
sub sth          : Attr {}
232
sub fetch_filter : Attr {}
add various things
yuki-kimoto authored on 2009-10-17
233

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

            
cleanup
yuki-kimoto authored on 2009-10-19
235
# Fetch (array)
add various
yuki-kimoto authored on 2009-10-18
236
sub fetch {
237
    my ($self, $type) = @_;
238
    my $sth = $self->sth;
add various
yuki-kimoto authored on 2009-10-18
239
    my $fetch_filter = $self->fetch_filter;
cleanup
yuki-kimoto authored on 2009-10-19
240
    
241
    # Fetch
242
    my $row = $sth->fetchrow_arrayref;
243
    
244
    # Cannot fetch
245
    return unless $row;
246
    
247
    # Filter
248
    if ($fetch_filter) {
add tests
yuki-kimoto authored on 2009-10-19
249
        my $keys  = $sth->{NAME_lc};
250
        my $types = $sth->{TYPE};
cleanup
yuki-kimoto authored on 2009-10-19
251
        for (my $i = 0; $i < @$keys; $i++) {
cleanup
yuki-kimoto authored on 2009-10-21
252
            $row->[$i]= $fetch_filter->($keys->[$i], $row->[$i], $types->[$i],
253
                                        $sth, $i);
add various
yuki-kimoto authored on 2009-10-18
254
        }
add various
yuki-kimoto authored on 2009-10-18
255
    }
cleanup
yuki-kimoto authored on 2009-10-19
256
    return wantarray ? @$row : $row;
257
}
258

            
259
# Fetch (hash)
260
sub fetch_hash {
261
    my $self = shift;
262
    my $sth = $self->sth;
263
    my $fetch_filter = $self->fetch_filter;
264
    
265
    # Fetch
add tests
yuki-kimoto authored on 2009-10-19
266
    my $row = $sth->fetchrow_arrayref;
cleanup
yuki-kimoto authored on 2009-10-19
267
    
268
    # Cannot fetch
269
    return unless $row;
270
    
add tests
yuki-kimoto authored on 2009-10-19
271
    # Keys
272
    my $keys  = $sth->{NAME_lc};
273
    
cleanup
yuki-kimoto authored on 2009-10-19
274
    # Filter
add tests
yuki-kimoto authored on 2009-10-19
275
    my $row_hash = {};
cleanup
yuki-kimoto authored on 2009-10-19
276
    if ($fetch_filter) {
add tests
yuki-kimoto authored on 2009-10-19
277
        my $types = $sth->{TYPE};
278
        for (my $i = 0; $i < @$keys; $i++) {
cleanup
yuki-kimoto authored on 2009-10-21
279
            $row_hash->{$keys->[$i]} = $fetch_filter->($keys->[$i], $row->[$i],
280
                                                       $types->[$i], $sth, $i);
add various
yuki-kimoto authored on 2009-10-18
281
        }
add various
yuki-kimoto authored on 2009-10-18
282
    }
cleanup
yuki-kimoto authored on 2009-10-21
283
    
284
    # No filter
add tests
yuki-kimoto authored on 2009-10-19
285
    else {
286
        for (my $i = 0; $i < @$keys; $i++) {
287
            $row_hash->{$keys->[$i]} = $row->[$i];
288
        }
289
    }
290
    return wantarray ? %$row_hash : $row_hash;
add various
yuki-kimoto authored on 2009-10-18
291
}
add various things
yuki-kimoto authored on 2009-10-17
292

            
cleanup
yuki-kimoto authored on 2009-10-19
293
# Fetch all (array)
add various
yuki-kimoto authored on 2009-10-18
294
sub fetch_all {
cleanup
yuki-kimoto authored on 2009-10-19
295
    my $self = shift;
add various
yuki-kimoto authored on 2009-10-18
296
    
cleanup
yuki-kimoto authored on 2009-10-19
297
    my $rows = [];
add tests
yuki-kimoto authored on 2009-10-19
298
    while(my @row = $self->fetch) {
299
        push @$rows, [@row];
add various
yuki-kimoto authored on 2009-10-18
300
    }
cleanup
yuki-kimoto authored on 2009-10-19
301
    return wantarray ? @$rows : $rows;
302
}
303

            
304
# Fetch all (hash)
305
sub fetch_all_hash {
306
    my $self = shift;
307
    
308
    my $rows = [];
309
    while(my %row = $self->fetch_hash) {
310
        push @$rows, {%row};
add various
yuki-kimoto authored on 2009-10-18
311
    }
cleanup
yuki-kimoto authored on 2009-10-19
312
    return wantarray ? @$rows : $rows;
add various
yuki-kimoto authored on 2009-10-18
313
}
add various things
yuki-kimoto authored on 2009-10-17
314

            
cleanup
yuki-kimoto authored on 2009-10-21
315
# Finish
add various
yuki-kimoto authored on 2009-10-18
316
sub finish { shift->sth->finish }
add various things
yuki-kimoto authored on 2009-10-17
317

            
cleanup
yuki-kimoto authored on 2009-10-21
318
# Error
319
sub error { 
320
    my $self = shift;
321
    my $sth  = $self->sth;
cleanup
yuki-kimoto authored on 2009-10-22
322
    return wantarray ? ($sth->errstr, $sth->err, $sth->state) : $sth->errstr;
cleanup
yuki-kimoto authored on 2009-10-21
323
}
324

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

            
327

            
cleanup
yuki-kimoto authored on 2009-10-21
328
package DBI::Custom::SQL::Template;
add test
yuki-kimoto authored on 2009-10-17
329
use Object::Simple;
try various way
yuki-kimoto authored on 2009-10-17
330
use Carp 'croak';
add test
yuki-kimoto authored on 2009-10-17
331

            
cleanup
yuki-kimoto authored on 2009-10-22
332
# Clone
try various
yuki-kimoto authored on 2009-10-21
333
sub clone {
334
    my $self = shift;
335
    my $new = $self->Object::Simple::new;
336
    
cleanup
yuki-kimoto authored on 2009-10-22
337
    # Scalar copy
338
    foreach my $attr (qw/tag_start tag_end bind_filter upper_case tag_syntax template/) {
339
        $new->$attr($self->$attr);
340
    }
341
    
342
    # Hash ref copy
343
    foreach my $attr (qw/tag_processors/) {
344
        $new->$attr(\%{$self->$attr || {}});
345
    }
346
    
347
    # Other
348
    $new->tree([]);
349
    
350
    return $new;
try various
yuki-kimoto authored on 2009-10-21
351
}
352

            
cleanup
yuki-kimoto authored on 2009-10-22
353

            
try varioud way
yuki-kimoto authored on 2009-10-17
354
### Attributes;
try various way
yuki-kimoto authored on 2009-10-17
355
sub tag_start   : Attr { default => '{' }
356
sub tag_end     : Attr { default => '}' }
357
sub template    : Attr {};
cleanup
yuki-kimoto authored on 2009-10-22
358
sub tree        : Attr { default => sub { [] } }
try various way
yuki-kimoto authored on 2009-10-17
359
sub bind_filter : Attr {}
360
sub upper_case  : Attr {default => 0}
try varioud way
yuki-kimoto authored on 2009-10-17
361

            
try various
yuki-kimoto authored on 2009-10-21
362
sub tag_syntax : Attr { default => <<'EOS' };
add test module
yuki-kimoto authored on 2009-10-19
363
{? name}         ?
try varioud way
yuki-kimoto authored on 2009-10-17
364
{= name}         name = ?
try various way
yuki-kimoto authored on 2009-10-17
365
{<> name}        name <> ?
try varioud way
yuki-kimoto authored on 2009-10-17
366

            
367
{< name}         name < ?
368
{> name}         name > ?
369
{>= name}        name >= ?
370
{<= name}        name <= ?
371

            
372
{like name}      name like ?
373
{in name}        name in [?, ?, ..]
374

            
375
{insert_values}  (key1, key2, key3) values (?, ?, ?)
376
{update_values}  set key1 = ?, key2 = ?, key3 = ?
377
EOS
378

            
cleanup
yuki-kimoto authored on 2009-10-22
379
sub tag_processors : Attr {type => 'hash', deref => 1, auto_build => sub { 
380
    shift->tag_processors(
381
        '?'             => \&DBI::Custom::SQL::Template::TagProcessor::expand_place_holder,
382
        '='             => \&DBI::Custom::SQL::Template::TagProcessor::expand_place_holder,
383
        '<>'            => \&DBI::Custom::SQL::Template::TagProcessor::expand_place_holder,
384
        '>'             => \&DBI::Custom::SQL::Template::TagProcessor::expand_place_holder,
385
        '<'             => \&DBI::Custom::SQL::Template::TagProcessor::expand_place_holder,
386
        '>='            => \&DBI::Custom::SQL::Template::TagProcessor::expand_place_holder,
387
        '<='            => \&DBI::Custom::SQL::Template::TagProcessor::expand_place_holder,
388
        'like'          => \&DBI::Custom::SQL::Template::TagProcessor::expand_place_holder,
389
        'in'            => \&DBI::Custom::SQL::Template::TagProcessor::expand_place_holder,
390
        'insert_values' => \&DBI::Custom::SQL::Template::TagProcessor::expand_insert_values,
391
        'update_set'    => \&DBI::Custom::SQL::Template::TagProcessor::expand_update_set
392
    );
393
}}
394

            
395
sub add_tag_processor {
396
    my $class = shift;
397
    my $tag_processors = ref $_[0] eq 'HASH' ? $_[0] : {@_};
398
    $class->tag_processor(%{$class->tag_processor}, %{$tag_processors});
399
}
400

            
401
sub create_sql {
402
    my ($self, $template, $values, $filter)  = @_;
403
    
404
    $filter ||= $self->bind_filter;
405
    
406
    $self->parse($template);
407
    
408
    my ($sql, @bind) = $self->build_sql({bind_filter => $filter, values => $values});
409
    
410
    return ($sql, @bind);
411
}
412

            
try varioud way
yuki-kimoto authored on 2009-10-17
413
sub parse {
414
    my ($self, $template) = @_;
415
    $self->template($template);
416
    
417
    # Clean start;
cleanup
yuki-kimoto authored on 2009-10-22
418
    $self->tree([]);
try varioud way
yuki-kimoto authored on 2009-10-17
419
    
420
    # Tags
421
    my $tag_start = quotemeta $self->tag_start;
422
    my $tag_end   = quotemeta $self->tag_end;
first commit
yuki-kimoto authored on 2009-10-13
423
    
try varioud way
yuki-kimoto authored on 2009-10-17
424
    # Tokenize
425
    my $state = 'text';
426
    
427
    # Save original template
428
    my $original_template = $template;
429
    
430
    # Text
431
    while ($template =~ s/([^$tag_start]*?)$tag_start([^$tag_end].*?)$tag_end//sm) {
try various way
yuki-kimoto authored on 2009-10-17
432
        my $text = $1;
try varioud way
yuki-kimoto authored on 2009-10-17
433
        my $tag  = $2;
434
        
try various way
yuki-kimoto authored on 2009-10-17
435
        push @{$self->tree}, {type => 'text', args => [$text]} if $text;
try varioud way
yuki-kimoto authored on 2009-10-17
436
        
437
        if ($tag) {
438
            
try various way
yuki-kimoto authored on 2009-10-17
439
            my ($tag_name, @args) = split /\s+/, $tag;
try varioud way
yuki-kimoto authored on 2009-10-17
440
            
try various way
yuki-kimoto authored on 2009-10-17
441
            $tag ||= '';
try various
yuki-kimoto authored on 2009-10-21
442
            unless ($self->tag_processors->{$tag_name}) {
443
                my $tag_syntax = $self->tag_syntax;
cleanup
yuki-kimoto authored on 2009-10-22
444
                croak("Tag '{$tag}' in SQL template is not exist.\n\n" .
try various
yuki-kimoto authored on 2009-10-21
445
                      "SQL template tag syntax\n" .
446
                      "$tag_syntax\n\n" .
447
                      "Your SQL template is \n$original_template\n\n");
448
            }
try varioud way
yuki-kimoto authored on 2009-10-17
449
            
try various way
yuki-kimoto authored on 2009-10-17
450
            push @{$self->tree}, {type => 'tag', tag_name => $tag_name, args => [@args]};
try varioud way
yuki-kimoto authored on 2009-10-17
451
        }
452
    }
453
    
try various way
yuki-kimoto authored on 2009-10-17
454
    push @{$self->tree}, {type => 'text', args => [$template]} if $template;
first commit
yuki-kimoto authored on 2009-10-13
455
}
456

            
try various way
yuki-kimoto authored on 2009-10-17
457
sub build_sql {
458
    my ($self, $args) = @_;
459
    
460
    my $tree        = $args->{tree} || $self->tree;
461
    my $bind_filter = $args->{bind_filter} || $self->bind_filter;
cleanup
yuki-kimoto authored on 2009-10-22
462
    my $values      = $args->{values} || {};
try various way
yuki-kimoto authored on 2009-10-17
463
    
try various
yuki-kimoto authored on 2009-10-21
464
    my @bind_values_all;
try various way
yuki-kimoto authored on 2009-10-17
465
    my $sql = '';
466
    foreach my $node (@$tree) {
467
        my $type     = $node->{type};
468
        my $tag_name = $node->{tag_name};
469
        my $args     = $node->{args};
470
        
471
        if ($type eq 'text') {
472
            # Join text
473
            $sql .= $args->[0];
474
        }
475
        elsif ($type eq 'tag') {
cleanup
yuki-kimoto authored on 2009-10-22
476
            my $tag_processor = $self->tag_processors->{$tag_name};
try various
yuki-kimoto authored on 2009-10-21
477
            
478
            croak("Tag processor '$type' must be code reference")
479
              unless ref $tag_processor eq 'CODE';
480
            
481
            my ($expand, @bind_values)
cleanup
yuki-kimoto authored on 2009-10-22
482
              = $tag_processor->($tag_name, $args, $values,
483
                                 $bind_filter, $self);
try various
yuki-kimoto authored on 2009-10-21
484
            
cleanup
yuki-kimoto authored on 2009-10-22
485
            $DB::single = 1;
486
            unless ($self->_placeholder_count($expand) == @bind_values) {
try various
yuki-kimoto authored on 2009-10-21
487
                require Data::Dumper;
try various way
yuki-kimoto authored on 2009-10-17
488
                
try various
yuki-kimoto authored on 2009-10-21
489
                my $bind_values_dump
cleanup
yuki-kimoto authored on 2009-10-22
490
                  = Data::Dumper->Dump([\@bind_values], ['*bind_values']);
try various way
yuki-kimoto authored on 2009-10-17
491
                
try various
yuki-kimoto authored on 2009-10-21
492
                croak("Place holder count must be same as bind value count\n" .
493
                      "Tag        : $tag_name\n" .
494
                      "Expand     : $expand\n" .
495
                      "Bind values: $bind_values_dump\n");
try various way
yuki-kimoto authored on 2009-10-17
496
            }
try various
yuki-kimoto authored on 2009-10-21
497
            push @bind_values_all, @bind_values;
498
            $sql .= $expand;
try various way
yuki-kimoto authored on 2009-10-17
499
        }
500
    }
501
    $sql .= ';' unless $sql =~ /;$/;
try various
yuki-kimoto authored on 2009-10-21
502
    return ($sql, @bind_values_all);
503
}
504

            
505
sub _placeholder_count {
506
    my ($self, $expand) = @_;
507
    $expand ||= '';
508
    
509
    my $count = 0;
cleanup
yuki-kimoto authored on 2009-10-22
510
    my $pos   = -1;
511
    while (($pos = index($expand, '?', $pos + 1)) != -1) {
try various
yuki-kimoto authored on 2009-10-21
512
        $count++;
513
    }
514
    return $count;
try various way
yuki-kimoto authored on 2009-10-17
515
}
try varioud way
yuki-kimoto authored on 2009-10-17
516

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

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

            
520
package DBI::Custom::SQL::Template::TagProcessor;
cleanup
yuki-kimoto authored on 2009-10-22
521
use strict;
522
use warnings;
cleanup
yuki-kimoto authored on 2009-10-21
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
    $tag_name = uc $tag_name if $sql_tmpl_obj->upper_case;
554
    
555
    my $expand;
556
    if ($tag_name eq '?') {
557
        $expand = '?';
558
    }
559
    elsif ($tag_name eq 'in') {
560
        $expand = '(';
561
        for (my $i = 0; $i < @$values; $i++) {
562
            $expand .= '?, ';
563
        }
564
        $expand =~ s/, $'//;
565
        $expand .= ')';
566
    }
567
    else {
568
        $expand = "$key $tag_name ?";
569
    }
570
    
try various
yuki-kimoto authored on 2009-10-21
571
    return ($expand, @bind_values);
572
}
573

            
574
sub expand_insert_values {
575
    my ($tag_name, $args, $values, $bind_filter, $sql_tmpl_obj) = @_;
576
    
577
    my $insert_keys = '(';
578
    my $place_holders = '(';
579
    
580
    $values = $args->[0] ? $values->{$args->[0]} : $values->{insert_values};
581
    
582
    my @bind_values;
583
    foreach my $key (sort keys %$values) {
584
        $bind_filter ? push @bind_values, scalar $bind_filter->($key, $values->{$key})
585
                     : push @bind_values, $values->{$key};
586
        
587
        $insert_keys   .= "$key, ";
588
        $place_holders .= "?, ";
589
    }
590
    
591
    $insert_keys =~ s/, $//;
592
    $insert_keys .= ')';
593
    
594
    $place_holders =~ s/, $//;
595
    $place_holders .= ')';
596
    
cleanup
yuki-kimoto authored on 2009-10-22
597
    my $expand = $sql_tmpl_obj->upper_case ? "$insert_keys VALUES $place_holders"
598
                                           : "$insert_keys values $place_holders";
try various
yuki-kimoto authored on 2009-10-21
599
    
600
    return ($expand, @bind_values);
601
}
602

            
603
sub expand_update_set {
604
    my ($tag_name, $args, $values, $bind_filter, $sql_tmpl_obj) = @_;
605
    
cleanup
yuki-kimoto authored on 2009-10-22
606
    my $expand = $sql_tmpl_obj->upper_case ? 'SET ' : 'set ';
try various
yuki-kimoto authored on 2009-10-21
607
    $values = $args->[0] ? $values->{$args->[0]} : $values->{update_set};
608
    
609
    my @bind_values;
610
    foreach my $key (sort keys %$values) {
611
        $bind_filter ? push @bind_values, scalar $bind_filter->($key, $values->{$key})
612
                     : push @bind_values, $values->{$key};
613
        
614
        $expand .= "$key = ?, ";
615
    }
616
    $expand =~ s/, $//;
617
    return ($expand, @bind_values);
cleanup
yuki-kimoto authored on 2009-10-21
618
}
619

            
620

            
add various things
yuki-kimoto authored on 2009-10-17
621
package DBI::Custom;
622
1;
623

            
first commit
yuki-kimoto authored on 2009-10-13
624
=head1 NAME
625

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

            
628
=head1 VERSION
629

            
add test
yuki-kimoto authored on 2009-10-16
630
Version 0.0101
first commit
yuki-kimoto authored on 2009-10-13
631

            
632
=cut
633

            
634
=head1 SYNOPSIS
635

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

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

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

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

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

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

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

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

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

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

            
cleanup
yuki-kimoto authored on 2009-10-21
656
=head2 prototype
first commit
yuki-kimoto authored on 2009-10-13
657

            
add test
yuki-kimoto authored on 2009-10-16
658
=head2 new
659

            
660
=head2 query
first commit
yuki-kimoto authored on 2009-10-13
661

            
add test
yuki-kimoto authored on 2009-10-17
662
=head2 create_sql
663

            
664
=head2 query_raw_sql
665

            
666
=head2 sql_template
667

            
add tests
yuki-kimoto authored on 2009-10-18
668
=head2 auto_commit
669

            
670
=head2 connected
671

            
672
=head2 disconnect
673

            
674
=head2 reconnect
675

            
676
=head2 result_class
677

            
cleanup
yuki-kimoto authored on 2009-10-22
678
=head2 run_tranzaction
first commit
yuki-kimoto authored on 2009-10-13
679

            
cleanup
yuki-kimoto authored on 2009-10-22
680
=head2 valid_connect_info
first commit
yuki-kimoto authored on 2009-10-13
681

            
682

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

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

            
687
=head1 COPYRIGHT & LICENSE
688

            
689
Copyright 2009 Yuki Kimoto, all rights reserved.
690

            
691
This program is free software; you can redistribute it and/or modify it
692
under the same terms as Perl itself.
693

            
694

            
695
=cut
696

            
697
1; # End of DBI::Custom