Showing 3 changed files with 80 additions and 473 deletions
+3
Build.PL 1000644 → 1000755
... ...
@@ -10,6 +10,9 @@ my $builder = Module::Build->new(
10 10
     build_requires => {
11 11
         'Test::More' => 0,
12 12
     },
13
+    requires => {
14
+        'Object::Simple' => 0.0602,
15
+    },
13 16
     add_to_cleanup      => [ 'DBI-Custom-*' ],
14 17
     create_makefile_pl => 'traditional',
15 18
 );
+49 -448
lib/DBI/Custom.pm
... ...
@@ -5,64 +5,62 @@ our $VERSION = '0.0101';
5 5
 
6 6
 use Carp 'croak';
7 7
 use DBI;
8
+use DBI::Custom::SQL::Template;
9
+
10
+### Class-Object Accessors
11
+sub connect_info : ClassObjectAttr { type => 'hash',  auto_build => sub {
12
+    shift->Object::Simple::initialize_class_object_attr(
13
+        default => sub { {} }, clone => sub {
14
+            my $value = shift;
15
+            my $new_value = \%{$value || {}};
16
+            $new_value->{options} = $value->{options} if $value->{options};
17
+            return $new_value;
18
+        }
19
+    )
20
+}}
8 21
 
9
-# Model
10
-sub prototype : ClassAttr { auto_build => sub {
11
-    my $class = shift;
12
-    my $super = do {
13
-        no strict 'refs';
14
-        ${"${class}::ISA"}[0];
15
-    };
16
-    my $prototype = eval{$super->can('prototype')}
17
-                         ? $super->prototype->clone
18
-                         : $class->Object::Simple::new;
19
-    
20
-    $class->prototype(bless $prototype, $class);
22
+sub bind_filter  : ClassObjectAttr { auto_build => sub {
23
+    shift->Object::Simple::initialize_class_object_attr(clone => 'scalar')
24
+}}
25
+sub fetch_filter : ClassObjectAttr { auto_build => sub {
26
+    shift->Object::Simple::initialize_class_object_attr(clone => 'scalar')
21 27
 }}
22 28
 
23
-# New
24
-sub new {
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;
30
-}
29
+sub filters : ClassObjectAttr { type => 'hash', deref => 1, auto_build => sub {
30
+    shift->Object::Simple::initialize_class_object_attr(clone => 'hash')
31
+}}
31 32
 
32
-# Clone
33
-sub clone {
34
-    my $self = shift;
35
-    my $new = $self->Object::Simple::new;
36
-    
37
-    # Scalar copy
38
-    foreach my $attr (qw/bind_filter fetch_filter result_class/) {
39
-        $new->$attr($self->$attr);
40
-    }
41
-    
42
-    # Hash ref copy
43
-    foreach my $attr (qw/connect_info filters valid_connect_info/) {
44
-        $new->$attr(\%{$self->$attr || {}});
45
-    }
46
-    
47
-    # Other
48
-    $new->connect_info->{options} = \%{$self->connect_info->{options}};
49
-    $new->sql_template($self->sql_template->clone);
50
-}
33
+sub result_class : ClassObjectAttr { auto_build => sub {
34
+    shift->Object::Simple::initialize_class_object_attr(clone => 'scalar')
35
+}}
51 36
 
52
-# Attribute
53
-sub connect_info : Attr { type => 'hash',  default => sub { {} } }
54
-sub bind_filter  : Attr {}
55
-sub fetch_filter : Attr {}
37
+sub sql_template : ClassObjectAttr { auto_build => sub {
38
+    shift->Object::Simple::initialize_class_object_attr(
39
+        clone   => sub {my $value = shift; $value ? $value->clone : undef},
40
+        default => sub { DBI::Custom::SQL::Template->new }
41
+    )
42
+}}
56 43
 
57
-sub filters : Attr { type => 'hash', deref => 1, default => sub { {} } }
58
-sub add_filter { shift->filters(@_) }
44
+sub valid_connect_info : ClassObjectAttr { type => 'hash', deref => 1, auto_build => sub {
45
+    shift->Object::Simple::initialize_class_object_attr(
46
+        default => sub { return {map {$_ => 1} qw/data_source user password options/} },
47
+        clone => 'hash'
48
+    )
49
+}}
59 50
 
60
-sub result_class : Attr { default => 'DBI::Custom::Result' }
51
+### Object Accessor
61 52
 sub dbh          : Attr {}
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
-}}
53
+
54
+
55
+### Methods
56
+# Add filter
57
+sub add_filter {
58
+    my $invocant = shift;
59
+    
60
+    my %old_filters = $invocant->filters;
61
+    my %new_filters = ref $_[0] eq 'HASH' ? %{$_[0]} : @_;
62
+    $invocant->filters(%old_filters, %new_filters);
63
+}
66 64
 
