Showing 5 changed files with 239 additions and 45 deletions
+2
Changes
... ...
@@ -1,3 +1,5 @@
1
+0.1639
2
+  added experimental not_exists()
1 3
 0.1638
2 4
   table object call dbi object method if not found method.
3 5
   added experimental base_table attribute and removed experimental table_class attribute
+63 -39
lib/DBIx/Custom.pm
... ...
@@ -333,13 +333,13 @@ sub execute{
333 333
     }
334 334
     $filter = {%$filter, %$f};
335 335
     
336
-    # Create bind values
337
-    my $binds = $self->_build_binds($params, $query->columns, $filter);
336
+    # Bind
337
+    my $bind = $self->_bind($params, $query->columns, $filter);
338 338
     
339 339
     # Execute
340
-    my $sth      = $query->sth;
340
+    my $sth = $query->sth;
341 341
     my $affected;
342
-    eval {$affected = $sth->execute(@$binds)};
342
+    eval {$affected = $sth->execute(@$bind)};
343 343
     $self->_croak($@, qq{. Following SQL is executed. "$query->{sql}"}) if $@;
344 344
     
345 345
     # Return resultset if select statement is executed
... ...
@@ -470,6 +470,8 @@ sub new {
470 470
     return $self;
471 471
 }
472 472
 
