| ... | ... | 
                  @@ -1,3 +1,8 @@  | 
              
| 1 | 
                  +0.1742  | 
              |
| 2 | 
                  + - fixed update_or_insert method bug  | 
              |
| 3 | 
                  + - micro optimization  | 
              |
| 4 | 
                  +0.1741  | 
              |
| 5 | 
                  + - added EXPERIMENTAL update_or_insert to DBIx::Custom::Model  | 
              |
| 1 | 6 | 
                  0.1740  | 
              
| 2 | 7 | 
                  - EXPERIMENTAL update_or_insert need id and primary_key option  | 
              
| 3 | 8 | 
                  and added option option  | 
              
| ... | ... | 
                  @@ -1,7 +1,7 @@  | 
              
| 1 | 1 | 
                  package DBIx::Custom;  | 
              
| 2 | 2 | 
                  use Object::Simple -base;  | 
              
| 3 | 3 | 
                   | 
              
| 4 | 
                  -our $VERSION = '0.1740';  | 
              |
| 4 | 
                  +our $VERSION = '0.1742';  | 
              |
| 5 | 5 | 
                  use 5.008001;  | 
              
| 6 | 6 | 
                   | 
              
| 7 | 7 | 
                  use Carp 'croak';  | 
              
| ... | ... | 
                  @@ -36,34 +36,38 @@ sub AUTOLOAD {
                 | 
              
| 36 | 36 | 
                  }  | 
              
| 37 | 37 | 
                   | 
              
| 38 | 38 | 
                  my @methods = qw/insert insert_at update update_at update_all  | 
              
| 39 | 
                  - delete delete_at delete_all select select_at count/;  | 
              |
| 39 | 
                  + delete delete_at delete_all select select_at count update_or_insert/;  | 
              |
| 40 | 40 | 
                   for my $method (@methods) {
                 | 
              
| 41 | 
                  +  | 
              |
| 42 | 
                  + my $code =  | 
              |
| 43 | 
                  +         qq/sub {/ .
                 | 
              |
| 44 | 
                  + qq/my \$self = shift;/ .  | 
              |
| 45 | 
                  + qq/\$self->dbi->$method(/ .  | 
              |
| 46 | 
                  + qq/\@_ % 2 ? shift : (),/;  | 
              |
| 41 | 47 | 
                   | 
              
| 42 | 
                  -    my $code = sub {
                 | 
              |
| 43 | 
                  - my $self = shift;  | 
              |
| 44 | 
                  -  | 
              |
| 45 | 
                  -        unless ($self->{_attribute_cache}{$self}) {
                 | 
              |
| 46 | 
                  - $self->$_ for qw/table bind_type primary_key  | 
              |
| 47 | 
                  - type join created_at updated_at/;  | 
              |
| 48 | 
                  -            $self->{_attribute_cache}{$self} = 1;
                 | 
              |
| 49 | 
                  - }  | 
              |
| 50 | 
                  -  | 
              |
| 51 | 
                  - $self->dbi->$method(  | 
              |
| 52 | 
                  - @_ % 2 ? shift : (),  | 
              |
| 53 | 
                  -            table => $self->{table},
                 | 
              |
| 54 | 
                  -            exists $self->{type} ? (type => $self->{type}) : (),
                 | 
              |
| 55 | 
                  -            exists $self->{created_at} && $method eq 'insert' ? (created_at => $self->{created_at}) : (),
                 | 
              |
| 56 | 
                  -            exists $self->{updated_at} && ($method eq 'insert' || $method eq 'update') ? (updated_at => $self->{updated_at}) : (),
                 | 
              |
| 57 | 
                  -            exists $self->{bind_type} ? (bind_type=> $self->{bind_type}) : (),
                 | 
              |
| 58 | 
                  -            exists $self->{primary_key} ? (primary_key => $self->{primary_key}) : (),
                 | 
              |
| 59 | 
                  -            exists $self->{join} && index($method, 'select') != -1 ? (join => $self->{join}) : (),
                 | 
              |
| 60 | 
                  - @_  | 
              |
| 61 | 
                  - )  | 
              |
| 62 | 
                  - };  | 
              |
| 48 | 
                  +  | 
              |
| 49 | 
                  + my @attrs = qw/table type primary_key bind_type/;  | 
              |
| 50 | 
                  + my @insert_attrs = qw/created_at updated_at/;  | 
              |
| 51 | 
                  + my @update_attrs = qw/updated_at/;  | 
              |
| 52 | 
                  + my @update_or_insert_attrs = qw/created_at updated_at/;  | 
              |
| 53 | 
                  + my @select_attrs = qw/join/;  | 
              |
| 54 | 
                  +    if ($method eq 'insert') { push @attrs, @insert_attrs }
                 | 
              |
| 55 | 
                  +    elsif ($method eq 'update_or_insert') {
                 | 
              |
| 56 | 
                  + push @attrs, @update_or_insert_attrs;  | 
              |
| 57 | 
                  + }  | 
              |
| 58 | 
                  +    elsif ($method eq 'update') { push @attrs, @update_attrs }
                 | 
              |
| 59 | 
                  +    elsif (index($method, 'select') != -1) { push @attrs, @select_attrs }
                 | 
              |
| 60 | 
                  +  | 
              |
| 61 | 
                  +    for my $attr (@attrs) {
                 | 
              |
| 62 | 
                  +        $code .= "$attr => exists \$self->{$attr} ? \$self->{$attr} : \$self->$attr,";
                 | 
              |
| 63 | 
                  + }  | 
              |
| 64 | 
                  +  | 
              |
| 65 | 
                  + $code .= qq/\@_);/ .  | 
              |
| 66 | 
                  + qq/}/;  | 
              |
| 63 | 67 | 
                   | 
              
| 64 | 68 | 
                  no strict 'refs';  | 
              
| 65 | 
                  - my $class = __PACKAGE__;  | 
              |
| 66 | 
                  -    *{"${class}::$method"} = $code;
                 | 
              |
| 69 | 
                  +    *{__PACKAGE__ . "::$method"} = eval $code;
                 | 
              |
| 70 | 
                  + croak $code if $@;  | 
              |
| 67 | 71 | 
                  }  | 
              