67 65
 # Auto commit
68 66
 sub auto_commit {
... ...
@@ -104,6 +102,7 @@ sub connect {
104 102
     return $self;
105 103
 }
106 104
 
105
+# DESTROY
107 106
 sub DESTROY {
108 107
     my $self = shift;
109 108
     $self->disconnect if $self->connected;
... ...
@@ -223,404 +222,6 @@ sub query_raw_sql {
223 222
 
224 223
 Object::Simple->build_class;
225 224
 
226
-
227
-package DBI::Custom::Result;
228
-use Object::Simple;
229
-
230
-# Attributes
231
-sub sth          : Attr {}
232
-sub fetch_filter : Attr {}
233
-
234
-
235
-# Fetch (array)
236
-sub fetch {
237
-    my ($self, $type) = @_;
238
-    my $sth = $self->sth;
239
-    my $fetch_filter = $self->fetch_filter;
240
-    
241
-    # Fetch
242
-    my $row = $sth->fetchrow_arrayref;
243
-    
244
-    # Cannot fetch
245
-    return unless $row;
246
-    
247
-    # Filter
248
-    if ($fetch_filter) {
249
-        my $keys  = $sth->{NAME_lc};
250
-        my $types = $sth->{TYPE};
251
-        for (my $i = 0; $i < @$keys; $i++) {
252
-            $row->[$i]= $fetch_filter->($keys->[$i], $row->[$i], $types->[$i],
253
-                                        $sth, $i);
254
-        }
255
-    }
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
266
-    my $row = $sth->fetchrow_arrayref;
267
-    
268
-    # Cannot fetch
269
-    return unless $row;
270
-    
271
-    # Keys
272
-    my $keys  = $sth->{NAME_lc};
273
-    
274
-    # Filter
275
-    my $row_hash = {};
276
-    if ($fetch_filter) {
277
-        my $types = $sth->{TYPE};
278
-        for (my $i = 0; $i < @$keys; $i++) {
279
-            $row_hash->{$keys->[$i]} = $fetch_filter->($keys->[$i], $row->[$i],
280
-                                                       $types->[$i], $sth, $i);
281
-        }
282
-    }
283
-    
284
-    # No filter
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;
291
-}
292
-
293
-# Fetch all (array)
294
-sub fetch_all {
295
-    my $self = shift;
296
-    
297
-    my $rows = [];
298
-    while(my @row = $self->fetch) {
299
-        push @$rows, [@row];
300
-    }
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};
311
-    }
312
-    return wantarray ? @$rows : $rows;
313
-}
314
-
315
-# Finish
316
-sub finish { shift->sth->finish }
317
-
318
-# Error
319
-sub error { 
320
-    my $self = shift;
321
-    my $sth  = $self->sth;
322
-    return wantarray ? ($sth->errstr, $sth->err, $sth->state) : $sth->errstr;
323
-}
324
-
325
-Object::Simple->build_class;
326
-
327
-
328
-package DBI::Custom::SQL::Template;
329
-use Object::Simple;
330
-use Carp 'croak';
331
-
332
-# Clone
333
-sub clone {
334
-    my $self = shift;
335
-    my $new = $self->Object::Simple::new;
336
-    
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;
351
-}
352
-
353
-
354
-### Attributes;
355
-sub tag_start   : Attr { default => '{' }
356
-sub tag_end     : Attr { default => '}' }
357
-sub template    : Attr {};
358
-sub tree        : Attr { default => sub { [] } }
359
-sub bind_filter : Attr {}
360
-sub upper_case  : Attr {default => 0}
361
-
362
-sub tag_syntax : Attr { default => <<'EOS' };
363
-{? name}         ?
364
-{= name}         name = ?
365
-{<> name}        name <> ?
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
-
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
-
413
-sub parse {
414
-    my ($self, $template) = @_;
415
-    $self->template($template);
416
-    
417
-    # Clean start;
418
-    $self->tree([]);
419
-    
420
-    # Tags
421
-    my $tag_start = quotemeta $self->tag_start;
422
-    my $tag_end   = quotemeta $self->tag_end;
423
-    
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) {
432
-        my $text = $1;
433
-        my $tag  = $2;
434
-        
435
-        push @{$self->tree}, {type => 'text', args => [$text]} if $text;
436
-        
437
-        if ($tag) {
438
-            
439
-            my ($tag_name, @args) = split /\s+/, $tag;
440
-            
441
-            $tag ||= '';
442
-            unless ($self->tag_processors->{$tag_name}) {
443
-                my $tag_syntax = $self->tag_syntax;
444
-                croak("Tag '{$tag}' in SQL template is not exist.\n\n" .
445
-                      "SQL template tag syntax\n" .
446
-                      "$tag_syntax\n\n" .
447
-                      "Your SQL template is \n$original_template\n\n");
448
-            }
449
-            
450
-            push @{$self->tree}, {type => 'tag', tag_name => $tag_name, args => [@args]};
451
-        }
452
-    }
453
-    
454
-    push @{$self->tree}, {type => 'text', args => [$template]} if $template;
455
-}
456
-
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;
462
-    my $values      = $args->{values} || {};
463
-    
464
-    my @bind_values_all;
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') {
476
-            my $tag_processor = $self->tag_processors->{$tag_name};
477
-            
478
-            croak("Tag processor '$type' must be code reference")
479
-              unless ref $tag_processor eq 'CODE';
480
-            
481
-            my ($expand, @bind_values)
482
-              = $tag_processor->($tag_name, $args, $values,
483
-                                 $bind_filter, $self);
484
-            
485
-            $DB::single = 1;
486
-            unless ($self->_placeholder_count($expand) == @bind_values) {
487
-                require Data::Dumper;
488
-                
489
-                my $bind_values_dump
490
-                  = Data::Dumper->Dump([\@bind_values], ['*bind_values']);
491
-                
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");
496
-            }
497
-            push @bind_values_all, @bind_values;
498
-            $sql .= $expand;
499
-        }
500
-    }
501
-    $sql .= ';' unless $sql =~ /;$/;
502
-    return ($sql, @bind_values_all);
503
-}
504
-
505
-sub _placeholder_count {
506
-    my ($self, $expand) = @_;
507
-    $expand ||= '';
508
-    
509
-    my $count = 0;
510
-    my $pos   = -1;
511
-    while (($pos = index($expand, '?', $pos + 1)) != -1) {
512
-        $count++;
513
-    }
514
-    return $count;
515
-}
516
-
517
-Object::Simple->build_class;
518
-
519
-
520
-package DBI::Custom::SQL::Template::TagProcessor;
521
-use strict;
522
-use warnings;
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
-    }
552
-    
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
-    
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
-    
597
-    my $expand = $sql_tmpl_obj->upper_case ? "$insert_keys VALUES $place_holders"
598
-                                           : "$insert_keys values $place_holders";
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
-    
606
-    my $expand = $sql_tmpl_obj->upper_case ? 'SET ' : 'set ';
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);
618
-}
619
-
620
-
621
-package DBI::Custom;
622
-1;
623
-
624 225
 =head1 NAME
