Showing 7 changed files with 106 additions and 56 deletions
+5
Changes
... ...
@@ -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 -1
lib/DBIx/Custom.pm
... ...
@@ -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';
+42 -31
lib/DBIx/Custom/Model.pm
... ...
@@ -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
+10 -14
lib/DBIx/Custom/Where.pm
... ...
@@ -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
+11 -7
t/common.t
... ...
@@ -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]});
+3 -3
t/mysql.t
... ...
@@ -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
+34
t/sqlite.t
... ...
@@ -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;