| 68 | 72 | 
                   | 
              
| 69 | 73 | 
                   sub execute {
                 | 
              
| ... | ... | 
                  @@ -214,28 +218,28 @@ Options is same as C<select> method's ones.  | 
              
| 214 | 218 | 
                  $model->delete(...);  | 
              
| 215 | 219 | 
                   | 
              
| 216 | 220 | 
                  Same as C<delete> of L<DBIx::Custom> except that  | 
              
| 217 | 
                  -you don't have to specify C<table> and C<primary_key> option.  | 
              |
| 221 | 
                  +you don't have to specify options if you set attribute in model.  | 
              |
| 218 | 222 | 
                   | 
              
| 219 | 223 | 
                  =head2 C<delete_all>  | 
              
| 220 | 224 | 
                   | 
              
| 221 | 225 | 
                  $model->delete_all(...);  | 
              
| 222 | 226 | 
                   | 
              
| 223 | 227 | 
                  Same as C<delete_all> of L<DBIx::Custom> except that  | 
              
| 224 | 
                  -you don't have to specify C<table> and C<primary_key> option.  | 
              |
| 228 | 
                  +you don't have to specify options if you set attribute in model.  | 
              |
| 225 | 229 | 
                   | 
              
| 226 | 230 | 
                  =head2 C<execute>  | 
              
| 227 | 231 | 
                   | 
              
| 228 | 232 | 
                  $model->execute(...);  | 
              
| 229 | 233 | 
                   | 
              
| 230 | 234 | 
                  Same as C<execute> of L<DBIx::Custom> except that  | 
              
| 231 | 
                  -you don't have to specify C<table> and C<primary_key> option.  | 
              |
| 235 | 
                  +you don't have to specify options if you set attribute in model.  | 
              |
| 232 | 236 | 
                   | 
              
| 233 | 237 | 
                  =head2 C<insert>  | 
              
| 234 | 238 | 
                   | 
              
| 235 | 239 | 
                  $model->insert(...);  | 
              
| 236 | 240 | 
                   | 
              
| 237 | 241 | 
                  Same as C<insert> of L<DBIx::Custom> except that  | 
              
| 238 | 
                  -you don't have to specify C<table> and C<primary_key> option.  | 
              |
| 242 | 
                  +you don't have to specify options if you set attribute in model.  | 
              |
| 239 | 243 | 
                   | 
              
| 240 | 244 | 
                  =head2 C<helper>  | 
              
| 241 | 245 | 
                   | 
              
| ... | ... | 
                  @@ -281,20 +285,27 @@ Create a L<DBIx::Custom::Model> object.  | 
              
| 281 | 285 | 
                  $model->select(...);  | 
              
| 282 | 286 | 
                   | 
              
| 283 | 287 | 
                  Same as C<select> of L<DBIx::Custom> except that  | 
              
| 284 | 
                  -you don't have to specify C<table>, C<primary_key> and C<jon> option.  | 
              |
| 288 | 
                  +you don't have to specify options if you set attribute in model.  | 
              |
| 285 | 289 | 
                   | 
              
| 286 | 290 | 
                  =head2 C<update>  | 
              
| 287 | 291 | 
                   | 
              
| 288 | 292 | 
                  $model->update(...);  | 
              
| 289 | 293 | 
                   | 
              
| 290 | 294 | 
                  Same as C<update> of L<DBIx::Custom> except that  | 
              
| 291 | 
                  -you don't have to specify C<table> and C<primary_key> option.  | 
              |
| 295 | 
                  +you don't have to specify options if you set attribute in model.  | 
              |
| 292 | 296 | 
                   | 
              
| 293 | 297 | 
                  =head2 C<update_all>  | 
              
| 294 | 298 | 
                   | 
              
| 295 | 299 | 
                  $model->update_all(param => \%param);  | 
              
| 296 | 300 | 
                   | 
              
| 297 | 301 | 
                  Same as C<update_all> of L<DBIx::Custom> except that  | 
              
| 298 | 
                  -you don't have to specify C<table> and C<primary_key> option.  | 
              |
| 302 | 
                  +you don't have to specify options if you set attribute in model.  | 
              |
| 303 | 
                  +  | 
              |
| 304 | 
                  +=head2 C<update_or_insert EXPERIMENTAL>  | 
              |
| 305 | 
                  +  | 
              |
| 306 | 
                  + $model->update_or_insert(...);  | 
              |
| 307 | 
                  +  | 
              |
| 308 | 
                  +Same as C<update> of L<DBIx::Custom> except that  | 
              |
| 309 | 
                  +you don't have to specify options if you set attribute in model.  | 
              |
| 299 | 310 | 
                   | 
              
| 300 | 311 | 
                  =cut  | 
              
| ... | ... | 
                  @@ -47,6 +47,7 @@ sub to_string {
                 | 
              
| 47 | 47 | 
                       $self->{_query_builder} = $self->dbi->query_builder;
                 | 
              
| 48 | 48 | 
                       $self->{_safety_character} = $self->dbi->safety_character;
                 | 
              
| 49 | 49 | 
                       $self->{_quote} = $self->dbi->_quote;
                 | 
              
| 50 | 
                  +    $self->{_tag_parse} = $self->dbi->tag_parse;
                 | 
              |
| 50 | 51 | 
                  $self->_parse($clause, $where, $count, 'and');  | 
              
| 51 | 52 | 
                   | 
              
| 52 | 53 | 
                   | 
              
| ... | ... | 
                  @@ -105,23 +106,19 @@ sub _parse {
                 | 
              
| 105 | 106 | 
                  my $pushed;  | 
              
| 106 | 107 | 
                   | 
              
| 107 | 108 | 
                  # Column  | 
              
| 108 | 
                  -        my $columns = $self->{_query_builder}->build_query($clause)->{columns};
                 | 
              |
| 109 | 
                  -        if (@$columns == 0) {
                 | 
              |
| 109 | 
                  +        my $c = $self->{_safety_character};
                 | 
              |
| 110 | 
                  +  | 
              |
| 111 | 
                  + my $column;  | 
              |
| 112 | 
                  +        if ($clause =~ /(\s|^)\{/ && $self->{_tag_parse}) {
                 | 
              |
| 113 | 
                  +            my $columns = $self->dbi->query_builder->build_query($clause)->{columns};
                 | 
              |
| 114 | 
                  + $column = $columns->[0];  | 
              |
| 115 | 
                  + }  | 
              |
| 116 | 
                  +        else { ($column) = $clause =~ /:([$c\.]+)/ }
                 | 
              |
| 117 | 
                  +        unless (defined $column) {
                 | 
              |
| 110 | 118 | 
                  push @$where, $clause;  | 
              
| 111 | 119 | 
                  $pushed = 1;  | 
              
| 112 | 120 | 
                  return $pushed;  | 
              
| 113 | 121 | 
                  }  | 
              
| 114 | 
                  -        elsif (@$columns != 1) {
                 | 
              |
| 115 | 
                  -            croak qq{Each part contains one column name: "$clause" (}
                 | 
              |
| 116 | 
                  - . _subname . ")";  | 
              |
| 117 | 
                  - }  | 
              |
| 118 | 
                  -  | 
              |
| 119 | 
                  - # Remove quote  | 
              |
| 120 | 
                  - my $column = $columns->[0];  | 
              |
| 121 | 
                  -        if (my $q = $self->{_quote}) {
                 | 
              |
| 122 | 
                  - $q = quotemeta($q);  | 
              |
| 123 | 
                  - $column =~ s/[$q]//g;  | 
              |
| 124 | 
                  - }  | 
              |
| 125 | 122 | 
                   | 
              
| 126 | 123 | 
                  # Column count up  | 
              
| 127 | 124 | 
                           my $count = ++$count->{$column};
                 | 
              
| ... | ... | 
                  @@ -152,7 +149,6 @@ sub _parse {
                 | 
              
| 152 | 149 | 
                  }  | 
              
| 153 | 150 | 
                  return;  | 
              
| 154 | 151 | 
                  }  | 
              
| 155 | 
                  -  | 
              |
| 156 | 152 | 
                  1;  | 
              
| 157 | 153 | 
                   | 
              
| 158 | 154 | 
                  =head1 NAME  | 
              
| ... | ... | 
                  @@ -616,7 +616,6 @@ is($row->{$key2}, $row->{$key3});
                 | 
              
| 616 | 616 | 
                  test 'update_or_insert';  | 
              
| 617 | 617 | 
                   eval { $dbi->execute("drop table $table1") };
                 | 
              
| 618 | 618 | 
                  $dbi->execute($create_table1);  | 
              
| 619 | 
                  -$DB::single = 1;  | 
              |
| 620 | 619 | 
                  $dbi->update_or_insert(  | 
              
| 621 | 620 | 
                       {$key2 => 2},
                 | 
              
| 622 | 621 | 
                  table => $table1,  | 
              
| ... | ... | 
                  @@ -644,6 +643,17 @@ eval {
                 | 
              
| 644 | 643 | 
                   | 
              
| 645 | 644 | 
                  like($@, qr/primary_key/);  | 
              
| 646 | 645 | 
                   | 
              
| 646 | 
                  +test 'model update_or_insert';  | 
              |
| 647 | 
                  +eval { $dbi->execute("drop table $table1") };
                 | 
              |
| 648 | 
                  +$dbi->execute($create_table1);  | 
              |
| 649 | 
                  +$model = $dbi->create_model(  | 
              |
| 650 | 
                  + table => $table1,  | 
              |
| 651 | 
                  + primary_key => $key1  | 
              |
| 652 | 
                  +);  | 
              |
| 653 | 
                  +$model->update_or_insert({$key2 => 2}, id => 1);
                 | 
              |
| 654 | 
                  +$row = $model->select(id => 1)->one;  | 
              |
| 655 | 
                  +is_deeply($row, {$key1 => 1, $key2 => 2}, "basic");
                 | 
              |
| 656 | 
                  +  | 
              |
| 647 | 657 | 
                  test 'default_bind_filter';  | 
              
| 648 | 658 | 
                   $dbi->execute("delete from $table1");
                 | 
              
| 649 | 659 | 
                  $dbi->register_filter(  | 
              
| ... | ... | 
                  @@ -1606,12 +1616,6 @@ $result = $dbi->select(  | 
              
| 1606 | 1616 | 
                  $row = $result->all;  | 
              
| 1607 | 1617 | 
                   is_deeply($row, [{$key1 => 1, $key2 => 2}]);
                 | 
              
| 1608 | 1618 | 
                   | 
              
| 1609 | 
                  -$where = $dbi->where  | 
              |
| 1610 | 
                  -             ->clause("$key1 = :$key1 $key2 = :$key2")
                 | 
              |
| 1611 | 
                  -             ->param({$key1 => 1});
                 | 
              |
| 1612 | 
                  -eval{$where->to_string};
                 | 
              |
| 1613 | 
                  -like($@, qr/one column/);  | 
              |
| 1614 | 
                  -  | 
              |
| 1615 | 1619 | 
                  $where = $dbi->where  | 
              
| 1616 | 1620 | 
                                ->clause(['or', ("$key1 = :$key1") x 3])
                 | 
              
| 1617 | 1621 | 
                                ->param({$key1 => [$dbi->not_exists, 1, 3]});
                 | 
              
| ... | ... | 
                  @@ -29,6 +29,7 @@ sub test { print "# $_[0]\n" }
                 | 
              
| 29 | 29 | 
                   | 
              
| 30 | 30 | 
                  # Varialbes for tests  | 
              
| 31 | 31 | 
                  my $dbname;  | 
              
| 32 | 
                  +my $row;  | 
              |
| 32 | 33 | 
                  my $rows;  | 
              
| 33 | 34 | 
                  my $result;  | 
              
| 34 | 35 | 
                   | 
              
| ... | ... | 
                  @@ -47,7 +48,6 @@ $dbi->do('create table table1 (key1 varchar(255), key2 varchar(255)) engine=Inno
                 | 
              
| 47 | 48 | 
                   | 
              
| 48 | 49 | 
                  test 'update_or_insert';  | 
              
| 49 | 50 | 
                  $dbi->delete_all(table => 'table1');  | 
              
| 50 | 
                  -$ENV{DBIX_CUSTOM_DEBUG} = 1;
                 | 
              |
| 51 | 51 | 
                  $dbi->update_or_insert(  | 
              
| 52 | 52 | 
                       {key2 => 2},
                 | 
              
| 53 | 53 | 
                  table => 'table1',  | 
              
| ... | ... | 
                  @@ -60,7 +60,7 @@ $dbi->update_or_insert(  | 
              
| 60 | 60 | 
                  }  | 
              
| 61 | 61 | 
                  );  | 
              
| 62 | 62 | 
                   | 
              
| 63 | 
                  -my $row = $dbi->select(id => 1, table => 'table1', primary_key => 'key1')->one;  | 
              |
| 63 | 
                  +$row = $dbi->select(id => 1, table => 'table1', primary_key => 'key1')->one;  | 
              |
| 64 | 64 | 
                   is_deeply($row, {key1 => 1, key2 => 2}, "basic");
                 | 
              
| 65 | 65 | 
                   | 
              
| 66 | 66 | 
                  $dbi->update_or_insert(  | 
              
| ... | ... | 
                  @@ -75,7 +75,7 @@ $dbi->update_or_insert(  | 
              
| 75 | 75 | 
                  }  | 
              
| 76 | 76 | 
                  );  | 
              
| 77 | 77 | 
                   | 
              
| 78 | 
                  -my $row = $dbi->select(id => 1, table => 'table1', primary_key => 'key1')->one;  | 
              |
| 78 | 
                  +$row = $dbi->select(id => 1, table => 'table1', primary_key => 'key1')->one;  | 
              |
| 79 | 79 | 
                   is_deeply($row, {key1 => 1, key2 => 3}, "basic");
                 | 
              
| 80 | 80 | 
                   | 
              
| 81 | 81 | 
                  # Test memory leaks  | 
              
| ... | ... | 
                  @@ -37,6 +37,7 @@ my $result;  | 
              
| 37 | 37 | 
                  my $row;  | 
              
| 38 | 38 | 
                  my $rows;  | 
              
| 39 | 39 | 
                  my $binary;  | 
              
| 40 | 
                  +my $model;  | 
              |
| 40 | 41 | 
                   | 
              
| 41 | 42 | 
                  # Prepare table  | 
              
| 42 | 43 | 
                  $dbi = DBIx::Custom->connect;  | 
              
| ... | ... | 
                  @@ -70,6 +71,17 @@ $row = $result->one;  | 
              
| 70 | 71 | 
                   is($row->{key1}, $row->{key2});
                 | 
              
| 71 | 72 | 
                   is($row->{key1}, $row->{key3});
                 | 
              
| 72 | 73 | 
                   | 
              
| 74 | 
                  +$dbi = DBIx::Custom->connect;  | 
              |
| 75 | 
                  +eval { $dbi->execute('drop table table1') };
                 | 
              |
| 76 | 
                  +$dbi->execute('create table table1 (key1, key2, key3)');
                 | 
              |
| 77 | 
                  +$dbi->now(\"datetime('now')");
                 | 
              |
| 78 | 
                  +$model = $dbi->create_model(created_at => 'key2', updated_at => 'key3', table => 'table1');  | 
              |
| 79 | 
                  +$model->insert({key1 => \"datetime('now')"});
                 | 
              |
| 80 | 
                  +$result = $dbi->select(table => 'table1');  | 
              |
| 81 | 
                  +$row = $result->one;  | 
              |
| 82 | 
                  +is($row->{key1}, $row->{key2});
                 | 
              |
| 83 | 
                  +is($row->{key1}, $row->{key3});
                 | 
              |
| 84 | 
                  +  | 
              |
| 73 | 85 | 
                  test 'insert created_at and updated_at scalar reference';  | 
              
| 74 | 86 | 
                  $dbi = DBIx::Custom->connect;  | 
              
| 75 | 87 | 
                   eval { $dbi->execute('drop table table1') };
                 | 
              
| ... | ... | 
                  @@ -91,6 +103,28 @@ $result = $dbi->select(table => 'table1');  | 
              
| 91 | 103 | 
                  $row = $result->one;  | 
              
| 92 | 104 | 
                   is($row->{key1}, $row->{key2});
                 | 
              
| 93 | 105 | 
                   | 
              
| 106 | 
                  +test 'update_or_insert created_at and updated_at';  | 
              |
| 107 | 
                  +eval { $dbi->execute('drop table table1') };
                 | 
              |
| 108 | 
                  +$dbi->execute('create table table1 (key1, key2, key3, key4)');
                 | 
              |
| 109 | 
                  +$dbi->now(\"datetime('now')");
                 | 
              |
| 110 | 
                  +$model = $dbi->create_model(created_at => 'key2', updated_at => 'key3', table => 'table1',  | 
              |
| 111 | 
                  +primary_key => 'key4');  | 
              |
| 112 | 
                  +$model->update_or_insert({key1 => \"datetime('now')"}, id => 1);
                 | 
              |
| 113 | 
                  +$result = $model->select(table => 'table1', id => 1);  | 
              |
| 114 | 
                  +$row = $result->one;  | 
              |
| 115 | 
                  +is($row->{key1}, $row->{key2});
                 | 
              |
| 116 | 
                  +is($row->{key1}, $row->{key3});
                 | 
              |
| 117 | 
                  +  | 
              |
| 118 | 
                  +$dbi = DBIx::Custom->connect;  | 
              |
| 119 | 
                  +eval { $dbi->execute('drop table table1') };
                 | 
              |
| 120 | 
                  +$dbi->execute('create table table1 (key1, key2)');
                 | 
              |
| 121 | 
                  +$dbi->now(\"datetime('now')");
                 | 
              |
| 122 | 
                  +$model = $dbi->create_model(updated_at => 'key2', table => 'table1');  | 
              |
| 123 | 
                  +$model->insert({key1 => \"datetime('now')"});
                 | 
              |
| 124 | 
                  +$result = $dbi->select(table => 'table1');  | 
              |
| 125 | 
                  +$row = $result->one;  | 
              |
| 126 | 
                  +is($row->{key1}, $row->{key2});
                 | 
              |
| 127 | 
                  +  | 
              |
| 94 | 128 | 
                  test 'DBIX_CUSTOM_DEBUG ok';  | 
              
| 95 | 129 | 
                   {
                 | 
              
| 96 | 130 | 
                       local $ENV{DBIX_CUSTOM_DEBUG} = 1;
                 |