| ... | ... |
@@ -1,4 +1,7 @@ |
| 1 | 1 |
0.1655 |
| 2 |
+ - added experimental DBIx::Custom::Model join attribute |
|
| 3 |
+ - added experimental select() join option |
|
| 4 |
+ - deprecated select() relation option |
|
| 2 | 5 |
- added experimental update_param and insert_param |
| 3 | 6 |
- remove experimental DBIx::Custom::Model relation |
| 4 | 7 |
0.1654 |
| ... | ... |
@@ -613,7 +613,19 @@ sub register_filter {
|
| 613 | 613 |
sub register_tag { shift->query_builder->register_tag(@_) }
|
| 614 | 614 |
|
| 615 | 615 |
our %VALID_SELECT_ARGS |
| 616 |
- = map { $_ => 1 } qw/table column where append relation filter query selection left_join/;
|
|
| 616 |
+ = map { $_ => 1 } qw/table column where append relation filter query selection join/;
|
|
| 617 |
+ |
|
| 618 |
+sub _need_tables {
|
|
| 619 |
+ my ($self, $tree, $need_tables, $tables) = @_; |
|
| 620 |
+ |
|
| 621 |
+ foreach my $table (@$tables) {
|
|
| 622 |
+ |
|
| 623 |
+ if ($tree->{$table}) {
|
|
| 624 |
+ $need_tables->{$table} = 1;
|
|
| 625 |
+ $self->_need_tables($tree, $need_tables, [$tree->{$table}{parent}])
|
|
| 626 |
+ } |
|
| 627 |
+ } |
|
| 628 |
+} |
|
| 617 | 629 |
|
| 618 | 630 |
sub select {
|
| 619 | 631 |
my ($self, %args) = @_; |
| ... | ... |
@@ -635,9 +647,9 @@ sub select {
|
| 635 | 647 |
my $where = $args{where} || {};
|
| 636 | 648 |
my $append = $args{append};
|
| 637 | 649 |
my $filter = $args{filter};
|
| 638 |
- my $left_join = $args{left_join} || [];
|
|
| 639 |
- croak qq{"left_join" must be array reference}
|
|
| 640 |
- unless ref $left_join eq 'ARRAY'; |
|
| 650 |
+ my $join = $args{join} || [];
|
|
| 651 |
+ croak qq{"join" must be array reference}
|
|
| 652 |
+ unless ref $join eq 'ARRAY'; |
|
| 641 | 653 |
|
| 642 | 654 |
my @join_tables; |
| 643 | 655 |
unshift @join_tables, $tables->[-1]; |
| ... | ... |
@@ -697,27 +709,39 @@ sub select {
|
| 697 | 709 |
# Table name in Where |
| 698 | 710 |
unshift @join_tables, @{$self->_tables($swhere)};
|
| 699 | 711 |
|
| 700 |
- # Left join |
|
| 701 |
- if (@$left_join) {
|
|
| 702 |
- for (my $i = 0; $i < @$left_join; $i += 2) {
|
|
| 703 |
- my $column1 = $left_join->[$i]; |
|
| 704 |
- my $column2 = $left_join->[$i + 1]; |
|
| 705 |
- |
|
| 706 |
- my $table1 = (split (/\./, $column1))[0]; |
|
| 707 |
- my $table2 = (split (/\./, $column2))[0]; |
|
| 712 |
+ # Join |
|
| 713 |
+ if (@$join) {
|
|
| 714 |
+ my $tree = {};
|
|
| 715 |
+ |
|
| 716 |
+ for (my $i = 0; $i < @$join; $i++) {
|
|
| 708 | 717 |
|
| 709 |
- my $table1_exists; |
|
| 710 |
- my $table2_exists; |
|
| 718 |
+ my $join_clause = $join->[$i]; |
|
| 711 | 719 |
|
| 712 |
- foreach my $table (@join_tables) {
|
|
| 713 |
- $table1_exists = 1 if $table eq $table1; |
|
| 714 |
- $table2_exists = 1 if $table eq $table2; |
|
| 720 |
+ if ($join_clause =~ /\s([^\.\s]+?)\..+\s([^\.\s]+?)\./) {
|
|
| 721 |
+ |
|
| 722 |
+ my $table1 = $1; |
|
| 723 |
+ my $table2 = $2; |
|
| 724 |
+ |
|
| 725 |
+ croak qq{right side table of "$join_clause" must be uniq}
|
|
| 726 |
+ if exists $tree->{$table2};
|
|
| 727 |
+ |
|
| 728 |
+ $tree->{$table2}
|
|
| 729 |
+ = {position => $i, parent => $table1, join => $join_clause};
|
|
| 715 | 730 |
} |
| 716 |
- |
|
| 717 |
- if ($table1_exists && $table2_exists) {
|
|
| 718 |
- push @sql, "left outer join $table2 on $column1 = $column2"; |
|
| 731 |
+ else {
|
|
| 732 |
+ croak qq{join "$join_clause" must be two table name};
|
|
| 719 | 733 |
} |
| 720 | 734 |
} |
| 735 |
+ |
|
| 736 |
+ my $need_tables = {};
|
|
| 737 |
+ $self->_need_tables($tree, $need_tables, \@join_tables); |
|
| 738 |
+ |
|
| 739 |
+ |
|
| 740 |
+ my @need_tables = sort { $tree->{$a}{position} <=> $tree->{$b}{position} } keys %$need_tables;
|
|
| 741 |
+ |
|
| 742 |
+ foreach my $need_table (@need_tables) {
|
|
| 743 |
+ push @sql, $tree->{$need_table}{join};
|
|
| 744 |
+ } |
|
| 721 | 745 |
} |
| 722 | 746 |
|
| 723 | 747 |
# Add where |
| ... | ... |
@@ -1748,7 +1772,7 @@ This is same as L<DBI>'s C<rollback>. |
| 1748 | 1772 |
where => \%where, |
| 1749 | 1773 |
append => $append, |
| 1750 | 1774 |
relation => \%relation, |
| 1751 |
- left_join => ['book.company_id' => 'company.id'] |
|
| 1775 |
+ join => ['left outer join company on book.company_id = company.id'] |
|
| 1752 | 1776 |
filter => \%filter, |
| 1753 | 1777 |
query => 1, |
| 1754 | 1778 |
selection => $selection |
| ... | ... |
@@ -1773,7 +1797,7 @@ First element is a string. it contains tags, |
| 1773 | 1797 |
such as "{= title} or {like author}".
|
| 1774 | 1798 |
Second element is paramters. |
| 1775 | 1799 |
|
| 1776 |
-C<left_join> is add left outer join clause after from clause. |
|
| 1800 |
+C<join> is join clause after from clause. |
|
| 1777 | 1801 |
This is experimental. |
| 1778 | 1802 |
|
| 1779 | 1803 |
=head3 C<(experimental) select_at()> |
| ... | ... |
@@ -15,6 +15,7 @@ __PACKAGE__->attr( |
| 15 | 15 |
columns => sub { [] },
|
| 16 | 16 |
filter => sub { [] },
|
| 17 | 17 |
primary_key => sub { [] },
|
| 18 |
+ join => sub { [] }
|
|
| 18 | 19 |
); |
| 19 | 20 |
|
| 20 | 21 |
our $AUTOLOAD; |
| ... | ... |
@@ -116,6 +117,7 @@ sub select {
|
| 116 | 117 |
my $self = shift; |
| 117 | 118 |
$self->dbi->select( |
| 118 | 119 |
table => $self->table, |
| 120 |
+ join => $self->join, |
|
| 119 | 121 |
@_ |
| 120 | 122 |
); |
| 121 | 123 |
} |
| ... | ... |
@@ -191,6 +193,15 @@ This filter is applied when L<DBIx::Custom> C<include_model()> is called. |
| 191 | 193 |
|
| 192 | 194 |
Model name. |
| 193 | 195 |
|
| 196 |
+=head2 C<(experimental) join> |
|
| 197 |
+ |
|
| 198 |
+ my $join = $model->join; |
|
| 199 |
+ $model = $model->join( |
|
| 200 |
+ ['left outer join company on book.company_id = company.id'] |
|
| 201 |
+ ); |
|
| 202 |
+ |
|
| 203 |
+Default join clause. This is used by C<select()>. |
|
| 204 |
+ |
|
| 194 | 205 |
=head2 C<table> |
| 195 | 206 |
|
| 196 | 207 |
my $table = $model->table; |
| ... | ... |
@@ -27,7 +27,8 @@ my $CREATE_TABLE = {
|
| 27 | 27 |
0 => 'create table table1 (key1 char(255), key2 char(255));', |
| 28 | 28 |
1 => 'create table table1 (key1 char(255), key2 char(255), key3 char(255), key4 char(255), key5 char(255));', |
| 29 | 29 |
2 => 'create table table2 (key1 char(255), key3 char(255));', |
| 30 |
- 3 => 'create table table1 (key1 Date, key2 datetime);' |
|
| 30 |
+ 3 => 'create table table1 (key1 Date, key2 datetime);', |
|
| 31 |
+ 4 => 'create table table3 (key3 int, key4 int);' |
|
| 31 | 32 |
}; |
| 32 | 33 |
|
| 33 | 34 |
my $SELECT_SOURCES = {
|
| ... | ... |
@@ -1681,7 +1682,7 @@ $result = $model->select(column => $model->column_clause, where => {'table1.key1
|
| 1681 | 1682 |
is_deeply($result->fetch_hash_first, {key1 => 1, key2 => 2});
|
| 1682 | 1683 |
$result = $model->select(column => $model->column_clause(remove => ['key1']), where => {'table1.key1' => 1});
|
| 1683 | 1684 |
is_deeply($result->fetch_hash_first, {key2 => 2});
|
| 1684 |
-$result = $model->select(relation => {'table1.key1' => 'table2.key1'}, column => $model->column_clause(add => ['key3']), where => {'table1.key1' => 1});
|
|
| 1685 |
+$result = $model->select(column => $model->column_clause(add => ['table2.key3']), where => {'table1.key1' => 1});
|
|
| 1685 | 1686 |
is_deeply($result->fetch_hash_first, {key1 => 1, key2 => 2, key3 => 3});
|
| 1686 | 1687 |
|
| 1687 | 1688 |
test 'update_param'; |
| ... | ... |
@@ -1724,27 +1725,62 @@ eval { $dbi->insert_param({";" => 1}) };
|
| 1724 | 1725 |
like($@, qr/not safety/); |
| 1725 | 1726 |
|
| 1726 | 1727 |
|
| 1727 |
-test 'left_join'; |
|
| 1728 |
+test 'join'; |
|
| 1728 | 1729 |
$dbi = DBIx::Custom->connect($NEW_ARGS->{0});
|
| 1729 | 1730 |
$dbi->execute($CREATE_TABLE->{0});
|
| 1730 | 1731 |
$dbi->insert(table => 'table1', param => {key1 => 1, key2 => 2});
|
| 1731 | 1732 |
$dbi->insert(table => 'table1', param => {key1 => 3, key2 => 4});
|
| 1732 | 1733 |
$dbi->execute($CREATE_TABLE->{2});
|
| 1733 | 1734 |
$dbi->insert(table => 'table2', param => {key1 => 1, key3 => 5});
|
| 1735 |
+$dbi->execute($CREATE_TABLE->{4});
|
|
| 1736 |
+$dbi->insert(table => 'table3', param => {key3 => 5, key4 => 4});
|
|
| 1734 | 1737 |
$rows = $dbi->select( |
| 1735 | 1738 |
table => 'table1', |
| 1736 | 1739 |
column => 'table1.key1 as table1_key1, table2.key1 as table2_key1, key2, key3', |
| 1737 | 1740 |
where => {'table1.key2' => 2},
|
| 1738 |
- left_join => ['table1.key1' => 'table2.key1'] |
|
| 1741 |
+ join => ['left outer join table2 on table1.key1 = table2.key1'] |
|
| 1739 | 1742 |
)->fetch_hash_all; |
| 1740 | 1743 |
is_deeply($rows, [{table1_key1 => 1, table2_key1 => 1, key2 => 2, key3 => 5}]);
|
| 1741 | 1744 |
|
| 1745 |
+$rows = $dbi->select( |
|
| 1746 |
+ table => 'table1', |
|
| 1747 |
+ where => {'key1' => 1},
|
|
| 1748 |
+ join => ['left outer join table2 on table1.key1 = table2.key1'] |
|
| 1749 |
+)->fetch_hash_all; |
|
| 1750 |
+is_deeply($rows, [{key1 => 1, key2 => 2}]);
|
|
| 1751 |
+ |
|
| 1742 | 1752 |
eval {
|
| 1743 | 1753 |
$rows = $dbi->select( |
| 1744 | 1754 |
table => 'table1', |
| 1745 | 1755 |
column => 'table1.key1 as table1_key1, table2.key1 as table2_key1, key2, key3', |
| 1746 | 1756 |
where => {'table1.key2' => 2},
|
| 1747 |
- left_join => {'table1.key1' => 'table2.key1'}
|
|
| 1757 |
+ join => {'table1.key1' => 'table2.key1'}
|
|
| 1748 | 1758 |
); |
| 1749 | 1759 |
}; |
| 1750 | 1760 |
like ($@, qr/array/); |
| 1761 |
+ |
|
| 1762 |
+$rows = $dbi->select( |
|
| 1763 |
+ table => 'table1', |
|
| 1764 |
+ where => {'key1' => 1},
|
|
| 1765 |
+ join => ['left outer join table2 on table1.key1 = table2.key1', |
|
| 1766 |
+ 'left outer join table3 on table2.key3 = table3.key3'] |
|
| 1767 |
+)->fetch_hash_all; |
|
| 1768 |
+is_deeply($rows, [{key1 => 1, key2 => 2}]);
|
|
| 1769 |
+ |
|
| 1770 |
+$rows = $dbi->select( |
|
| 1771 |
+ column => 'table3.key4 as table3__key4', |
|
| 1772 |
+ table => 'table1', |
|
| 1773 |
+ where => {'table1.key1' => 1},
|
|
| 1774 |
+ join => ['left outer join table2 on table1.key1 = table2.key1', |
|
| 1775 |
+ 'left outer join table3 on table2.key3 = table3.key3'] |
|
| 1776 |
+)->fetch_hash_all; |
|
| 1777 |
+is_deeply($rows, [{table3__key4 => 4}]);
|
|
| 1778 |
+ |
|
| 1779 |
+$rows = $dbi->select( |
|
| 1780 |
+ column => 'table1.key1 as table1__key1', |
|
| 1781 |
+ table => 'table1', |
|
| 1782 |
+ where => {'table3.key4' => 4},
|
|
| 1783 |
+ join => ['left outer join table2 on table1.key1 = table2.key1', |
|
| 1784 |
+ 'left outer join table3 on table2.key3 = table3.key3'] |
|
| 1785 |
+)->fetch_hash_all; |
|
| 1786 |
+is_deeply($rows, [{table1__key1 => 1}]);
|
| ... | ... |
@@ -3,10 +3,10 @@ package MyModel6::table1; |
| 3 | 3 |
use base 'MyModel6'; |
| 4 | 4 |
|
| 5 | 5 |
__PACKAGE__->attr( |
| 6 |
- relation => sub {
|
|
| 7 |
- {
|
|
| 8 |
- 'table1.key1' => 'table2.key1' |
|
| 9 |
- } |
|
| 6 |
+ join => sub {
|
|
| 7 |
+ [ |
|
| 8 |
+ 'left outer join table2 on table1.key1 = table2.key1' |
|
| 9 |
+ ] |
|
| 10 | 10 |
}, |
| 11 | 11 |
primary_key => sub { ['key1'] }
|
| 12 | 12 |
); |