| ... | ... | 
                  @@ -17,22 +17,16 @@ sub prototype : ClassAttr { auto_build => sub {
                 | 
              
| 17 | 17 | 
                  ? $super->prototype->clone  | 
              
| 18 | 18 | 
                  : $class->Object::Simple::new;  | 
              
| 19 | 19 | 
                   | 
              
| 20 | 
                  - $class->prototype($prototype);  | 
              |
| 20 | 
                  + $class->prototype(bless $prototype, $class);  | 
              |
| 21 | 21 | 
                  }}  | 
              
| 22 | 22 | 
                   | 
              
| 23 | 23 | 
                  # New  | 
              
| 24 | 24 | 
                   sub new {
                 | 
              
| 25 | 
                  - my $self = shift->Object::Simple::new(@_);  | 
              |
| 26 | 
                  - my $class = ref $self;  | 
              |
| 27 | 
                  -    return bless {%{$class->prototype->clone}, %{$self}}, $class;
                 | 
              |
| 28 | 
                  -}  | 
              |
| 29 | 
                  -  | 
              |
| 30 | 
                  -# Initialize class  | 
              |
| 31 | 
                  -sub initialize_class {
                 | 
              |
| 32 | 
                  - my ($class, $callback) = @_;  | 
              |
| 33 | 
                  -  | 
              |
| 34 | 
                  - # Callback to initialize prototype  | 
              |
| 35 | 
                  - $callback->($class->prototype);  | 
              |
| 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;  | 
              |
| 36 | 30 | 
                  }  | 
              
| 37 | 31 | 
                   | 
              
| 38 | 32 | 
                  # Clone  | 
              
| ... | ... | 
                  @@ -40,29 +34,35 @@ sub clone {
                 | 
              
| 40 | 34 | 
                  my $self = shift;  | 
              
| 41 | 35 | 
                  my $new = $self->Object::Simple::new;  | 
              
| 42 | 36 | 
                   | 
              
| 43 | 
                  -    $new->connect_info(%{$self->connect_info || {}});
                 | 
              |
| 44 | 
                  -    $new->connect_info->{options} = \%{$self->connect_info->{options}};
                 | 
              |
| 37 | 
                  + # Scalar copy  | 
              |
| 38 | 
                  +    foreach my $attr (qw/bind_filter fetch_filter result_class/) {
                 | 
              |
| 39 | 
                  + $new->$attr($self->$attr);  | 
              |
| 40 | 
                  + }  | 
              |
| 45 | 41 | 
                   | 
              
| 46 | 
                  -    $new->filters(%{$self->filters || {}});
                 | 
              |
| 47 | 
                  - $new->bind_filter($self->bind_filter);  | 
              |
| 48 | 
                  - $new->fetch_filter($self->fetch_filter);  | 
              |
| 49 | 
                  - $new->result_class($self->result_class);  | 
              |
| 42 | 
                  + # Hash ref copy  | 
              |
| 43 | 
                  +    foreach my $attr (qw/connect_info filters valid_connect_info/) {
                 | 
              |
| 44 | 
                  +        $new->$attr(\%{$self->$attr || {}});
                 | 
              |
| 45 | 
                  + }  | 
              |
| 50 | 46 | 
                   | 
              
| 47 | 
                  + # Other  | 
              |
| 48 | 
                  +    $new->connect_info->{options} = \%{$self->connect_info->{options}};
                 | 
              |
| 51 | 49 | 
                  $new->sql_template($self->sql_template->clone);  | 
              
| 52 | 50 | 
                  }  | 
              
| 53 | 51 | 
                   | 
              
| 54 | 52 | 
                  # Attribute  | 
              
| 55 | 
                  -sub connect_info       : Attr { type => 'hash',  auto_build => sub { shift->connect_info({}) } }
                 | 
              |
| 56 | 
                  -  | 
              |
| 53 | 
                  +sub connect_info : Attr { type => 'hash',  default => sub { {} } }
                 | 
              |
| 57 | 54 | 
                   sub bind_filter  : Attr {}
                 | 
              
| 58 | 55 | 
                   sub fetch_filter : Attr {}
                 | 
              
| 59 | 56 | 
                   | 
              
| 60 | 
                  -sub filters : Attr { type => 'hash', deref => 1, auto_build => sub { shift->filters({}) } }
                 | 
              |
| 57 | 
                  +sub filters : Attr { type => 'hash', deref => 1, default => sub { {} } }
                 | 
              |
| 61 | 58 | 
                   sub add_filter { shift->filters(@_) }
                 | 
              
| 62 | 59 | 
                   | 
              
| 63 | 
                  -sub result_class : Attr { auto_build => sub { shift->result_class('DBI::Custom::Result') }}
                 | 
              |
