| ... | ... |
@@ -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 |
| ... | ... |
@@ -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 |
|
| ... | ... |
@@ -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 シュガーメソッドを使わない |
| ... | ... |
@@ -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 |
} |
| ... | ... |
@@ -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 |
+ |