625 226
 
626 227
 DBI::Custom - Customizable simple DBI
+28 -25
t/01-core.t
... ...
@@ -4,6 +4,7 @@ use warnings;
4 4
 
5 5
 use DBI::Custom;
6 6
 use Scalar::Util qw/blessed/;
7
+use DBI::Custom::SQL::Template;
7 8
 
8 9
 my $sql_tmpl1 = DBI::Custom::SQL::Template->new->upper_case(0);
9 10
 my $sql_tmpl2 = DBI::Custom::SQL::Template->new->upper_case(1);
... ...
@@ -22,14 +23,13 @@ my $sql_tmpl3 = DBI::Custom::SQL::Template->new->upper_case(2);
22 23
         },
23 24
         bind_filter => 'f',
24 25
         fetch_filter => 'g',
25
-        dbh => 'e',
26 26
         result_class => 'g',
27 27
         sql_template => $sql_tmpl1,
28 28
         valid_connect_info => {i => 1}
29 29
     );
30 30
     is_deeply($dbi,{connect_info => {user => 'a', password => 'b', data_source => 'c', 
31 31
                     options => {d => 1, e => 2}}, filters => {f => 3}, bind_filter => 'f',
32
-                    fetch_filter => 'g', dbh => 'e', result_class => 'g',
32
+                    fetch_filter => 'g', result_class => 'g',
33 33
                     sql_template => $sql_tmpl1, valid_connect_info => {i => 1}}, 'new');