| 60 | 
                  +sub result_class : Attr { default => 'DBI::Custom::Result' }
                 | 
              |
| 64 | 61 | 
                   sub dbh          : Attr {}
                 | 
              
| 65 | 
                  -sub sql_template : Attr { auto_build => sub { shift->sql_template(DBI::Custom::SQL::Template->new) } }
                 | 
              |
| 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 | 
                  +}}  | 
              |
| 66 | 66 | 
                   | 
              
| 67 | 67 | 
                  # Auto commit  | 
              
| 68 | 68 | 
                   sub auto_commit {
                 | 
              
| ... | ... | 
                  @@ -78,10 +78,6 @@ sub auto_commit {
                 | 
              
| 78 | 78 | 
                       return $self->dbh->{AutoCommit};
                 | 
              
| 79 | 79 | 
                  }  | 
              
| 80 | 80 | 
                   | 
              
| 81 | 
                  -sub valid_connect_info : Attr { default => sub {
                 | 
              |
| 82 | 
                  -    {map {$_ => 1} qw/data_source user password options/}
                 | 
              |
| 83 | 
                  -}}  | 
              |
| 84 | 
                  -  | 
              |
| 85 | 81 | 
                  # Connect  | 
              
| 86 | 82 | 
                   sub connect {
                 | 
              
| 87 | 83 | 
                  my $self = shift;  | 
              
| ... | ... | 
                  @@ -155,17 +151,6 @@ sub run_tranzaction {
                 | 
              
| 155 | 151 | 
                  $self->auto_commit(1);  | 
              
| 156 | 152 | 
                  }  | 
              
| 157 | 153 | 
                   | 
              
| 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 | 
                  -  | 
              |
| 169 | 154 | 
                  # Create SQL from SQL template  | 
              
| 170 | 155 | 
                   sub create_sql {
                 | 
              
| 171 | 156 | 
                  my $self = shift;  | 
              
| ... | ... | 
                  @@ -238,6 +223,7 @@ sub query_raw_sql {
                 | 
              
| 238 | 223 | 
                   | 
              
| 239 | 224 | 
                  Object::Simple->build_class;  | 
              
| 240 | 225 | 
                   | 
              
| 226 | 
                  +  | 
              |
| 241 | 227 | 
                  package DBI::Custom::Result;  | 
              
| 242 | 228 | 
                  use Object::Simple;  | 
              
| 243 | 229 | 
                   | 
              
| ... | ... | 
                  @@ -333,7 +319,7 @@ sub finish { shift->sth->finish }
                 | 
              
| 333 | 319 | 
                   sub error { 
                 | 
              
| 334 | 320 | 
                  my $self = shift;  | 
              
| 335 | 321 | 
                  my $sth = $self->sth;  | 
              
| 336 | 
                  - wantarray ? ($sth->errstr, $sth->err, $sth->state) : $sth->errstr;  | 
              |
| 322 | 
                  + return wantarray ? ($sth->errstr, $sth->err, $sth->state) : $sth->errstr;  | 
              |
| 337 | 323 | 
                  }  | 
              
| 338 | 324 | 
                   | 
              
| 339 | 325 | 
                  Object::Simple->build_class;  | 
              
| ... | ... | 
                  @@ -343,38 +329,36 @@ package DBI::Custom::SQL::Template;  | 
              
| 343 | 329 | 
                  use Object::Simple;  | 
              
| 344 | 330 | 
                  use Carp 'croak';  | 
              
| 345 | 331 | 
                   | 
              
| 332 | 
                  +# Clone  | 
              |
| 346 | 333 | 
                   sub clone {
                 | 
              
| 347 | 334 | 
                  my $self = shift;  | 
              
| 348 | 335 | 
                  my $new = $self->Object::Simple::new;  | 
              
| 349 | 336 | 
                   | 
              
| 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);  | 
              |
| 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;  | 
              |
| 355 | 351 | 
                  }  | 
              
| 356 | 352 | 
                   | 
              
| 353 | 
                  +  | 
              |
| 357 | 354 | 
                  ### Attributes;  | 
              
| 358 | 355 | 
                   sub tag_start   : Attr { default => '{' }
                 | 
              
| 359 | 356 | 
                   sub tag_end     : Attr { default => '}' }
                 | 
              
| 360 | 357 | 
                   sub template    : Attr {};
                 | 
              
| 361 | 
                  -sub tree        : Attr { auto_build => sub { shift->tree([]) } }
                 | 
              |
| 358 | 
                  +sub tree        : Attr { default => sub { [] } }
                 | 
              |
| 362 | 359 | 
                   sub bind_filter : Attr {}
                 | 
              
| 363 | 
                  -sub values      : Attr {}
                 | 
              |
| 364 | 360 | 
                   sub upper_case  : Attr {default => 0}
                 | 
              
| 365 | 361 | 
                   | 
              
| 366 | 
                  -sub create_sql {
                 | 
              |
| 367 | 
                  - my ($self, $template, $values, $filter) = @_;  | 
              |
| 368 | 
                  -  | 
              |
| 369 | 
                  - $filter ||= $self->bind_filter;  | 
              |
| 370 | 
                  -  | 
              |
| 371 | 
                  - $self->parse($template);  | 
              |
| 372 | 
                  -  | 
              |
| 373 | 
                  -    my ($sql, @bind) = $self->build_sql({bind_filter => $filter, values => $values});
                 | 
              |
| 374 | 
                  -  | 
              |
| 375 | 
                  - return ($sql, @bind);  | 
              |
| 376 | 
                  -}  | 
              |
| 377 | 
                  -  | 
              |
| 378 | 362 | 
                   sub tag_syntax : Attr { default => <<'EOS' };
                 | 
              
| 379 | 363 | 
                   {? name}         ?
                 | 
              
| 380 | 364 | 
                   {= name}         name = ?
                 | 
              
| ... | ... | 
                  @@ -392,12 +376,46 @@ sub tag_syntax : Attr { default => <<'EOS' };
                 | 
              
| 392 | 376 | 
                   {update_values}  set key1 = ?, key2 = ?, key3 = ?
                 | 
              
| 393 | 377 | 
                  EOS  | 
              
| 394 | 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 | 
                  +  | 
              |
| 395 | 413 | 
                   sub parse {
                 | 
              
| 396 | 414 | 
                  my ($self, $template) = @_;  | 
              
| 397 | 415 | 
                  $self->template($template);  | 
              
| 398 | 416 | 
                   | 
              
| 399 | 417 | 
                  # Clean start;  | 
              
| 400 | 
                  -    delete $self->{tree};
                 | 
              |
| 418 | 
                  + $self->tree([]);  | 
              |
| 401 | 419 | 
                   | 
              
| 402 | 420 | 
                  # Tags  | 
              
| 403 | 421 | 
                  my $tag_start = quotemeta $self->tag_start;  | 
              
| ... | ... | 
                  @@ -423,7 +441,7 @@ sub parse {
                 | 
              
| 423 | 441 | 
                  $tag ||= '';  | 
              
| 424 | 442 | 
                               unless ($self->tag_processors->{$tag_name}) {
                 | 
              
| 425 | 443 | 
                  my $tag_syntax = $self->tag_syntax;  | 
              
| 426 | 
                  -                croak("Tag '$tag' in SQL template is not exist.\n\n" .
                 | 
              |
| 444 | 
                  +                croak("Tag '{$tag}' in SQL template is not exist.\n\n" .
                 | 
              |
| 427 | 445 | 
                  "SQL template tag syntax\n" .  | 
              
| 428 | 446 | 
                  "$tag_syntax\n\n" .  | 
              
| 429 | 447 | 
                  "Your SQL template is \n$original_template\n\n");  | 
              
| ... | ... | 
                  @@ -441,7 +459,7 @@ sub build_sql {
                 | 
              
| 441 | 459 | 
                   | 
              
| 442 | 460 | 
                       my $tree        = $args->{tree} || $self->tree;
                 | 
              
| 443 | 461 | 
                       my $bind_filter = $args->{bind_filter} || $self->bind_filter;
                 | 
              
| 444 | 
                  -    my $values      = exists $args->{values} ? $args->{values} : $self->values;
                 | 
              |
| 462 | 
                  +    my $values      = $args->{values} || {};
                 | 
              |
| 445 | 463 | 
                   | 
              
| 446 | 464 | 
                  my @bind_values_all;  | 
              
| 447 | 465 | 
                  my $sql = '';  | 
              
| ... | ... | 
                  @@ -455,20 +473,21 @@ sub build_sql {
                 | 
              
| 455 | 473 | 
                  $sql .= $args->[0];  | 
              
| 456 | 474 | 
                  }  | 
              
| 457 | 475 | 
                           elsif ($type eq 'tag') {
                 | 
              
| 458 | 
                  -            my $tag_processor = $self->tag_processors->{$type};
                 | 
              |
| 476 | 
                  +            my $tag_processor = $self->tag_processors->{$tag_name};
                 | 
              |
| 459 | 477 | 
                   | 
              
| 460 | 478 | 
                               croak("Tag processor '$type' must be code reference")
                 | 
              
| 461 | 479 | 
                  unless ref $tag_processor eq 'CODE';  | 
              
| 462 | 480 | 
                   | 
              
| 463 | 481 | 
                  my ($expand, @bind_values)  | 
              
| 464 | 
                  -              = $self->tag_processors->{$type}->($tag_name, $args, $values,
                 | 
              |
| 465 | 
                  - $bind_filter, $self);  | 
              |
| 482 | 
                  + = $tag_processor->($tag_name, $args, $values,  | 
              |
| 483 | 
                  + $bind_filter, $self);  | 
              |
| 466 | 484 | 
                   | 
              
| 467 | 
                  -            unless ($self->place_holder_count($expand) eq @bind_values) {
                 | 
              |
| 485 | 
                  + $DB::single = 1;  | 
              |
| 486 | 
                  +            unless ($self->_placeholder_count($expand) == @bind_values) {
                 | 
              |
| 468 | 487 | 
                  require Data::Dumper;  | 
              
| 469 | 488 | 
                   | 
              
| 470 | 489 | 
                  my $bind_values_dump  | 
              
| 471 | 
                  - = Data::Dumper->Dump([\@bind_values], ['@bind_values']);  | 
              |
| 490 | 
                  + = Data::Dumper->Dump([\@bind_values], ['*bind_values']);  | 
              |
| 472 | 491 | 
                   | 
              
| 473 | 492 | 
                                   croak("Place holder count must be same as bind value count\n" .
                 | 
              
| 474 | 493 | 
                  "Tag : $tag_name\n" .  | 
              
| ... | ... | 
                  @@ -488,38 +507,19 @@ sub _placeholder_count {
                 | 
              
| 488 | 507 | 
                  $expand ||= '';  | 
              
| 489 | 508 | 
                   | 
              
| 490 | 509 | 
                  my $count = 0;  | 
              
| 491 | 
                  - my $pos = 0;  | 
              |
| 492 | 
                  -    while ((my $pos = index $expand, $pos) != -1) {
                 | 
              |
| 510 | 
                  + my $pos = -1;  | 
              |
| 511 | 
                  +    while (($pos = index($expand, '?', $pos + 1)) != -1) {
                 | 
              |
| 493 | 512 | 
                  $count++;  | 
              
| 494 | 513 | 
                  }  | 
              
| 495 | 514 | 
                  return $count;  | 
              
| 496 | 515 | 
                  }  | 
              
| 497 | 516 | 
                   | 
              
| 498 | 
                  -sub tag_processors : Attr {type => 'hash', deref => 1, auto_build => sub { 
                 | 
              |
| 499 | 
                  - shift->tag_processors(  | 
              |
| 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  | 
              |
| 510 | 
                  - );  | 
              |
| 511 | 
                  -}}  | 
              |
| 512 | 
                  -  | 
              |
| 513 | 
                  -sub add_tag_processor {
                 | 
              |
| 514 | 
                  - my $class = shift;  | 
              |
| 515 | 
                  -    my $tag_processors = ref $_[0] eq 'HASH' ? $_[0] : {@_};
                 | 
              |
| 516 | 
                  -    $class->tag_processor(%{$class->tag_processor}, %{$tag_processors});
                 | 
              |
| 517 | 
                  -}  | 
              |
| 518 | 
                  -  | 
              |
| 519 | 517 | 
                  Object::Simple->build_class;  | 
              
| 520 | 518 | 
                   | 
              
| 521 | 519 | 
                   | 
              
| 522 | 520 | 
                  package DBI::Custom::SQL::Template::TagProcessor;  | 
              
| 521 | 
                  +use strict;  | 
              |
| 522 | 
                  +use warnings;  | 
              |
| 523 | 523 | 
                   | 
              
| 524 | 524 | 
                   sub expand_place_holder {
                 | 
              
| 525 | 525 | 
                  my ($tag_name, $args, $values, $bind_filter, $sql_tmpl_obj) = @_;  | 
              
| ... | ... | 
                  @@ -550,20 +550,6 @@ sub expand_place_holder {
                 | 
              
| 550 | 550 | 
                  }  | 
              
| 551 | 551 | 
                  }  | 
              
| 552 | 552 | 
                   | 
              
| 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 | 553 | 
                  $tag_name = uc $tag_name if $sql_tmpl_obj->upper_case;  | 
              
| 568 | 554 | 
                   | 
              
| 569 | 555 | 
                  my $expand;  | 
              
| ... | ... | 
                  @@ -608,8 +594,8 @@ sub expand_insert_values {
                 | 
              
| 608 | 594 | 
                  $place_holders =~ s/, $//;  | 
              
| 609 | 595 | 
                  $place_holders .= ')';  | 
              
| 610 | 596 | 
                   | 
              
| 611 | 
                  - my $expand = $sql_tmpl_obj->uppser_case ? "$insert_keys VALUES $place_holders"  | 
              |
| 612 | 
                  - : "$insert_keys values $place_holders";  | 
              |
| 597 | 
                  + my $expand = $sql_tmpl_obj->upper_case ? "$insert_keys VALUES $place_holders"  | 
              |
| 598 | 
                  + : "$insert_keys values $place_holders";  | 
              |
| 613 | 599 | 
                   | 
              
| 614 | 600 | 
                  return ($expand, @bind_values);  | 
              
| 615 | 601 | 
                  }  | 
              
| ... | ... | 
                  @@ -617,7 +603,7 @@ sub expand_insert_values {
                 | 
              
| 617 | 603 | 
                   sub expand_update_set {
                 | 
              
| 618 | 604 | 
                  my ($tag_name, $args, $values, $bind_filter, $sql_tmpl_obj) = @_;  | 
              
| 619 | 605 | 
                   | 
              
| 620 | 
                  - my $expand = $sql_tmpl_obj->uppser_case ? 'SET ' : 'set ';  | 
              |
| 606 | 
                  + my $expand = $sql_tmpl_obj->upper_case ? 'SET ' : 'set ';  | 
              |
| 621 | 607 | 
                       $values = $args->[0] ? $values->{$args->[0]} : $values->{update_set};
                 | 
              
| 622 | 608 | 
                   | 
              
| 623 | 609 | 
                  my @bind_values;  | 
              
| ... | ... | 
                  @@ -667,8 +653,6 @@ Version 0.0101  | 
              
| 667 | 653 | 
                   | 
              
| 668 | 654 | 
                  =head2 filters  | 
              
| 669 | 655 | 
                   | 
              
| 670 | 
                  -=head2 initialize_class  | 
              |
| 671 | 
                  -  | 
              |
| 672 | 656 | 
                  =head2 prototype  | 
              
| 673 | 657 | 
                   | 
              
| 674 | 658 | 
                  =head2 new  | 
              
| ... | ... | 
                  @@ -685,17 +669,15 @@ Version 0.0101  | 
              
| 685 | 669 | 
                   | 
              
| 686 | 670 | 
                  =head2 connected  | 
              
| 687 | 671 | 
                   | 
              
| 688 | 
                  -=head2 dbh_option  | 
              |
| 689 | 
                  -  | 
              |
| 690 | 672 | 
                  =head2 disconnect  | 
              
| 691 | 673 | 
                   | 
              
| 692 | 674 | 
                  =head2 reconnect  | 
              
| 693 | 675 | 
                   | 
              
| 694 | 676 | 
                  =head2 result_class  | 
              
| 695 | 677 | 
                   | 
              
| 696 | 
                  -=head2 commit  | 
              |
| 678 | 
                  +=head2 run_tranzaction  | 
              |
| 697 | 679 | 
                   | 
              
| 698 | 
                  -=head2 rollback  | 
              |
| 680 | 
                  +=head2 valid_connect_info  | 
              |
| 699 | 681 | 
                   | 
              
| 700 | 682 | 
                   | 
              
| 701 | 683 | 
                  =head1 AUTHOR  | 
              
| ... | ... | 
                  @@ -5,13 +5,17 @@ use warnings;  | 
              
| 5 | 5 | 
                  use DBI::Custom;  | 
              
| 6 | 6 | 
                  use Scalar::Util qw/blessed/;  | 
              
| 7 | 7 | 
                   | 
              
| 8 | 
                  +my $sql_tmpl1 = DBI::Custom::SQL::Template->new->upper_case(0);  | 
              |
| 9 | 
                  +my $sql_tmpl2 = DBI::Custom::SQL::Template->new->upper_case(1);  | 
              |
| 10 | 
                  +my $sql_tmpl3 = DBI::Custom::SQL::Template->new->upper_case(2);  | 
              |
| 11 | 
                  +  | 
              |
| 8 | 12 | 
                   {
                 | 
              
| 9 | 13 | 
                  my $dbi = DBI::Custom->new(  | 
              
| 10 | 14 | 
                           connect_info => {
                 | 
              
| 11 | 
                  - user => 'a',  | 
              |
| 12 | 
                  - password => 'b',  | 
              |
| 13 | 
                  - data_source => 'c',  | 
              |
| 14 | 
                  -            options => {d => 1, e => 2}
                 | 
              |
| 15 | 
                  + user => 'a',  | 
              |
| 16 | 
                  + password => 'b',  | 
              |
| 17 | 
                  + data_source => 'c',  | 
              |
| 18 | 
                  +          options => {d => 1, e => 2}
                 | 
              |
| 15 | 19 | 
                  },  | 
              
| 16 | 20 | 
                           filters => {
                 | 
              
| 17 | 21 | 
                  f => 3,  | 
              
| ... | ... | 
                  @@ -19,37 +23,42 @@ use Scalar::Util qw/blessed/;  | 
              
| 19 | 23 | 
                  bind_filter => 'f',  | 
              
| 20 | 24 | 
                  fetch_filter => 'g',  | 
              
| 21 | 25 | 
                  dbh => 'e',  | 
              
| 22 | 
                  - result_class => 'g'  | 
              |
| 26 | 
                  + result_class => 'g',  | 
              |
| 27 | 
                  + sql_template => $sql_tmpl1,  | 
              |
| 28 | 
                  +        valid_connect_info => {i => 1}
                 | 
              |
| 23 | 29 | 
                  );  | 
              
| 24 | 
                  -  | 
              |
| 25 | 30 | 
                       is_deeply($dbi,{connect_info => {user => 'a', password => 'b', data_source => 'c', 
                 | 
              
| 26 | 31 | 
                                       options => {d => 1, e => 2}}, filters => {f => 3}, bind_filter => 'f',
                 | 
              
| 27 | 
                  - fetch_filter => 'g', dbh => 'e', result_class => 'g'}, 'new');  | 
              |
| 32 | 
                  + fetch_filter => 'g', dbh => 'e', result_class => 'g',  | 
              |
| 33 | 
                  +                    sql_template => $sql_tmpl1, valid_connect_info => {i => 1}}, 'new');
                 | 
              |
| 28 | 34 | 
                   | 
              
| 29 | 35 | 
                  isa_ok($dbi, 'DBI::Custom');  | 
              
| 30 | 36 | 
                  }  | 
              
| 31 | 37 | 
                   | 
              
| 38 | 
                  +  | 
              |
| 32 | 39 | 
                   {
                 | 
              
| 33 | 40 | 
                  package DBI::Custom::T1;  | 
              
| 34 | 41 | 
                  use base 'DBI::Custom';  | 
              
| 35 | 42 | 
                   | 
              
| 36 | 
                  -    __PACKAGE__->initialize_class(sub {
                 | 
              |
| 37 | 
                  - my $class = shift;  | 
              |
| 38 | 
                  -  | 
              |
| 39 | 
                  - $class  | 
              |
| 40 | 
                  - ->connect_info(  | 
              |
| 41 | 
                  - user => 'a',  | 
              |
| 42 | 
                  - password => 'b',  | 
              |
| 43 | 
                  - data_source => 'c',  | 
              |
| 44 | 
                  -            options => {d => 1, e => 2}
                 | 
              |
| 45 | 
                  - )  | 
              |
| 46 | 
                  - ->filters(  | 
              |
| 47 | 
                  - f => 3  | 
              |
| 48 | 
                  - )  | 
              |
| 49 | 
                  -          ->bind_filter('f')
                 | 
              |
| 50 | 
                  -          ->fetch_filter('g')
                 | 
              |
| 51 | 
                  -          ->dbh('e')
                 | 
              |
| 52 | 
                  - });  | 
              |
| 43 | 
                  + my $prototype = __PACKAGE__->prototype;  | 
              |
| 44 | 
                  +  | 
              |
| 45 | 
                  + $prototype  | 
              |
| 46 | 
                  + ->connect_info(  | 
              |
| 47 | 
                  + user => 'a',  | 
              |
| 48 | 
                  + password => 'b',  | 
              |
| 49 | 
                  + data_source => 'c',  | 
              |
| 50 | 
                  +          options => {d => 1, e => 2}
                 | 
              |
| 51 | 
                  + )  | 
              |
| 52 | 
                  + ->filters(  | 
              |
| 53 | 
                  + f => 3  | 
              |
| 54 | 
                  + )  | 
              |
| 55 | 
                  +      ->bind_filter('f')
                 | 
              |
| 56 | 
                  +      ->fetch_filter('g')
                 | 
              |
| 57 | 
                  +      ->dbh('e')
                 | 
              |
| 58 | 
                  +      ->result_class('DBI::Custom::Result')
                 | 
              |
| 59 | 
                  + ->sql_template($sql_tmpl1)  | 
              |
| 60 | 
                  +      ->valid_connect_info({p => 1})
                 | 
              |
| 61 | 
                  + ;  | 
              |
| 53 | 62 | 
                  }  | 
              
| 54 | 63 | 
                   {
                 | 
              
| 55 | 64 | 
                  my $dbi = DBI::Custom::T1->new(  | 
              
| ... | ... | 
                  @@ -64,11 +73,16 @@ use Scalar::Util qw/blessed/;  | 
              
| 64 | 73 | 
                  },  | 
              
| 65 | 74 | 
                  bind_filter => 'fo',  | 
              
| 66 | 75 | 
                  fetch_filter => 'go',  | 
              
| 67 | 
                  - result_class => 'ho'  | 
              |
| 76 | 
                  + result_class => 'ho',  | 
              |
| 77 | 
                  + sql_template => $sql_tmpl1,  | 
              |
| 78 | 
                  +        valid_connect_info => {io => 1}
                 | 
              |
| 68 | 79 | 
                  );  | 
              
| 69 | 
                  -  | 
              |
| 80 | 
                  +    my $sql_tmpl = delete $dbi->{sql_template};
                 | 
              |
| 81 | 
                  + is($sql_tmpl->upper_case, 0);  | 
              |
| 70 | 82 | 
                       is_deeply($dbi,{connect_info => {user => 'ao', password => 'bo', data_source => 'co', options => {do => 10, eo => 20}}
                 | 
              
| 71 | 
                  -                    ,filters => {fo => 30}, bind_filter => 'fo', fetch_filter => 'go', result_class => 'ho'}, 'new arguments');
                 | 
              |
| 83 | 
                  +                    ,filters => {fo => 30}, bind_filter => 'fo', fetch_filter => 'go', result_class => 'ho',
                 | 
              |
| 84 | 
                  +                    ,valid_connect_info => {io => 1}
                 | 
              |
| 85 | 
                  + }, 'new arguments');  | 
              |
| 72 | 86 | 
                   | 
              
| 73 | 87 | 
                  isa_ok($dbi, 'DBI::Custom::T1');  | 
              
| 74 | 88 | 
                  }  | 
              
| ... | ... | 
                  @@ -76,8 +90,10 @@ use Scalar::Util qw/blessed/;  | 
              
| 76 | 90 | 
                   {
                 | 
              
| 77 | 91 | 
                  my $dbi = DBI::Custom::T1->new;  | 
              
| 78 | 92 | 
                   | 
              
| 93 | 
                  +    my $sql_tmpl = delete $dbi->{sql_template};
                 | 
              |
| 79 | 94 | 
                       is_deeply($dbi,{connect_info => {user => 'a', password => 'b', data_source => 'c', options => {d => 1, e => 2}},
                 | 
              
| 80 | 
                  -                    filters => {f => 3}, bind_filter => 'f', fetch_filter => 'g', result_class => 'DBI::Custom::Result'}, 'new custom class');
                 | 
              |
| 95 | 
                  +                    filters => {f => 3}, bind_filter => 'f', fetch_filter => 'g', result_class => 'DBI::Custom::Result',
                 | 
              |
| 96 | 
                  +                    valid_connect_info => {p => 1}}, 'new custom class');
                 | 
              |
| 81 | 97 | 
                   | 
              
| 82 | 98 | 
                  isa_ok($dbi, 'DBI::Custom::T1');  | 
              
| 83 | 99 | 
                   | 
              
| ... | ... | 
                  @@ -91,8 +107,11 @@ use Scalar::Util qw/blessed/;  | 
              
| 91 | 107 | 
                   {
                 | 
              
| 92 | 108 | 
                  my $dbi = DBI::Custom::T1_2->new;  | 
              
| 93 | 109 | 
                   | 
              
| 110 | 
                  +    my $sql_tmpl = delete $dbi->{sql_template};
                 | 
              |
| 111 | 
                  + is($sql_tmpl->upper_case, 0);  | 
              |
| 94 | 112 | 
                       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'}, 'new custom class inherit');
                 | 
              |
| 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');
                 | 
              |
| 96 | 115 | 
                   | 
              
| 97 | 116 | 
                  isa_ok($dbi, 'DBI::Custom::T1_2');  | 
              
| 98 | 117 | 
                  }  | 
              
| ... | ... | 
                  @@ -101,33 +120,35 @@ use Scalar::Util qw/blessed/;  | 
              
| 101 | 120 | 
                  package DBI::Custom::T1_3;  | 
              
| 102 | 121 | 
                  use base 'DBI::Custom::T1';  | 
              
| 103 | 122 | 
                   | 
              
| 104 | 
                  -    __PACKAGE__->initialize_class(sub {
                 | 
              |
| 105 | 
                  - my $class = shift;  | 
              |
| 123 | 
                  + my $prototype = __PACKAGE__->prototype;  | 
              |
| 106 | 124 | 
                   | 
              
| 107 | 
                  - $class  | 
              |
| 108 | 
                  - ->connect_info(  | 
              |
| 109 | 
                  - user => 'ao',  | 
              |
| 110 | 
                  - password => 'bo',  | 
              |
| 111 | 
                  - data_source => 'co',  | 
              |
| 112 | 
                  -            options => {do => 10, eo => 20}
                 | 
              |
| 113 | 
                  - )  | 
              |
| 114 | 
                  - ->filters(  | 
              |
| 115 | 
                  - fo => 30  | 
              |
| 116 | 
                  - )  | 
              |
| 117 | 
                  -          ->bind_filter('fo')
                 | 
              |
| 118 | 
                  -          ->fetch_filter('go')
                 | 
              |
| 119 | 
                  -          ->dbh('eo')
                 | 
              |
| 120 | 
                  -          ->result_class('ho');
                 | 
              |
| 121 | 
                  -  | 
              |
| 122 | 
                  - });  | 
              |
| 123 | 
                  -  | 
              |
| 125 | 
                  + $prototype  | 
              |
| 126 | 
                  + ->connect_info(  | 
              |
| 127 | 
                  + user => 'ao',  | 
              |
| 128 | 
                  + password => 'bo',  | 
              |
| 129 | 
                  + data_source => 'co',  | 
              |
| 130 | 
                  +        options => {do => 10, eo => 20}
                 | 
              |
| 131 | 
                  + )  | 
              |
| 132 | 
                  + ->filters(  | 
              |
| 133 | 
                  + fo => 30  | 
              |
| 134 | 
                  + )  | 
              |
| 135 | 
                  +      ->bind_filter('fo')
                 | 
              |
| 136 | 
                  +      ->fetch_filter('go')
                 | 
              |
| 137 | 
                  +      ->dbh('eo')
                 | 
              |
| 138 | 
                  +      ->result_class('ho')
                 | 
              |
| 139 | 
                  + ->sql_template($sql_tmpl2)  | 
              |
| 140 | 
                  +      ->valid_connect_info({p => 3})
                 | 
              |
| 141 | 
                  + ;  | 
              |
| 124 | 142 | 
                  }  | 
              
| 125 | 143 | 
                   | 
              
| 126 | 144 | 
                   {
                 | 
              
| 127 | 145 | 
                  my $dbi = DBI::Custom::T1_3->new;  | 
              
| 128 | 146 | 
                   | 
              
| 147 | 
                  +    my $sql_tmpl = delete $dbi->{sql_template};
                 | 
              |
| 148 | 
                  + is($sql_tmpl->upper_case, 1);  | 
              |
| 129 | 149 | 
                       is_deeply($dbi,{connect_info => {user => 'ao', password => 'bo', data_source => 'co', options => {do => 10, eo => 20}},
                 | 
              
| 130 | 
                  -                    filters => {fo => 30}, bind_filter => 'fo', fetch_filter => 'go', result_class => 'ho'}, 'new custom class');
                 | 
              |
| 150 | 
                  +                    filters => {fo => 30}, bind_filter => 'fo', fetch_filter => 'go', result_class => 'ho',
                 | 
              |
| 151 | 
                  +                    valid_connect_info => {p => 3}}, 'new custom class');
                 | 
              |
| 131 | 152 | 
                   | 
              
| 132 | 153 | 
                  isa_ok($dbi, 'DBI::Custom::T1_3');  | 
              
| 133 | 154 | 
                  }  | 
              
| ... | ... | 
                  @@ -146,11 +167,16 @@ use Scalar::Util qw/blessed/;  | 
              
| 146 | 167 | 
                  bind_filter => 'f',  | 
              
| 147 | 168 | 
                  fetch_filter => 'g',  | 
              
| 148 | 169 | 
                  dbh => 'e',  | 
              
| 149 | 
                  - result_class => 'h'  | 
              |
| 170 | 
                  + result_class => 'h',  | 
              |
| 171 | 
                  + sql_template => $sql_tmpl3,  | 
              |
| 172 | 
                  +        valid_connect_info => {p => 4}
                 | 
              |
| 150 | 173 | 
                  );  | 
              
| 151 | 174 | 
                   | 
              
| 175 | 
                  +    my $sql_tmpl = delete $dbi->{sql_template};
                 | 
              |
| 176 | 
                  + is($sql_tmpl->upper_case, 2);  | 
              |
| 152 | 177 | 
                       is_deeply($dbi,{connect_info => {user => 'a', password => 'b', data_source => 'c', options => {d => 1, e => 2}},
                 | 
              
| 153 | 
                  -                    filters => {f => 3}, bind_filter => 'f', fetch_filter => 'g', dbh => 'e', result_class => 'h'}, 'new');
                 | 
              |
| 178 | 
                  +                    filters => {f => 3}, bind_filter => 'f', fetch_filter => 'g', dbh => 'e', result_class => 'h',
                 | 
              |
| 179 | 
                  +                    valid_connect_info => {p => 4}}, 'new');
                 | 
              |
| 154 | 180 | 
                   | 
              
| 155 | 181 | 
                  isa_ok($dbi, 'DBI::Custom');  | 
              
| 156 | 182 | 
                  }  |