... | ... |
@@ -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 |
); |