34 34
     
35 35
     isa_ok($dbi, 'DBI::Custom');
... ...
@@ -40,9 +40,9 @@ my $sql_tmpl3 = DBI::Custom::SQL::Template->new->upper_case(2);
40 40
     package DBI::Custom::T1;
41 41
     use base 'DBI::Custom';
42 42
     
43
-    my $prototype = __PACKAGE__->prototype;
43
+    my $class = __PACKAGE__;
44 44
     
45
-    $prototype
45
+    $class
46 46
       ->connect_info(
47 47
           user => 'a',
48 48
           password => 'b',
... ...
@@ -54,7 +54,6 @@ my $sql_tmpl3 = DBI::Custom::SQL::Template->new->upper_case(2);
54 54
       )
55 55
       ->bind_filter('f')
56 56
       ->fetch_filter('g')
57
-      ->dbh('e')
58 57
       ->result_class('DBI::Custom::Result')
59 58
       ->sql_template($sql_tmpl1)
60 59
       ->valid_connect_info({p => 1})
... ...
@@ -90,11 +89,13 @@ my $sql_tmpl3 = DBI::Custom::SQL::Template->new->upper_case(2);
90 89
 {
91 90
     my $dbi = DBI::Custom::T1->new;
92 91
     
93
-    my $sql_tmpl = delete $dbi->{sql_template};
94
-    is_deeply($dbi,{connect_info => {user => 'a', password => 'b', data_source => 'c', options => {d => 1, e => 2}},
95
-                    filters => {f => 3}, bind_filter => 'f', fetch_filter => 'g', result_class => 'DBI::Custom::Result',
96
-                    valid_connect_info => {p => 1}}, 'new custom class');
97
-    
92
+    is_deeply($dbi->connect_info, {user => 'a', password => 'b', data_source => 'c', options => {d => 1, e => 2}});
93
+    is_deeply({$dbi->filters}, {f => 3});
94
+    is($dbi->bind_filter, 'f');
95
+    is($dbi->fetch_filter, 'g');
96
+    is($dbi->result_class, 'DBI::Custom::Result');
97
+    is_deeply({$dbi->valid_connect_info},{p => 1});
98
+    is($dbi->sql_template->upper_case, 0);
98 99
     isa_ok($dbi, 'DBI::Custom::T1');
99 100
     
100 101
 }
... ...
@@ -107,11 +108,13 @@ my $sql_tmpl3 = DBI::Custom::SQL::Template->new->upper_case(2);
107 108
 {
108 109
     my $dbi = DBI::Custom::T1_2->new;
109 110
     
110
-    my $sql_tmpl = delete $dbi->{sql_template};
111
-    is($sql_tmpl->upper_case, 0);
112
-    is_deeply($dbi,{connect_info => {user => 'a', password => 'b', data_source => 'c', options => {d => 1, e => 2}},
113
-                    filters => {f => 3}, bind_filter => 'f', fetch_filter => 'g', result_class => 'DBI::Custom::Result',
114
-                    valid_connect_info => {p => 1}}, 'new custom class inherit');
111
+    is_deeply($dbi->connect_info, {user => 'a', password => 'b', data_source => 'c', options => {d => 1, e => 2}});
112
+    is_deeply(scalar $dbi->filters, {f => 3});
113
+    is($dbi->bind_filter, 'f');
114
+    is($dbi->fetch_filter, 'g');
115
+    is($dbi->result_class, 'DBI::Custom::Result');
116
+    is_deeply({$dbi->valid_connect_info}, {p => 1});
117
+    is($dbi->sql_template->upper_case, 0);
115 118
     
116 119
     isa_ok($dbi, 'DBI::Custom::T1_2');
117 120
 }