473
+sub not_exists { bless {}, 'DBIx::Custom::NotExists' }
474
+
473 475
 sub register_filter {
474 476
     my $invocant = shift;
475 477
     
... ...
@@ -695,31 +697,47 @@ sub where {
695 697
     return DBIx::Custom::Where->new(query_builder => shift->query_builder)
696 698
 }
697 699
 
698
-sub _build_binds {
700
+sub _bind {
699 701
     my ($self, $params, $columns, $filter) = @_;
700 702
     
701 703
     # bind values
702
-    my @binds;
704
+    my @bind;
703 705
     
704 706
     # Build bind values
705 707
     my $count = {};
708
+    my $not_exists = {};
706 709
     foreach my $column (@$columns) {
707 710
         
708 711
         # Value
709
-        my $value = ref $params->{$column} eq 'ARRAY'
710
-                  ? $params->{$column}->[$count->{$column} || 0]
711
-                  : $params->{$column};
712
+        my $value;
713
+        if(ref $params->{$column} eq 'ARRAY') {
714
+            my $i = $count->{$column} || 0;
715
+            $i += $not_exists->{$column} || 0;
716
+            my $found;
717
+            for (my $k = $i; $i < @{$params->{$column}}; $k++) {
718
+                if (ref $params->{$column}->[$k] eq 'DBIx::Custom::NotExists') {
719
+                    $not_exists->{$column}++;
720
+                }
721
+                else  {
722
+                    $value = $params->{$column}->[$k];
723
+                    $found = 1;
724
+                    last
725
+                }
726
+            }
727
+            next unless $found;
728
+        }
729
+        else { $value = $params->{$column} }
712 730
         
713 731
         # Filter
714 732
         my $f = $filter->{$column} || $self->{default_out_filter} || '';
715 733
         
716
-        push @binds, $f ? $f->($value) : $value;
734
+        push @bind, $f ? $f->($value) : $value;
717 735
         
718 736
         # Count up 
719 737
         $count->{$column}++;
720 738
     }
721 739
     
722
-    return \@binds;
740
+    return \@bind;
723 741
 }
724 742
 
725 743
 sub _croak {
... ...
@@ -1094,24 +1112,6 @@ Arguments is same as C<delete> method,
1094 1112
 except that C<delete_all> don't have C<where> argument.
1095 1113
 Return value of C<delete_all()> is the count of affected rows.
1096 1114
 
1097
-=head2 C<(experimental) method>
1098
-
1099
-    $dbi->method(
1100
-        update_or_insert => sub {
1101
-            my $self = shift;
1102
-            # do something
1103
-        },
1104
-        find_or_create   => sub {
1105
-            my $self = shift;
1106
-            # do something
1107
-        }
1108
-    );
1109
-
1110
-Register method. These method is called from L<DBIx::Custom> object directory.
1111
-
1112
-    $dbi->update_or_insert;
1113
-    $dbi->find_or_create;
1114
-
1115 1115
 =head2 C<insert>
1116 1116
 
1117 1117
     $dbi->insert(table  => $table, 
... ...
@@ -1132,18 +1132,11 @@ default to 0. This is experimental.
1132 1132
 This is overwrites C<default_bind_filter>.
1133 1133
 Return value of C<insert()> is the count of affected rows.
1134 1134
 
1135
-=head2 C<new>
1136
-
1137
-    my $dbi = DBIx::Custom->connect(data_source => "dbi:mysql:database=dbname",
1138
-                                    user => 'ken', password => '!LFKD%$&');
1139
-
1140
-Create a new L<DBIx::Custom> object.
1141
-
1142 1135
 =head2 C<(experimental) each_column>
1143 1136
 
1144 1137
     $dbi->each_column(
1145 1138
         sub {
1146
-            my ($table, $column, $info) = @_;
1139
+            my ($self, $table, $column, $info) = @_;
1147 1140
             
1148 1141
             my $type = $info->{TYPE_NAME};
1149 1142
             
... ...
@@ -1155,8 +1148,39 @@ Create a new L<DBIx::Custom> object.
1155 1148
 Get column informations from database.
1156 1149
 Argument is callback.
1157 1150
 You can do anything in callback.
1158
-Callback receive three arguments, table name, column name and column
1159
-information.
1151
+Callback receive four arguments, dbi object, table name,
1152
+column name and columninformation.
1153
+
1154
+=head2 C<(experimental) method>
1155
+
1156
+    $dbi->method(
1157
+        update_or_insert => sub {
1158
+            my $self = shift;
1159
+            # do something
1160
+        },
1161
+        find_or_create   => sub {
1162
+            my $self = shift;
1163
+            # do something
1164
+        }
1165
+    );
1166
+
1167
+Register method. These method is called from L<DBIx::Custom> object directory.
1168
+
1169
+    $dbi->update_or_insert;
1170
+    $dbi->find_or_create;
1171
+
1172
+=head2 C<new>
1173
+
1174
+    my $dbi = DBIx::Custom->connect(data_source => "dbi:mysql:database=dbname",
1175
+                                    user => 'ken', password => '!LFKD%$&');
1176
+
1177
+Create a new L<DBIx::Custom> object.
1178
+
1179
+=head2 C<(experimental) not_exists>
1180
+
1181
+    my $not_exists = $dbi->not_exists;
1182
+
1183
+Get DBIx::Custom::NotExists object.
1160 1184
 
1161 1185
 =head2 C<register_filter>
1162 1186
 
+88
lib/DBIx/Custom/Guide/Ja.pod
... ...
@@ -878,8 +878,96 @@ C<=>タグの場合は
878 878
     
879 879
 を返す必要があるということです。
880 880
 
881
+タグの実装の他のサンプルはL<DBIx::Custom::Tag>のソースコード
882
+をご覧になってみてください。
883
+
881 884
 =head2 6. Where句の動的な生成
882 885
 
886
+=head3 Where句の動的な生成 where()
887
+
888
+複数の検索条件を指定して、検索を行いたい場合があります。
889
+次の3つのケースのwhere句を考えてみましょう。
890
+下記のようなwhere句が必要になります。
891
+
892
+titleの値だけで検索したい場合
893
+
894
+    where {= title}
895
+
896
+authorの値だけで検索したい場合
897
+
898
+    where {= author}
899
+
900
+titleとauthorの両方の値で検索したい場合
901
+
902
+    where {= title} and {=author}
903
+
904
+L<DBIx::Custom>では動的なWhere句の生成をサポートしています。
905
+まずC<where()>でL<DBIx::Custom::Where>オブジェクトを生成します。
906
+
907
+    my $where = $dbi->where;
908
+
909
+次にC<clause()>を使用してwhere句を記述します。
910
+
911
+    $where->clause(
912
+        ['and', '{= title'}, '{= author}']
913
+    );
914
+
915
+clauseの指定方法は次のようになります。
916
+
917
+    ['or' あるいは 'and', タグ1, タグ2, タグ3]
918
+
919
+第一引数にはorあるいはandを指定します。第二引数以降には
920
+検索条件をタグを使って記述します。
921
+
922
+C<clause>の指定は入れ子にすることもでき、さらに複雑な条件
923
+を記述することもできます。
924
+
925
+    ['and', 
926
+      '{= title}', 
927
+      ['or', '{= author}', '{like date}']
928
+    ]
929
+
930
+このようにC<clause>を設定した後にC<param>にパラメータを指定します。
931
+    
932
+    my $param => {title => 'Perl'};
933
+    $where->param($param);
934
+
935
+この例ではtitleだけがパラメータに含まれています。
936
+
937
+この後C<to_string()>を実行すると$paramに含まれるパラメータを満たす
938
+where句を生成することができます。
939
+
940
+    my $where_clause = $where->to_string;
941
+
942
+パラメータはtitleだけですので、次のようなwhere句が生成されます。
943
+
944
+    where {= title}
945
+
946
+またD<DBIx::Custom>は文字列の評価をオーバーロードして、C<to_string()>
947
+を呼び出すようにしていますので、次のようにしてwhere句を生成することも
948
+できます。
949
+
950
+    my $where_clause = "$where";
951
+
952
+これはSQLの中にwhere句を埋め込むときにとても役立つ機能です。
953
+
954
+また同一の列名を持つ場合はパラメータを配列のリファレンスにしてください。
955
+
956
+[undef, undef]
957
+
958
+[sub {'not exists'}, 1]
959
+ 
960
+
961
+
962
+
963
+
964
+=head3 select()との連携
965
+
966
+
967
+
968
+=head3 execute()との連携
969
+
970
+
883 971
 =head2 7. パフォーマンスの改善
884 972
 
885 973
 =head3 シュガーメソッドを使わない
+8 -5
lib/DBIx/Custom/Where.pm
... ...
@@ -72,7 +72,7 @@ sub _parse {
72 72
         
73 73
         # Column
74 74
         my $columns = $self->query_builder->build_query($clause)->columns;
75
-        croak qq{each tag contains one column name: tag "$clause"}
75
+        croak qq{Each tag contains one column name: tag "$clause"}
76 76
           unless @$columns == 1;
77 77
         my $column = $columns->[0];
78 78
         
... ...
@@ -82,21 +82,24 @@ sub _parse {
82 82
         # Push
83 83
         my $param = $self->param;
84 84
         my $pushed;
85
-        if (defined $param) {
85
+        if (ref $param eq 'HASH') {
86 86
             if (exists $param->{$column}) {
87 87
                 if (ref $param->{$column} eq 'ARRAY') {
88
-                    $pushed = 1 if exists $param->{$column}->[$count - 1];
89
-                }
88
+                    $pushed = 1
89
+                      if  exists $param->{$column}->[$count - 1]
90
+                       && ref $param->{$column}->[$count - 1] ne 'DBIx::Custom::NotExists';
91
+                } 
90 92
                 elsif ($count == 1) {
91 93
                     $pushed = 1;
92 94
                 }
93 95
             }
94 96
             push @$where, $clause if $pushed;
95 97
         }
96
-        else {
98
+        elsif (!defined $param) {
97 99
             push @$where, $clause;
98 100
             $pushed = 1;
99 101
         }
102
+        else { croak "Parameter must be hash reference or undfined value" }
100 103
         
101 104
         return $pushed;
102 105
     }
+78 -1
t/dbix-custom-core-sqlite.t
... ...
@@ -886,7 +886,7 @@ $where = $dbi->where
886 886
 $result = $dbi->select(
887 887
     table => 'table1',
888 888
     where => $where,
889
-);
889
+); 
890 890
 $row = $result->fetch_hash_all;
891 891
 is_deeply($row, [{key1 => 1, key2 => 2}]);
892 892
 
... ...
@@ -957,6 +957,82 @@ $where = $dbi->where
957 957
 eval{$where->to_string};
958 958
 like($@, qr/one column/);
959 959
 
960
+$where = $dbi->where
961
+             ->clause('{= key1}')
962
+             ->param([]);
963
+eval{$where->to_string};
964
+like($@, qr/Parameter/);
965
+
966
+$where = $dbi->where
967
+             ->clause(['or', ('{= key1}') x 3])
968
+             ->param({key1 => [$dbi->not_exists, 1, 3]});
969
+$result = $dbi->select(
970
+    table => 'table1',
971
+    where => $where,
972
+);
973
+$row = $result->fetch_hash_all;
974
+is_deeply($row, [{key1 => 1, key2 => 2}, {key1 => 3, key2 => 4}], 'not_exists');
975
+
976
+$where = $dbi->where
977
+             ->clause(['or', ('{= key1}') x 3])
978
+             ->param({key1 => [1, $dbi->not_exists, 3]});
979
+$result = $dbi->select(
980
+    table => 'table1',
981
+    where => $where,
982
+);
983
+$row = $result->fetch_hash_all;
984
+is_deeply($row, [{key1 => 1, key2 => 2}, {key1 => 3, key2 => 4}], 'not_exists');
985
+
986
+$where = $dbi->where
987
+             ->clause(['or', ('{= key1}') x 3])
988
+             ->param({key1 => [1, 3, $dbi->not_exists]});
989
+$result = $dbi->select(
990
+    table => 'table1',
991
+    where => $where,
992
+);
993
+$row = $result->fetch_hash_all;
994
+is_deeply($row, [{key1 => 1, key2 => 2}, {key1 => 3, key2 => 4}], 'not_exists');
995
+
996
+$where = $dbi->where
997
+             ->clause(['or', ('{= key1}') x 3])
998
+             ->param({key1 => [1, $dbi->not_exists, $dbi->not_exists]});
999
+$result = $dbi->select(
1000
+    table => 'table1',
1001
+    where => $where,
1002
+);
1003
+$row = $result->fetch_hash_all;
1004
+is_deeply($row, [{key1 => 1, key2 => 2}], 'not_exists');
1005
+
1006
+$where = $dbi->where
1007
+             ->clause(['or', ('{= key1}') x 3])
1008
+             ->param({key1 => [$dbi->not_exists, 1, $dbi->not_exists]});
1009
+$result = $dbi->select(
1010
+    table => 'table1',
1011
+    where => $where,
1012
+);
1013
+$row = $result->fetch_hash_all;
1014
+is_deeply($row, [{key1 => 1, key2 => 2}], 'not_exists');
1015
+
1016
+$where = $dbi->where
1017
+             ->clause(['or', ('{= key1}') x 3])
1018
+             ->param({key1 => [$dbi->not_exists, $dbi->not_exists, 1]});
1019
+$result = $dbi->select(
1020
+    table => 'table1',
1021
+    where => $where,
1022
+);
1023
+$row = $result->fetch_hash_all;
1024
+is_deeply($row, [{key1 => 1, key2 => 2}], 'not_exists');
1025
+
1026
+$where = $dbi->where
1027
+             ->clause(['or', ('{= key1}') x 3])
1028
+             ->param({key1 => [$dbi->not_exists, $dbi->not_exists, $dbi->not_exists]});
1029
+$result = $dbi->select(
1030
+    table => 'table1',
1031
+    where => $where,
1032
+);
1033
+$row = $result->fetch_hash_all;
1034
+is_deeply($row, [{key1 => 1, key2 => 2}, {key1 => 3, key2 => 4}], 'not_exists');
1035
+
960 1036
 test 'dbi_option default';
961 1037
 $dbi = DBIx::Custom->new;
962 1038
 is_deeply($dbi->dbi_option, {});
... ...
@@ -1113,3 +1189,4 @@ $dbi->method(
1113 1189
 );
1114 1190
 is($dbi->base_table->one, 1, 'use dbi method');
1115 1191
 is($dbi->table('table1')->one, 1, 'use dbi method');
1192
+