Showing 7 changed files with 100 additions and 91 deletions
+2 -1
Changes
... ...
@@ -1,5 +1,6 @@
1 1
 0.1663
2
-    - added bind_param_option can set bind_param option
2
+    - added EXPERIMENTAL type() attribute to DBIx::Custom::Model
3
+    - added EXPERIMENTAL bind_param_option can set bind_param option
3 4
       to insert(), update(), delete(), select(), insert_at(),
4 5
       update_at(), delete_at(), select_at(), delete_all(), update_all()
5 6
 0.1662
+32 -7
lib/DBIx/Custom.pm
... ...
@@ -19,7 +19,7 @@ use DBIx::Custom::Tag;
19 19
 use DBIx::Custom::Util;
20 20
 use Encode qw/encode_utf8 decode_utf8/;
21 21
 
22
-our @COMMON_ARGS = qw/table query filter bind_param_option/;
22
+our @COMMON_ARGS = qw/table query filter type/;
23 23
 
24 24
 __PACKAGE__->attr(
25 25
     [qw/data_source password pid user/],
... ...
@@ -433,15 +433,23 @@ sub execute{
433 433
     }
434 434
     $filter = {%$filter, %$f};
435 435
     
436
+    # Type
437
+    my $type = DBIx::Custom::Util::array_to_hash($args{type});
438
+    
436 439
     # Bind
437
-    my $bind = $self->_bind($params, $query->columns, $filter);
440
+    my $bind = $self->_bind($params, $query->columns, $filter, $type);
438 441
     
439 442
     # Execute
440 443
     my $sth = $query->sth;
441 444
     my $affected;
442 445
     eval {
443 446
         for (my $i = 0; $i < @$bind; $i++) {
444
-            $sth->bind_param($i + 1, $bind->[$i]);
447
+            if (my $type = $bind->[$i]->{type}) {
448
+                $sth->bind_param($i + 1, $bind->[$i]->{value}, $type);
449
+            }
450
+            else {
451
+                $sth->bind_param($i + 1, $bind->[$i]->{value});
452
+            }
445 453
         }
446 454
         $affected = $sth->execute;
447 455
     };
... ...
@@ -678,6 +686,8 @@ sub include_model {
678 686
         $table_alias = {%$table_alias, %{$model->table_alias}};
679 687
         
680 688
         # Table - Model
689
+        croak "Table name is duplicated"
690
+          if exists $self->{_model_from}->{$model->table};
681 691
         $self->{_model_from}->{$model->table} = $model->name;
682 692
     }
683 693
     
... ...
@@ -1163,10 +1173,10 @@ sub where {
1163 1173
 }
1164 1174
 
1165 1175
 sub _bind {
1166
-    my ($self, $params, $columns, $filter) = @_;
1176
+    my ($self, $params, $columns, $filter, $type) = @_;
1167 1177
     
1168 1178
     # bind values
1169
-    my @bind;
1179
+    my $bind = [];
1170 1180
     
1171 1181
     # Build bind values
1172 1182
     my $count = {};
... ...
@@ -1196,13 +1206,17 @@ sub _bind {
1196 1206
         # Filter
1197 1207
         my $f = $filter->{$column} || $self->{default_out_filter} || '';
1198 1208
         
1199
-        push @bind, $f ? $f->($value) : $value;
1209
+        # Type
1210
+        push @$bind, {
1211
+            value => $f ? $f->($value) : $value,
1212
+            type => $type->{$column}
1213
+        };
1200 1214
         
1201 1215
         # Count up 
1202 1216
         $count->{$column}++;
1203 1217
     }
1204 1218
     
1205
-    return \@bind;
1219
+    return $bind;
1206 1220
 }
1207 1221
 
1208 1222
 sub _connect {
... ...
@@ -2403,6 +2417,17 @@ You can check SQL.
2403 2417
 
2404 2418
     my $sql = $query->sql;
2405 2419
 
2420
+=item C<type> EXPERIMENTAL
2421
+
2422
+Specify database data type.
2423
+
2424
+    $dbi->select(type => [image => DBI::SQL_BLOB]);
2425
+    $dbi->select(type => [[qw/image audio/] => DBI::SQL_BLOB]);
2426
+
2427
+This is used to bind paramter by C<bind_param()> of statment handle.
2428
+
2429
+    $sth->bind_param($pos, $value, DBI::SQL_BLOB);
2430
+
2406 2431
 =back
2407 2432
 
2408 2433
 =head2 C<select_at()> EXPERIMENTAL
+30 -76
lib/DBIx/Custom/Model.pm
... ...
@@ -16,6 +16,7 @@ __PACKAGE__->attr(
16 16
     columns => sub { [] },
17 17
     filter => sub { [] },
18 18
     join => sub { [] },
19
+    type => sub { [] },
19 20
     primary_key => sub { [] }
20 21
 );
21 22
 
... ...
@@ -39,6 +40,25 @@ sub AUTOLOAD {
39 40
     }
40 41
 }
41 42
 
43
+my @methods = qw/insert insert_at update update_at update_all
44
+                 delete delete_at delete_all select select_at/;
45
+foreach my $method (@methods) {
46
+
47
+    my $code = sub {
48
+        my $self = shift;
49
+        
50
+        my @args = (table => $self->table, type => $self->type);
51
+        push @args, (primary_key => $self->primary_key) if $method =~ /_at$/;
52
+        push @args, (join => $self->join) if $method =~ /^select/;
53
+        
54
+        $self->dbi->$method(@args, @_);
55
+    };
56
+    
57
+    no strict 'refs';
58
+    my $class = __PACKAGE__;
59
+    *{"${class}::$method"} = $code;
60
+}
61
+
42 62
 sub column {
43 63
     my ($self, $table, $columns) = @_;
44 64
     
... ...
@@ -56,43 +76,8 @@ sub column {
56 76
     return $self->dbi->column($table, $columns);
57 77
 }
58 78
 
59
-sub delete {
60
-    my $self = shift;
61
-    $self->dbi->delete(table => $self->table, @_);
62
-}
63
-
64
-sub delete_all {
65
-    my $self = shift;
66
-    $self->dbi->delete_all(table => $self->table, @_);
67
-}
68
-
69
-sub delete_at {
70
-    my $self = shift;
71
-    
72
-    return $self->dbi->delete_at(
73
-        table => $self->table,
74
-        primary_key => $self->primary_key,
75
-        @_
76
-    );
77
-}
78
-
79 79
 sub DESTROY { }
80 80
 
81
-sub insert {
82
-    my $self = shift;
83
-    $self->dbi->insert(table => $self->table, @_);
84
-}
85
-
86
-sub insert_at {
87
-    my $self = shift;
88
-    
89
-    return $self->dbi->insert_at(
90
-        table => $self->table,
91
-        primary_key => $self->primary_key,
92
-        @_
93
-    );
94
-}
95
-
96 81
 sub mycolumn {
97 82
     my $self = shift;
98 83
     my $table = shift unless ref $_[0];
... ...
@@ -104,46 +89,6 @@ sub mycolumn {
104 89
     return $self->dbi->mycolumn($table, $columns);
105 90
 }
106 91
 
107
-sub select {
108
-    my $self = shift;
109
-    $self->dbi->select(
110
-        table => $self->table,
111
-        join => $self->join,
112
-        @_
113
-    );
114
-}
115
-
116
-sub select_at {
117
-    my $self = shift;
118
-    
119
-    return $self->dbi->select_at(
120
-        table => $self->table,
121
-        primary_key => $self->primary_key,
122
-        join => $self->join,
123
-        @_
124
-    );
125
-}
126
-
127
-sub update {
128
-    my $self = shift;
129
-    $self->dbi->update(table => $self->table, @_)
130
-}
131
-
132
-sub update_all {
133
-    my $self = shift;
134
-    $self->dbi->update_all(table => $self->table, @_);
135
-}
136
-
137
-sub update_at {
138
-    my $self = shift;
139
-    
140
-    return $self->dbi->update_at(
141
-        table => $self->table,
142
-        primary_key => $self->primary_key,
143
-        @_
144
-    );
145
-}
146
-
147 92
 1;
148 93
 
149 94
 =head1 NAME
... ...
@@ -204,6 +149,15 @@ Generally, this is automatically set from class name.
204 149
 Foreign key, this is used as C<primary_key> of C<insert_at>,C<update_at()>,
205 150
 C<delete_at()>,C<select_at()>.
206 151
 
152
+=head2 C<type>
153
+
154
+    my $type = $model->type;
155
+    $model   = $model->type(['image' => DBI::SQL_BLOB]);
156
+    
157
+Database data type, this is used as type optioon of C<insert()>, C<insert_at()>,
158
+C<update()>, C<update_at()>, C<update_all>, C<delete()>, C<delete_all()>,
159
+C<select(), C<select_at()>
160
+
207 161
 =head2 C<view>
208 162
 
209 163
     my $view = $model->view;
... ...
@@ -265,7 +219,7 @@ you don't have to specify C<table> option.
265 219
 Same as C<insert_at()> of L<DBIx::Custom> except that
266 220
 you don't have to specify C<table> and C<primary_key> option.
267 221
 
268
-=head2 C<mycolumn> EXPERIMENTAL
222
+=head2 C<mycolumn>
269 223
 
270 224
     my $column = $self->mycolumn;
271 225
     my $column = $self->mycolumn(book => ['author', 'title']);
+32 -3
t/dbix-custom-core-sqlite.t
... ...
@@ -1403,11 +1403,13 @@ is_deeply($model->list->fetch_hash_all, [{name => 'a'}], 'basic');
1403 1403
 }
1404 1404
 $dbi = MyDBI5->connect($NEW_ARGS->{0});
1405 1405
 $dbi->execute("create table company (name)");
1406
+$dbi->execute("create table table1 (key1)");
1406 1407
 $model = $dbi->model('company');
1407 1408
 $model->insert({name => 'a'});
1408 1409
 is_deeply($model->list->fetch_hash_all, [{name => 'a'}], 'include all model');
1410
+$dbi->insert(table => 'table1', param => {key1 => 1});
1409 1411
 $model = $dbi->model('book');
1410
-is_deeply($model->list->fetch_hash_all, [{name => 'a'}], 'include all model');
1412
+is_deeply($model->list->fetch_hash_all, [{key1 => 1}], 'include all model');
1411 1413
 
1412 1414
 test 'primary_key';
1413 1415
 use MyDBI1;
... ...
@@ -1602,13 +1604,15 @@ test 'model delete_at';
1602 1604
 }
1603 1605
 $dbi = MyDBI6->connect($NEW_ARGS->{0});
1604 1606
 $dbi->execute($CREATE_TABLE->{1});
1607
+$dbi->execute("create table table2 (key1, key2, key3)");
1608
+$dbi->execute("create table table3 (key1, key2, key3)");
1605 1609
 $dbi->insert(table => 'table1', param => {key1 => 1, key2 => 2, key3 => 3});
1606 1610
 $dbi->model('table1')->delete_at(where => [1, 2]);
1607 1611
 is_deeply($dbi->select(table => 'table1')->fetch_hash_all, []);
1608
-$dbi->insert(table => 'table1', param => {key1 => 1, key2 => 2, key3 => 3});
1612
+$dbi->insert(table => 'table2', param => {key1 => 1, key2 => 2, key3 => 3});
1609 1613
 $dbi->model('table1_1')->delete_at(where => [1, 2]);
1610 1614
 is_deeply($dbi->select(table => 'table1')->fetch_hash_all, []);
1611
-$dbi->insert(table => 'table1', param => {key1 => 1, key2 => 2, key3 => 3});
1615
+$dbi->insert(table => 'table3', param => {key1 => 1, key2 => 2, key3 => 3});
1612 1616
 $dbi->model('table1_3')->delete_at(where => [1, 2]);
1613 1617
 is_deeply($dbi->select(table => 'table1')->fetch_hash_all, []);
1614 1618
 
... ...
@@ -1873,3 +1877,28 @@ $result = $model->select(
1873 1877
 is_deeply($result->fetch_hash_first, 
1874 1878
           {table2_alias__key1 => 1, table2_alias__key3 => 48});
1875 1879
 
1880
+test 'type() option';
1881
+$dbi = DBIx::Custom->connect(
1882
+    data_source => 'dbi:SQLite:dbname=:memory:',
1883
+    dbi_option => {
1884
+        $DBD::SQLite::VERSION > 1.26 ? (sqlite_unicode => 1) : (unicode => 1)
1885
+    }
1886
+);
1887
+my $binary = pack("I3", 1, 2, 3);
1888
+$dbi->execute('create table table1(key1, key2)');
1889
+$dbi->insert(table => 'table1', param => {key1 => $binary, key2 => 'あ'}, type => [key1 => DBI::SQL_BLOB]);
1890
+$result = $dbi->select(table => 'table1');
1891
+$row   = $result->fetch_hash_first;
1892
+is_deeply($row, {key1 => $binary, key2 => 'あ'}, "basic");
1893
+$result = $dbi->execute('select length(key1) as key1_length from table1');
1894
+$row = $result->fetch_hash_first;
1895
+is($row->{key1_length}, length $binary);
1896
+
1897
+$dbi->insert(table => 'table1', param => {key1 => $binary, key2 => 'あ'}, type => [['key1'] => DBI::SQL_BLOB]);
1898
+$result = $dbi->select(table => 'table1');
1899
+$row   = $result->fetch_hash_first;
1900
+is_deeply($row, {key1 => $binary, key2 => 'あ'}, "basic");
1901
+$result = $dbi->execute('select length(key1) as key1_length from table1');
1902
+$row = $result->fetch_hash_first;
1903
+is($row->{key1_length}, length $binary);
1904
+
+1 -1
t/dbix-custom-core-sqlite/MyModel4/book.pm
... ...
@@ -2,7 +2,7 @@ package MyModel4::book;
2 2
 
3 3
 use base 'MyModel4';
4 4
 
5
-sub table { 'company' }
5
+sub table { 'table1' }
6 6
 
7 7
 sub list { shift->select }
8 8
 
+1 -1
t/dbix-custom-core-sqlite/MyModel5/table1_1.pm
... ...
@@ -5,7 +5,7 @@ use warnings;
5 5
 
6 6
 use base 'MyModel5';
7 7
 
8
-__PACKAGE__->attr(table => 'table1');
8
+__PACKAGE__->attr(table => 'table2');
9 9
 
10 10
 __PACKAGE__->attr('primary_key' => sub { ['key1', 'key2'] });
11 11
 
+2 -2
t/dbix-custom-core-sqlite/MyModel5/table1_2.pm
... ...
@@ -6,8 +6,8 @@ use warnings;
6 6
 use base 'MyModel5';
7 7
 
8 8
 __PACKAGE__->attr(name => 'table1_3');
9
-__PACKAGE__->attr(table => 'table1');
9
+__PACKAGE__->attr(table => 'table3');
10 10
 
11 11
 __PACKAGE__->attr('primary_key' => sub { ['key1', 'key2'] });
12 12
 
13
-1;
13
+1;