... ...
@@ -120,9 +123,9 @@ my $sql_tmpl3 = DBI::Custom::SQL::Template->new->upper_case(2);
120 123
     package DBI::Custom::T1_3;
121 124
     use base 'DBI::Custom::T1';
122 125
     
123
-    my $prototype = __PACKAGE__->prototype;
126
+    my $class = __PACKAGE__;
124 127
         
125
-    $prototype
128
+    $class
126 129
       ->connect_info(
127 130
         user => 'ao',
128 131
         password => 'bo',
... ...
@@ -134,7 +137,6 @@ my $sql_tmpl3 = DBI::Custom::SQL::Template->new->upper_case(2);
134 137
       )
135 138
       ->bind_filter('fo')
136 139
       ->fetch_filter('go')
137
-      ->dbh('eo')
138 140
       ->result_class('ho')
139 141
       ->sql_template($sql_tmpl2)
140 142
       ->valid_connect_info({p => 3})
... ...
@@ -144,11 +146,13 @@ my $sql_tmpl3 = DBI::Custom::SQL::Template->new->upper_case(2);
144 146
 {
145 147
     my $dbi = DBI::Custom::T1_3->new;
146 148
     
147
-    my $sql_tmpl = delete $dbi->{sql_template};
148
-    is($sql_tmpl->upper_case, 1);
149
-    is_deeply($dbi,{connect_info => {user => 'ao', password => 'bo', data_source => 'co', options => {do => 10, eo => 20}},
150
-                    filters => {fo => 30}, bind_filter => 'fo', fetch_filter => 'go', result_class => 'ho',
151
-                    valid_connect_info => {p => 3}}, 'new custom class');
149
+    is_deeply($dbi->connect_info, {user => 'ao', password => 'bo', data_source => 'co', options => {do => 10, eo => 20}});
150
+    is_deeply(scalar $dbi->filters, {fo => 30});
151
+    is($dbi->bind_filter, 'fo');
152
+    is($dbi->fetch_filter, 'go');
153
+    is($dbi->result_class, 'ho');
154
+    is_deeply(scalar $dbi->valid_connect_info, {p => 3});
155
+    is($dbi->sql_template->upper_case, 1);
152 156
     
153 157
     isa_ok($dbi, 'DBI::Custom::T1_3');
154 158
 }
... ...
@@ -166,7 +170,6 @@ my $sql_tmpl3 = DBI::Custom::SQL::Template->new->upper_case(2);
166 170
         },
167 171
         bind_filter => 'f',
168 172
         fetch_filter => 'g',
169
-        dbh => 'e',
170 173
         result_class => 'h',
171 174
         sql_template => $sql_tmpl3,
172 175
         valid_connect_info => {p => 4}
... ...
@@ -175,7 +178,7 @@ my $sql_tmpl3 = DBI::Custom::SQL::Template->new->upper_case(2);
175 178
     my $sql_tmpl = delete $dbi->{sql_template};
176 179
     is($sql_tmpl->upper_case, 2);
177 180
     is_deeply($dbi,{connect_info => {user => 'a', password => 'b', data_source => 'c', options => {d => 1, e => 2}},
178
-                    filters => {f => 3}, bind_filter => 'f', fetch_filter => 'g', dbh => 'e', result_class => 'h',
181
+                    filters => {f => 3}, bind_filter => 'f', fetch_filter => 'g', result_class => 'h',
179 182
                     valid_connect_info => {p => 4}}, 'new');
180 183
     
181 184
     isa_ok($dbi, 'DBI::Custom');