[Bast-commits] r6219 - in DBIx-Class/0.08/trunk: . lib/DBIx/Class
lib/DBIx/Class/Manual lib/DBIx/Class/Storage
lib/DBIx/Class/Storage/DBI lib/DBIx/Class/Storage/DBI/Oracle
t t/count t/resultset t/search
ribasushi at dev.catalyst.perl.org
ribasushi at dev.catalyst.perl.org
Tue May 12 05:02:56 GMT 2009
Author: ribasushi
Date: 2009-05-12 05:02:56 +0000 (Tue, 12 May 2009)
New Revision: 6219
Added:
DBIx-Class/0.08/trunk/t/count/count_distinct.t
DBIx-Class/0.08/trunk/t/count/count_joined.t
DBIx-Class/0.08/trunk/t/from_subquery.t
Removed:
DBIx-Class/0.08/trunk/lib/DBIx/Class/Storage/DBI/MultiDistinctEmulation.pm
Modified:
DBIx-Class/0.08/trunk/
DBIx-Class/0.08/trunk/lib/DBIx/Class/Manual/Cookbook.pod
DBIx-Class/0.08/trunk/lib/DBIx/Class/ResultSet.pm
DBIx-Class/0.08/trunk/lib/DBIx/Class/Storage/DBI.pm
DBIx-Class/0.08/trunk/lib/DBIx/Class/Storage/DBI/Oracle/Generic.pm
DBIx-Class/0.08/trunk/lib/DBIx/Class/Storage/DBI/SQLite.pm
DBIx-Class/0.08/trunk/t/03podcoverage.t
DBIx-Class/0.08/trunk/t/47bind_attribute.t
DBIx-Class/0.08/trunk/t/60core.t
DBIx-Class/0.08/trunk/t/73oracle.t
DBIx-Class/0.08/trunk/t/resultset/as_query.t
DBIx-Class/0.08/trunk/t/search/subquery.t
Log:
r5757 at Thesaurus (orig r5756): arcanez | 2009-03-14 14:55:55 +0100
created count_distinct branch
r5758 at Thesaurus (orig r5757): arcanez | 2009-03-14 15:33:03 +0100
* change count with group_by (distinct) to use a subquery
* rewrite of _bind_to_sql (uses placeholders and bindvars)
* tests for count distinct
* fixed tests for from subquery
r5760 at Thesaurus (orig r5759): arcanez | 2009-03-16 16:48:28 +0100
don't remove the where clause unless we're doing distinct, it needs to be there
r5850 at Thesaurus (orig r5849): arcanez | 2009-03-30 21:40:05 +0200
* add more tests
* remove old cruft
* remove old note
r6035 at Thesaurus (orig r6034): ribasushi | 2009-04-30 09:10:36 +0200
Add joined count test
r6079 at Thesaurus (orig r6078): arcanez | 2009-05-01 08:41:34 +0200
cleanup/fix some broken tests
r6097 at Thesaurus (orig r6096): arcanez | 2009-05-01 19:37:04 +0200
make sure merge bind
test for aformentioned
TODO count_joined test for a little while
r6105 at Thesaurus (orig r6104): arcanez | 2009-05-02 02:33:49 +0200
remove hackish ways
r6106 at Thesaurus (orig r6105): arcanez | 2009-05-02 03:20:04 +0200
more fixes to tests
r6107 at Thesaurus (orig r6106): arcanez | 2009-05-02 03:33:47 +0200
remove DBIx::Class::Storage::DBI::MultiDistinctEmulation
r6111 at Thesaurus (orig r6110): ribasushi | 2009-05-03 02:00:19 +0200
Failing test without immediate fixes go to branches, not to trunk
r6114 at Thesaurus (orig r6113): ribasushi | 2009-05-03 10:23:28 +0200
Bump SQLA ependencies so parenthesis_significant is guaranteed to be there
r6148 at Thesaurus (orig r6147): ribasushi | 2009-05-06 17:40:31 +0200
Add subquery/from test by michaelr (copied from subquery branch r5742)
r6151 at Thesaurus (orig r6150): ribasushi | 2009-05-06 17:56:07 +0200
TODOify sqla-dependent tests
r6152 at Thesaurus (orig r6151): arcanez | 2009-05-06 18:33:58 +0200
fix old test using new bind vars (no more interpolating)
r6154 at Thesaurus (orig r6153): ribasushi | 2009-05-07 00:56:40 +0200
Rename internal function to clarify what it does
r6171 at Thesaurus (orig r6170): ribasushi | 2009-05-07 19:53:30 +0200
Adjust tests for the IN fixes
r6187 at Thesaurus (orig r6186): ribasushi | 2009-05-08 23:11:43 +0200
Final count tests
r6188 at Thesaurus (orig r6187): arcanez | 2009-05-09 03:50:12 +0200
rewrite DISTINCT/COUNT(DISTINCT) Cookbook entries
r6213 at Thesaurus (orig r6212): arcanez | 2009-05-11 22:41:21 +0200
warn/die based on { select => { distinct => { } } }
r6214 at Thesaurus (orig r6213): arcanez | 2009-05-11 23:21:11 +0200
use carp instead of warn
r6216 at Thesaurus (orig r6215): arcanez | 2009-05-11 23:45:05 +0200
make sure we get just a string
r6217 at Thesaurus (orig r6216): arcanez | 2009-05-11 23:52:11 +0200
oops
Property changes on: DBIx-Class/0.08/trunk
___________________________________________________________________
Name: svn:mergeinfo
-
Name: svk:merge
- 168d5346-440b-0410-b799-f706be625ff1:/DBIx-Class-current:2207
462d4d0c-b505-0410-bf8e-ce8f877b3390:/local/bast/DBIx-Class:3159
4d5fae46-8e6a-4e08-abee-817e9fb894a2:/local/bast/DBIx-Class/0.08/branches/resultsetcolumn_custom_columns:5160
4d5fae46-8e6a-4e08-abee-817e9fb894a2:/local/bast/DBIx-Class/0.08/branches/sqla_1.50_compat:5414
4d5fae46-8e6a-4e08-abee-817e9fb894a2:/local/bast/DBIx-Class/0.08/trunk:5969
9c88509d-e914-0410-b01c-b9530614cbfe:/local/DBIx-Class:32260
9c88509d-e914-0410-b01c-b9530614cbfe:/local/DBIx-Class-CDBICompat:54993
9c88509d-e914-0410-b01c-b9530614cbfe:/vendor/DBIx-Class:31122
ab17426e-7cd3-4704-a2a2-80b7c0a611bb:/local/dbic_column_attr:10946
ab17426e-7cd3-4704-a2a2-80b7c0a611bb:/local/dbic_trunk:11142
bd5ac9a7-f185-4d95-9186-dbb8b392a572:/local/os/bast/DBIx-Class/0.08/trunk:2798
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/belongs_to_null_col_fix:5244
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/cdbicompat_integration:4160
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/column_attr:5074
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/complex_join_rels:4589
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/file_column:3920
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/fix-update-and-delete-as_query:6162
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/multi_stuff:5565
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/on_disconnect_do:3694
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/oracle_sequence:4173
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/parser_fk_index:4485
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/prefetch:5699
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/replication_dedux:4600
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/rt_bug_41083:5437
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/savepoints:4223
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/sqla_1.50_compat:5321
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/storage-ms-access:4142
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/subclassed_rsset:5930
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/subquery:5617
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/sybase:5651
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/sybase_mssql:6125
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/versioned_enhancements:4125
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/versioning:4578
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/views:5585
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class-C3:318
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class-current:2222
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class-joins:173
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class-resultset:570
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/datetime:1716
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/find_compat:1855
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/find_unique_query_fixes:2142
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/inflate:1988
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/many_to_many:2025
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/re_refactor_bugfix:1944
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/reorganize_tests:1827
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/resultset-new-refactor:1766
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/resultset_2_electric_boogaloo:2175
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/resultset_cleanup:2102
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/sqlt_tests_refactor:2043
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/trunk/DBIx-Class:3606
fe160bb6-dc1c-0410-9f2b-d64a711b54a5:/local/DBIC-trunk-0.08:10510
+ 168d5346-440b-0410-b799-f706be625ff1:/DBIx-Class-current:2207
462d4d0c-b505-0410-bf8e-ce8f877b3390:/local/bast/DBIx-Class:3159
4d5fae46-8e6a-4e08-abee-817e9fb894a2:/local/bast/DBIx-Class/0.08/branches/resultsetcolumn_custom_columns:5160
4d5fae46-8e6a-4e08-abee-817e9fb894a2:/local/bast/DBIx-Class/0.08/branches/sqla_1.50_compat:5414
4d5fae46-8e6a-4e08-abee-817e9fb894a2:/local/bast/DBIx-Class/0.08/trunk:5969
9c88509d-e914-0410-b01c-b9530614cbfe:/local/DBIx-Class:32260
9c88509d-e914-0410-b01c-b9530614cbfe:/local/DBIx-Class-CDBICompat:54993
9c88509d-e914-0410-b01c-b9530614cbfe:/vendor/DBIx-Class:31122
ab17426e-7cd3-4704-a2a2-80b7c0a611bb:/local/dbic_column_attr:10946
ab17426e-7cd3-4704-a2a2-80b7c0a611bb:/local/dbic_trunk:11142
bd5ac9a7-f185-4d95-9186-dbb8b392a572:/local/os/bast/DBIx-Class/0.08/trunk:2798
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/belongs_to_null_col_fix:5244
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/cdbicompat_integration:4160
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/column_attr:5074
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/complex_join_rels:4589
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/count_distinct:6218
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/file_column:3920
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/fix-update-and-delete-as_query:6162
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/multi_stuff:5565
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/on_disconnect_do:3694
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/oracle_sequence:4173
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/parser_fk_index:4485
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/prefetch:5699
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/replication_dedux:4600
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/rt_bug_41083:5437
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/savepoints:4223
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/sqla_1.50_compat:5321
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/storage-ms-access:4142
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/subclassed_rsset:5930
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/subquery:5617
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/sybase:5651
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/sybase_mssql:6125
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/versioned_enhancements:4125
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/versioning:4578
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/views:5585
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class-C3:318
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class-current:2222
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class-joins:173
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class-resultset:570
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/datetime:1716
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/find_compat:1855
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/find_unique_query_fixes:2142
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/inflate:1988
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/many_to_many:2025
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/re_refactor_bugfix:1944
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/reorganize_tests:1827
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/resultset-new-refactor:1766
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/resultset_2_electric_boogaloo:2175
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/resultset_cleanup:2102
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/sqlt_tests_refactor:2043
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/trunk/DBIx-Class:3606
fe160bb6-dc1c-0410-9f2b-d64a711b54a5:/local/DBIC-trunk-0.08:10510
Modified: DBIx-Class/0.08/trunk/lib/DBIx/Class/Manual/Cookbook.pod
===================================================================
--- DBIx-Class/0.08/trunk/lib/DBIx/Class/Manual/Cookbook.pod 2009-05-12 05:02:33 UTC (rev 6218)
+++ DBIx-Class/0.08/trunk/lib/DBIx/Class/Manual/Cookbook.pod 2009-05-12 05:02:56 UTC (rev 6219)
@@ -237,30 +237,50 @@
=head2 SELECT DISTINCT with multiple columns
- my $rs = $schema->resultset('Foo')->search(
+ my $rs = $schema->resultset('Artist')->search(
{},
{
- select => [
- { distinct => [ $source->columns ] }
- ],
- as => [ $source->columns ] # remember 'as' is not the same as SQL AS :-)
+ columns => [ qw/artistid name rank/ ],
+ distinct => 1
+ }
+ );
+
+ my $rs = $schema->resultset('Artist')->search(
+ {},
+ {
+ columns => [ qw/artistid name rank/ ],
+ group_by => [ qw/artistid name rank/ ],
}
);
+ # Equivalent SQL:
+ # SELECT me.artistid, me.name, me.rank
+ # FROM artist me
+ # GROUP BY artistid, name, rank
+
=head2 SELECT COUNT(DISTINCT colname)
- my $rs = $schema->resultset('Foo')->search(
+ my $rs = $schema->resultset('Artist')->search(
{},
{
- select => [
- { count => { distinct => 'colname' } }
- ],
- as => [ 'count' ]
+ columns => [ qw/name/ ],
+ distinct => 1
}
);
- my $count = $rs->next->get_column('count');
+ my $rs = $schema->resultset('Artist')->search(
+ {},
+ {
+ columns => [ qw/name/ ],
+ group_by => [ qw/name/ ],
+ }
+ );
+ my $count = $rs->count;
+
+ # Equivalent SQL:
+ # SELECT COUNT( DISTINCT( me.name ) ) FROM artist me
+
=head2 Grouping results
L<DBIx::Class> supports C<GROUP BY> as follows:
Modified: DBIx-Class/0.08/trunk/lib/DBIx/Class/ResultSet.pm
===================================================================
--- DBIx-Class/0.08/trunk/lib/DBIx/Class/ResultSet.pm 2009-05-12 05:02:33 UTC (rev 6218)
+++ DBIx-Class/0.08/trunk/lib/DBIx/Class/ResultSet.pm 2009-05-12 05:02:56 UTC (rev 6219)
@@ -307,7 +307,7 @@
my $new_attrs = { %{$our_attrs}, %{$attrs} };
# merge new attrs into inherited
- foreach my $key (qw/join prefetch +select +as/) {
+ foreach my $key (qw/join prefetch +select +as bind/) {
next unless exists $attrs->{$key};
$new_attrs->{$key} = $self->_merge_attr($our_attrs->{$key}, $attrs->{$key});
}
@@ -1148,12 +1148,6 @@
with to find the number of elements. If passed arguments, does a search
on the resultset and counts the results of that.
-Note: When using C<count> with C<group_by>, L<DBIx::Class> emulates C<GROUP BY>
-using C<COUNT( DISTINCT( columns ) )>. Some databases (notably SQLite) do
-not support C<DISTINCT> with multiple columns. If you are using such a
-database, you should only use columns from the main table in your C<group_by>
-clause.
-
=cut
sub count {
@@ -1174,32 +1168,21 @@
sub _count { # Separated out so pager can get the full count
my $self = shift;
- my $select = { count => '*' };
-
my $attrs = { %{$self->_resolved_attrs} };
- if (my $group_by = delete $attrs->{group_by}) {
- delete $attrs->{having};
- my @distinct = (ref $group_by ? @$group_by : ($group_by));
- # todo: try CONCAT for multi-column pk
- my @pk = $self->result_source->primary_columns;
- if (@pk == 1) {
- my $alias = $attrs->{alias};
- foreach my $column (@distinct) {
- if ($column =~ qr/^(?:\Q${alias}.\E)?$pk[0]$/) {
- @distinct = ($column);
- last;
- }
- }
- }
- $select = { count => { distinct => \@distinct } };
+ if (my $group_by = $attrs->{group_by}) {
+ delete $attrs->{order_by};
+
+ $attrs->{select} = $group_by;
+ $attrs->{from} = [ { 'mesub' => (ref $self)->new($self->result_source, $attrs)->cursor->as_query } ];
+ delete $attrs->{where};
}
- $attrs->{select} = $select;
+ $attrs->{select} = { count => '*' };
$attrs->{as} = [qw/count/];
- # offset, order by and page are not needed to count. record_filter is cdbi
- delete $attrs->{$_} for qw/rows offset order_by page pager record_filter/;
+ # offset, order by, group by, where and page are not needed to count. record_filter is cdbi
+ delete $attrs->{$_} for qw/rows offset order_by group_by page pager record_filter/;
my $tmp_rs = (ref $self)->new($self->result_source, $attrs);
my ($count) = $tmp_rs->cursor->next;
Deleted: DBIx-Class/0.08/trunk/lib/DBIx/Class/Storage/DBI/MultiDistinctEmulation.pm
===================================================================
--- DBIx-Class/0.08/trunk/lib/DBIx/Class/Storage/DBI/MultiDistinctEmulation.pm 2009-05-12 05:02:33 UTC (rev 6218)
+++ DBIx-Class/0.08/trunk/lib/DBIx/Class/Storage/DBI/MultiDistinctEmulation.pm 2009-05-12 05:02:56 UTC (rev 6219)
@@ -1,51 +0,0 @@
-package DBIx::Class::Storage::DBI::MultiDistinctEmulation;
-
-use strict;
-use warnings;
-
-use base qw/DBIx::Class::Storage::DBI/;
-
-sub _select {
- my ($self, $ident, $select, $condition, $attrs) = @_;
-
- # hack to make count distincts with multiple columns work in SQLite and Oracle
- if (ref $select eq 'ARRAY') {
- @{$select} = map {$self->replace_distincts($_)} @{$select};
- } else {
- $select = $self->replace_distincts($select);
- }
-
- return $self->next::method($ident, $select, $condition, $attrs);
-}
-
-sub replace_distincts {
- my ($self, $select) = @_;
-
- $select->{count}->{distinct} = join("||", @{$select->{count}->{distinct}})
- if (ref $select eq 'HASH' && $select->{count} && ref $select->{count} eq 'HASH' &&
- $select->{count}->{distinct} && ref $select->{count}->{distinct} eq 'ARRAY');
-
- return $select;
-}
-
-1;
-
-=head1 NAME
-
-DBIx::Class::Storage::DBI::MultiDistinctEmulation - Some databases can't handle count distincts with multiple cols. They should use base on this.
-
-=head1 SYNOPSIS
-
-=head1 DESCRIPTION
-
-This class allows count distincts with multiple columns for retarded databases (Oracle and SQLite)
-
-=head1 AUTHORS
-
-Luke Saunders <luke.saunders at gmail.com>
-
-=head1 LICENSE
-
-You may distribute this code under the same terms as Perl itself.
-
-=cut
Modified: DBIx-Class/0.08/trunk/lib/DBIx/Class/Storage/DBI/Oracle/Generic.pm
===================================================================
--- DBIx-Class/0.08/trunk/lib/DBIx/Class/Storage/DBI/Oracle/Generic.pm 2009-05-12 05:02:33 UTC (rev 6218)
+++ DBIx-Class/0.08/trunk/lib/DBIx/Class/Storage/DBI/Oracle/Generic.pm 2009-05-12 05:02:56 UTC (rev 6219)
@@ -26,7 +26,7 @@
use Carp::Clan qw/^DBIx::Class/;
-use base qw/DBIx::Class::Storage::DBI::MultiDistinctEmulation/;
+use base qw/DBIx::Class::Storage::DBI/;
# __PACKAGE__->load_components(qw/PK::Auto/);
Modified: DBIx-Class/0.08/trunk/lib/DBIx/Class/Storage/DBI/SQLite.pm
===================================================================
--- DBIx-Class/0.08/trunk/lib/DBIx/Class/Storage/DBI/SQLite.pm 2009-05-12 05:02:33 UTC (rev 6218)
+++ DBIx-Class/0.08/trunk/lib/DBIx/Class/Storage/DBI/SQLite.pm 2009-05-12 05:02:56 UTC (rev 6219)
@@ -6,7 +6,7 @@
use File::Copy;
use File::Spec;
-use base qw/DBIx::Class::Storage::DBI::MultiDistinctEmulation/;
+use base qw/DBIx::Class::Storage::DBI/;
sub _dbh_last_insert_id {
my ($self, $dbh, $source, $col) = @_;
Modified: DBIx-Class/0.08/trunk/lib/DBIx/Class/Storage/DBI.pm
===================================================================
--- DBIx-Class/0.08/trunk/lib/DBIx/Class/Storage/DBI.pm 2009-05-12 05:02:33 UTC (rev 6218)
+++ DBIx-Class/0.08/trunk/lib/DBIx/Class/Storage/DBI.pm 2009-05-12 05:02:56 UTC (rev 6219)
@@ -37,6 +37,7 @@
DBIC::SQL::Abstract; # Would merge upstream, but nate doesn't reply :(
use base qw/SQL::Abstract::Limit/;
+use Carp::Clan qw/^DBIx::Class/;
sub new {
my $self = shift->SUPER::new(@_);
@@ -147,6 +148,9 @@
sub select {
my ($self, $table, $fields, $where, $order, @rest) = @_;
+ local $self->{having_bind} = [];
+ local $self->{from_bind} = [];
+
if (ref $table eq 'SCALAR') {
$table = $$table;
}
@@ -158,8 +162,7 @@
@rest = (-1) unless defined $rest[0];
die "LIMIT 0 Does Not Compute" if $rest[0] == 0;
# and anyway, SQL::Abstract::Limit will cause a barf if we don't first
- local $self->{having_bind} = [];
- my ($sql, @ret) = $self->SUPER::select(
+ my ($sql, @where_bind) = $self->SUPER::select(
$table, $self->_recurse_fields($fields), $where, $order, @rest
);
$sql .=
@@ -171,7 +174,7 @@
) :
''
;
- return wantarray ? ($sql, @ret, @{$self->{having_bind}}) : $sql;
+ return wantarray ? ($sql, @{$self->{from_bind}}, @where_bind, @{$self->{having_bind}}) : $sql;
}
sub insert {
@@ -219,13 +222,30 @@
} @$fields);
} elsif ($ref eq 'HASH') {
foreach my $func (keys %$fields) {
+ if ($func eq 'distinct') {
+ my $_fields = $fields->{$func};
+ if (ref $_fields eq 'ARRAY' && @{$_fields} > 1) {
+ die "Unsupported syntax, please use " .
+ "{ group_by => [ qw/" . (join ' ', @$_fields) . "/ ] }" .
+ " or " .
+ "{ select => [ qw/" . (join ' ', @$_fields) . "/ ], distinct => 1 }";
+ }
+ else {
+ $_fields = @{$_fields}[0] if ref $_fields eq 'ARRAY';
+ carp "This syntax will be deprecated in 09, please use " .
+ "{ group_by => '${_fields}' }" .
+ " or " .
+ "{ select => '${_fields}', distinct => 1 }";
+ }
+ }
+
return $self->_sqlcase($func)
.'( '.$self->_recurse_fields($fields->{$func}).' )';
}
}
# Is the second check absolutely necessary?
elsif ( $ref eq 'REF' and ref($$fields) eq 'ARRAY' ) {
- return $self->_bind_to_sql( $fields );
+ return $self->_fold_sqlbind( $fields );
}
else {
Carp::croak($ref . qq{ unexpected in _recurse_fields()})
@@ -318,19 +338,18 @@
return join('', @sqlf);
}
-sub _bind_to_sql {
- my $self = shift;
- my $arr = shift;
- my $sql = shift @$$arr;
- $sql =~ s/\?/$self->_quote((shift @$$arr)->[1])/eg;
- return $sql
+sub _fold_sqlbind {
+ my ($self, $sqlbind) = @_;
+ my $sql = shift @$$sqlbind;
+ push @{$self->{from_bind}}, @$$sqlbind;
+ return $sql;
}
sub _make_as {
my ($self, $from) = @_;
- return join(' ', map { (ref $_ eq 'SCALAR' ? $$_
- : ref $_ eq 'REF' ? $self->_bind_to_sql($_)
- : $self->_quote($_))
+ return join(' ', map { (ref $_ eq 'SCALAR' ? $$_
+ : ref $_ eq 'REF' ? $self->_fold_sqlbind($_)
+ : $self->_quote($_))
} reverse each %{$self->_skip_options($from)});
}
Modified: DBIx-Class/0.08/trunk/t/03podcoverage.t
===================================================================
--- DBIx-Class/0.08/trunk/t/03podcoverage.t 2009-05-12 05:02:33 UTC (rev 6218)
+++ DBIx-Class/0.08/trunk/t/03podcoverage.t 2009-05-12 05:02:56 UTC (rev 6219)
@@ -99,7 +99,6 @@
'DBIx::Class::Storage::DBI' => { skip => 1 },
'DBIx::Class::Storage::DBI::DB2' => { skip => 1 },
'DBIx::Class::Storage::DBI::MSSQL' => { skip => 1 },
- 'DBIx::Class::Storage::DBI::MultiDistinctEmulation' => { skip => 1 },
'DBIx::Class::Storage::DBI::ODBC400' => { skip => 1 },
'DBIx::Class::Storage::DBI::ODBC::DB2_400_SQL' => { skip => 1 },
'DBIx::Class::Storage::DBI::Oracle' => { skip => 1 },
Modified: DBIx-Class/0.08/trunk/t/47bind_attribute.t
===================================================================
--- DBIx-Class/0.08/trunk/t/47bind_attribute.t 2009-05-12 05:02:33 UTC (rev 6218)
+++ DBIx-Class/0.08/trunk/t/47bind_attribute.t 2009-05-12 05:02:56 UTC (rev 6219)
@@ -3,19 +3,19 @@
use Test::More;
use lib qw(t/lib);
-use DBICTest;
+use DBIC::SqlMakerTest;
+use_ok('DBICTest');
+
my $schema = DBICTest->init_schema;
BEGIN {
eval "use DBD::SQLite";
plan $@
? ( skip_all => 'needs DBD::SQLite for testing' )
- : ( tests => 7 );
+ : ( tests => 9 );
}
-### $schema->storage->debug(1);
-
my $where_bind = {
where => \'name like ?',
bind => [ 'Cat%' ],
@@ -55,10 +55,10 @@
$new_source->source_name('Complex');
$new_source->name(\<<'');
-( select a.*, cd.cdid as cdid, cd.title as title, cd.year as year
- from artist a
- join cd on cd.artist=a.artistid
- where cd.year=?)
+( SELECT a.*, cd.cdid AS cdid, cd.title AS title, cd.year AS year
+ FROM artist a
+ JOIN cd ON cd.artist = a.artistid
+ WHERE cd.year = ?)
$schema->register_extra_source('Complex' => $new_source);
@@ -72,11 +72,22 @@
->search({ 'artistid' => 1 });
is ( $rs->count, 1, '...cookbook (bind first) + chained search' );
+{
+ $rs = $schema->resultset('Complex')->search({}, { bind => [ 1999 ] })->search({}, { where => \"title LIKE ?", bind => [ 'Spoon%' ] });
+ my ($sql, @bind) = @${$rs->as_query};
+ is_same_sql_bind(
+ $sql, \@bind,
+ "(SELECT me.artistid, me.name, me.rank, me.charfield FROM (SELECT a.*, cd.cdid AS cdid, cd.title AS title, cd.year AS year FROM artist a JOIN cd ON cd.artist = a.artistid WHERE cd.year = ?) WHERE title LIKE ?)",
+ [
+ [ '!!dummy' => '1999' ],
+ [ '!!dummy' => 'Spoon%' ]
+ ],
+ 'got correct SQL'
+);
+
+}
+
TODO: {
- # not sure what causes an uninit warning here, please remove when the TODO starts to pass,
- # so the real reason for the warning can be found and fixed
- local $SIG{__WARN__} = sub { warn @_ unless $_[0] =~ /uninitialized/ };
-
local $TODO = 'bind args order needs fixing (semifor)';
$rs = $schema->resultset('Complex')->search({}, { bind => [ 1999 ] })
->search({ 'artistid' => 1 }, {
Modified: DBIx-Class/0.08/trunk/t/60core.t
===================================================================
--- DBIx-Class/0.08/trunk/t/60core.t 2009-05-12 05:02:33 UTC (rev 6218)
+++ DBIx-Class/0.08/trunk/t/60core.t 2009-05-12 05:02:56 UTC (rev 6219)
@@ -8,7 +8,7 @@
my $schema = DBICTest->init_schema();
-plan tests => 95;
+plan tests => 96;
eval { require DateTime::Format::MySQL };
my $NO_DTFM = $@ ? 1 : 0;
@@ -28,7 +28,7 @@
my @art = $schema->resultset("Artist")->search({ }, { order_by => 'name DESC'});
-cmp_ok(@art, '==', 3, "Three artists returned");
+is(@art, 3, "Three artists returned");
my $art = $art[0];
@@ -39,7 +39,7 @@
is($art->name, 'We Are In Rehab', "Accessor update ok");
my %dirty = $art->get_dirty_columns();
-cmp_ok(scalar(keys(%dirty)), '==', 1, '1 dirty column');
+is(scalar(keys(%dirty)), 1, '1 dirty column');
ok(grep($_ eq 'name', keys(%dirty)), 'name is dirty');
is($art->get_column("name"), 'We Are In Rehab', 'And via get_column');
@@ -47,7 +47,7 @@
ok($art->update, 'Update run');
my %not_dirty = $art->get_dirty_columns();
-cmp_ok(scalar(keys(%not_dirty)), '==', 0, 'Nothing is dirty');
+is(scalar(keys(%not_dirty)), 0, 'Nothing is dirty');
eval {
my $ret = $art->make_column_dirty('name2');
@@ -55,7 +55,7 @@
ok(defined($@), 'Failed to make non-existent column dirty');
$art->make_column_dirty('name');
my %fake_dirty = $art->get_dirty_columns();
-cmp_ok(scalar(keys(%fake_dirty)), '==', 1, '1 fake dirty column');
+is(scalar(keys(%fake_dirty)), 1, '1 fake dirty column');
ok(grep($_ eq 'name', keys(%fake_dirty)), 'name is fake dirty');
my $record_jp = $schema->resultset("Artist")->search(undef, { join => 'cds' })->search(undef, { prefetch => 'cds' })->next;
@@ -68,15 +68,15 @@
@art = $schema->resultset("Artist")->search({ name => 'We Are In Rehab' });
-cmp_ok(@art, '==', 1, "Changed artist returned by search");
+is(@art, 1, "Changed artist returned by search");
-cmp_ok($art[0]->artistid, '==', 3,'Correct artist too');
+is($art[0]->artistid, 3,'Correct artist too');
lives_ok (sub { $art->delete }, 'Cascading delete on Ordered has_many works' ); # real test in ordered.t
@art = $schema->resultset("Artist")->search({ });
-cmp_ok(@art, '==', 2, 'And then there were two');
+is(@art, 2, 'And then there were two');
ok(!$art->in_storage, "It knows it's dead");
@@ -90,15 +90,15 @@
@art = $schema->resultset("Artist")->search({ });
-cmp_ok(@art, '==', 3, 'And now there are three again');
+is(@art, 3, 'And now there are three again');
my $new = $schema->resultset("Artist")->create({ artistid => 4 });
-cmp_ok($new->artistid, '==', 4, 'Create produced record ok');
+is($new->artistid, 4, 'Create produced record ok');
@art = $schema->resultset("Artist")->search({ });
-cmp_ok(@art, '==', 4, "Oh my god! There's four of them!");
+is(@art, 4, "Oh my god! There's four of them!");
$new->set_column('name' => 'Man With A Fork');
@@ -152,7 +152,7 @@
my $cd = $schema->resultset("CD")->find(1);
my %cols = $cd->get_columns;
-cmp_ok(keys %cols, '==', 6, 'get_columns number of columns ok');
+is(keys %cols, 6, 'get_columns number of columns ok');
is($cols{title}, 'Spoonful of bees', 'get_columns values ok');
@@ -235,31 +235,40 @@
my( $or_rs ) = $schema->resultset("CD")->search_rs($search, { join => 'tags',
order_by => 'cdid' });
-cmp_ok($or_rs->count, '==', 5, 'Search with OR ok');
+is($or_rs->count, 5, 'Search with OR ok');
my $distinct_rs = $schema->resultset("CD")->search($search, { join => 'tags', distinct => 1 });
-cmp_ok($distinct_rs->all, '==', 4, 'DISTINCT search with OR ok');
+is($distinct_rs->all, 4, 'DISTINCT search with OR ok');
SKIP: {
skip "SQLite < 3.2.6 doesn't understand COUNT(DISTINCT())", 2
if $is_broken_sqlite;
- my $tcount = $schema->resultset("Track")->search(
+ my $tcount = $schema->resultset('Track')->search(
{},
- {
- select => {count => {distinct => ['position', 'title']}},
- as => ['count']
+ {
+ select => [ qw/position title/ ],
+ distinct => 1,
}
);
- cmp_ok($tcount->next->get_column('count'), '==', 13, 'multiple column COUNT DISTINCT ok');
+ is($tcount->count, 13, 'multiple column COUNT DISTINCT ok');
- $tcount = $schema->resultset("Track")->search(
+ $tcount = $schema->resultset('Track')->search(
{},
- {
- columns => {count => {count => {distinct => ['position', 'title']}}},
+ {
+ columns => [ qw/position title/ ],
+ distinct => 1,
}
);
- cmp_ok($tcount->next->get_column('count'), '==', 13, 'multiple column COUNT DISTINCT using column syntax ok');
+ is($tcount->count, 13, 'multiple column COUNT DISTINCT ok');
+
+ $tcount = $schema->resultset('Track')->search(
+ {},
+ {
+ group_by => [ qw/position title/ ]
+ }
+ );
+ is($tcount->count, 13, 'multiple column COUNT DISTINCT using column syntax ok');
}
my $tag_rs = $schema->resultset('Tag')->search(
@@ -267,17 +276,17 @@
my $rel_rs = $tag_rs->search_related('cd');
-cmp_ok($rel_rs->count, '==', 5, 'Related search ok');
+is($rel_rs->count, 5, 'Related search ok');
-cmp_ok($or_rs->next->cdid, '==', $rel_rs->next->cdid, 'Related object ok');
+is($or_rs->next->cdid, $rel_rs->next->cdid, 'Related object ok');
$or_rs->reset;
$rel_rs->reset;
my $tag = $schema->resultset('Tag')->search(
[ { 'me.tag' => 'Blue' } ], { cols=>[qw/tagid/] } )->next;
-cmp_ok($tag->has_column_loaded('tagid'), '==', 1, 'Has tagid loaded');
-cmp_ok($tag->has_column_loaded('tag'), '==', 0, 'Has not tag loaded');
+ok($tag->has_column_loaded('tagid'), 'Has tagid loaded');
+ok(!$tag->has_column_loaded('tag'), 'Has not tag loaded');
ok($schema->storage(), 'Storage available');
@@ -309,7 +318,7 @@
ok($schema->source('SourceNameArtists'), 'SourceNameArtists result source exists');
my @artsn = $schema->resultset('SourceNameArtists')->search({}, { order_by => 'name DESC' });
- cmp_ok(@artsn, '==', 4, "Four artists returned");
+ is(@artsn, 4, "Four artists returned");
# make sure subclasses that don't set source_name are ok
ok($schema->source('ArtistSubclass'), 'ArtistSubclass exists');
@@ -323,8 +332,8 @@
{
my $art_del = $schema->resultset("Artist")->find({ artistid => 1 });
lives_ok (sub { $art_del->delete }, 'Cascading delete on Ordered has_many works' ); # real test in ordered.t
- cmp_ok( $schema->resultset("CD")->search({artist => 1}), '==', 0, 'Cascading through has_many top level.');
- cmp_ok( $schema->resultset("CD_to_Producer")->search({cd => 1}), '==', 0, 'Cascading through has_many children.');
+ is( $schema->resultset("CD")->search({artist => 1}), 0, 'Cascading through has_many top level.');
+ is( $schema->resultset("CD_to_Producer")->search({cd => 1}), 0, 'Cascading through has_many children.');
}
# test column_info
Modified: DBIx-Class/0.08/trunk/t/73oracle.t
===================================================================
--- DBIx-Class/0.08/trunk/t/73oracle.t 2009-05-12 05:02:33 UTC (rev 6218)
+++ DBIx-Class/0.08/trunk/t/73oracle.t 2009-05-12 05:02:56 UTC (rev 6219)
@@ -39,7 +39,7 @@
' as well as following sequences: \'pkid1_seq\', \'pkid2_seq\' and \'nonpkid_seq\''
unless ($dsn && $user && $pass);
-plan tests => 24;
+plan tests => 26;
DBICTest::Schema->load_classes('ArtistFQN');
my $schema = DBICTest::Schema->connect($dsn, $user, $pass);
@@ -106,16 +106,33 @@
# check count distinct with multiple columns
my $other_track = $schema->resultset('Track')->create({ trackid => 2, cd => 1, position => 1, title => 'Track2' });
+
my $tcount = $schema->resultset('Track')->search(
- {},
- {
- select => [{count => {distinct => ['position', 'title']}}],
- as => ['count']
- }
- );
+ {},
+ {
+ select => [ qw/position title/ ],
+ distinct => 1,
+ }
+);
+is($tcount->count, 2, 'multiple column COUNT DISTINCT ok');
-is($tcount->next->get_column('count'), 2, "multiple column select distinct ok");
+$tcount = $schema->resultset('Track')->search(
+ {},
+ {
+ columns => [ qw/position title/ ],
+ distinct => 1,
+ }
+);
+is($tcount->count, 2, 'multiple column COUNT DISTINCT ok');
+$tcount = $schema->resultset('Track')->search(
+ {},
+ {
+ group_by => [ qw/position title/ ]
+ }
+);
+is($tcount->count, 2, 'multiple column COUNT DISTINCT using column syntax ok');
+
# test LIMIT support
for (1..6) {
$schema->resultset('Artist')->create({ name => 'Artist ' . $_ });
Added: DBIx-Class/0.08/trunk/t/count/count_distinct.t
===================================================================
--- DBIx-Class/0.08/trunk/t/count/count_distinct.t (rev 0)
+++ DBIx-Class/0.08/trunk/t/count/count_distinct.t 2009-05-12 05:02:56 UTC (rev 6219)
@@ -0,0 +1,82 @@
+use strict;
+use warnings;
+
+use Test::More;
+use Test::Exception;
+
+use lib qw(t/lib);
+
+use DBICTest;
+use DBIC::SqlMakerTest;
+
+my $schema = DBICTest->init_schema();
+
+eval "use DBD::SQLite";
+plan skip_all => 'needs DBD::SQLite for testing' if $@;
+plan tests => 18;
+
+# The tag Blue is assigned to cds 1 2 3 and 5
+# The tag Cheesy is assigned to cds 2 4 and 5
+#
+# This combination should make some interesting group_by's
+#
+my $rs;
+my $in_rs = $schema->resultset('Tag')->search({ tag => [ 'Blue', 'Cheesy' ] });
+
+$rs = $schema->resultset('Tag')->search({ tag => 'Blue' });
+is($rs->count, 4, 'Count without DISTINCT');
+
+$rs = $schema->resultset('Tag')->search({ tag => [ 'Blue', 'Cheesy' ] }, { group_by => 'tag' });
+is($rs->count, 2, 'Count with single column group_by');
+
+$rs = $schema->resultset('Tag')->search({ tag => [ 'Blue', 'Cheesy' ] }, { group_by => 'cd' });
+is($rs->count, 5, 'Count with another single column group_by');
+
+$rs = $schema->resultset('Tag')->search({ tag => 'Blue' }, { group_by => [ qw/tag cd/ ]});
+is($rs->count, 4, 'Count with multiple column group_by');
+
+$rs = $schema->resultset('Tag')->search({ tag => 'Blue' }, { distinct => 1 });
+is($rs->count, 4, 'Count with single column distinct');
+
+$rs = $schema->resultset('Tag')->search({ tag => { -in => $in_rs->get_column('tag')->as_query } });
+is($rs->count, 7, 'Count with IN subquery');
+
+$rs = $schema->resultset('Tag')->search({ tag => { -in => $in_rs->get_column('tag')->as_query } }, { group_by => 'tag' });
+is($rs->count, 2, 'Count with IN subquery with outside group_by');
+
+$rs = $schema->resultset('Tag')->search({ tag => { -in => $in_rs->get_column('tag')->as_query } }, { distinct => 1 });
+is($rs->count, 7, 'Count with IN subquery with outside distinct');
+
+$rs = $schema->resultset('Tag')->search({ tag => { -in => $in_rs->get_column('tag')->as_query } }, { distinct => 1, select => 'tag' }),
+is($rs->count, 2, 'Count with IN subquery with outside distinct on a single column');
+
+$rs = $schema->resultset('Tag')->search({ tag => { -in => $in_rs->search({}, { group_by => 'tag' })->get_column('tag')->as_query } });
+is($rs->count, 7, 'Count with IN subquery with single group_by');
+
+$rs = $schema->resultset('Tag')->search({ tag => { -in => $in_rs->search({}, { group_by => 'cd' })->get_column('tag')->as_query } });
+is($rs->count, 7, 'Count with IN subquery with another single group_by');
+
+$rs = $schema->resultset('Tag')->search({ tag => { -in => $in_rs->search({}, { group_by => [ qw/tag cd/ ] })->get_column('tag')->as_query } });
+is($rs->count, 7, 'Count with IN subquery with multiple group_by');
+
+$rs = $schema->resultset('Tag')->search({ tag => \"= 'Blue'" });
+is($rs->count, 4, 'Count without DISTINCT, using literal SQL');
+
+$rs = $schema->resultset('Tag')->search({ tag => \" IN ('Blue', 'Cheesy')" }, { group_by => 'tag' });
+is($rs->count, 2, 'Count with literal SQL and single group_by');
+
+$rs = $schema->resultset('Tag')->search({ tag => \" IN ('Blue', 'Cheesy')" }, { group_by => 'cd' });
+is($rs->count, 5, 'Count with literal SQL and another single group_by');
+
+$rs = $schema->resultset('Tag')->search({ tag => \" IN ('Blue', 'Cheesy')" }, { group_by => [ qw/tag cd/ ] });
+is($rs->count, 7, 'Count with literal SQL and multiple group_by');
+
+my @warnings;
+{
+ local $SIG{__WARN__} = sub { push @warnings, shift };
+ my $row = $schema->resultset('Tag')->search({}, { select => { distinct => 'tag' } })->first;
+}
+
+is(@warnings, 1, 'expecteing warn');
+
+dies_ok(sub { my $row = $schema->resultset('Tag')->search({}, { select => { distinct => [qw/tag cd/] } })->first }, 'expecting to die');
Property changes on: DBIx-Class/0.08/trunk/t/count/count_distinct.t
___________________________________________________________________
Name: svn:mergeinfo
+
Added: DBIx-Class/0.08/trunk/t/count/count_joined.t
===================================================================
--- DBIx-Class/0.08/trunk/t/count/count_joined.t (rev 0)
+++ DBIx-Class/0.08/trunk/t/count/count_joined.t 2009-05-12 05:02:56 UTC (rev 6219)
@@ -0,0 +1,18 @@
+use strict;
+use warnings;
+
+use Test::More;
+
+use lib qw(t/lib);
+
+use DBICTest;
+
+plan tests => 1;
+
+my $schema = DBICTest->init_schema();
+
+TODO: {
+ local $TODO = 'Needs -paren fixes in SQLA before it can work';
+ my $cds = $schema->resultset("CD")->search({ cdid => 1 }, { join => { cd_to_producer => 'producer' } });
+ is($cds->count, 1, "extra joins do not explode single entity count");
+}
Added: DBIx-Class/0.08/trunk/t/from_subquery.t
===================================================================
--- DBIx-Class/0.08/trunk/t/from_subquery.t (rev 0)
+++ DBIx-Class/0.08/trunk/t/from_subquery.t 2009-05-12 05:02:56 UTC (rev 6219)
@@ -0,0 +1,192 @@
+use strict;
+use warnings FATAL => 'all';
+
+use Test::More;
+
+BEGIN {
+ eval "use SQL::Abstract 1.49";
+ plan $@
+ ? ( skip_all => "Needs SQLA 1.49+" )
+ : ( tests => 8 );
+}
+
+use lib qw(t/lib);
+use DBICTest;
+use DBIC::SqlMakerTest;
+
+my $schema = DBICTest->init_schema();
+my $art_rs = $schema->resultset('Artist');
+my $cdrs = $schema->resultset('CD');
+
+{
+ my $cdrs2 = $cdrs->search({
+ artist_id => { 'in' => $art_rs->search({}, { rows => 1 })->get_column( 'id' )->as_query },
+ });
+
+ my $arr = $cdrs2->as_query;
+ my ($query, @bind) = @{$$arr};
+ is_same_sql_bind(
+ $query, \@bind,
+ "(SELECT me.cdid,me.artist,me.title,me.year,me.genreid,me.single_track FROM cd me WHERE artist_id IN ( SELECT id FROM artist me LIMIT 1 ))",
+ [],
+ );
+}
+
+{
+ my $rs = $art_rs->search(
+ {},
+ {
+ 'select' => [
+ $cdrs->search({}, { rows => 1 })->get_column('id')->as_query,
+ ],
+ },
+ );
+
+ my $arr = $rs->as_query;
+ my ($query, @bind) = @{$$arr};
+ is_same_sql_bind(
+ $query, \@bind,
+ "(SELECT (SELECT id FROM cd me LIMIT 1) FROM artist me)",
+ [],
+ );
+}
+
+{
+ my $rs = $art_rs->search(
+ {},
+ {
+ '+select' => [
+ $cdrs->search({}, { rows => 1 })->get_column('id')->as_query,
+ ],
+ },
+ );
+
+ my $arr = $rs->as_query;
+ my ($query, @bind) = @{$$arr};
+ is_same_sql_bind(
+ $query, \@bind,
+ "(SELECT me.artistid, me.name, me.rank, me.charfield, (SELECT id FROM cd me LIMIT 1) FROM artist me)",
+ [],
+ );
+}
+
+# simple from
+{
+ my $rs = $cdrs->search(
+ {},
+ {
+ alias => 'cd2',
+ from => [
+ { cd2 => $cdrs->search({ id => { '>' => 20 } })->as_query },
+ ],
+ },
+ );
+
+ my $arr = $rs->as_query;
+ my ($query, @bind) = @{$$arr};
+ is_same_sql_bind(
+ $query, \@bind,
+ "(SELECT cd2.cdid, cd2.artist, cd2.title, cd2.year, cd2.genreid, cd2.single_track FROM (SELECT me.cdid,me.artist,me.title,me.year,me.genreid,me.single_track FROM cd me WHERE ( id > ? ) ) cd2)",
+ [
+ [ 'id', 20 ]
+ ],
+ );
+}
+
+# nested from
+{
+ my $art_rs2 = $schema->resultset('Artist')->search({},
+ {
+ from => [ { 'me' => 'artist' },
+ [ { 'cds' => $cdrs->search({},{ 'select' => [\'me.artist as cds_artist' ]})->as_query },
+ { 'me.artistid' => 'cds_artist' } ] ]
+ });
+
+ my $arr = $art_rs2->as_query;
+ my ($query, @bind) = @{$$arr};
+ is_same_sql_bind(
+ $query, \@bind,
+ "(SELECT me.artistid, me.name, me.rank, me.charfield FROM artist me JOIN (SELECT me.artist as cds_artist FROM cd me) cds ON me.artistid = cds_artist)",
+ []
+ );
+
+
+}
+
+# nested subquery in from
+{
+ my $rs = $cdrs->search(
+ {},
+ {
+ alias => 'cd2',
+ from => [
+ { cd2 => $cdrs->search(
+ { id => { '>' => 20 } },
+ {
+ alias => 'cd3',
+ from => [
+ { cd3 => $cdrs->search( { id => { '<' => 40 } } )->as_query }
+ ],
+ }, )->as_query },
+ ],
+ },
+ );
+
+ my $arr = $rs->as_query;
+ my ($query, @bind) = @{$$arr};
+ is_same_sql_bind(
+ $query, \@bind,
+ "(SELECT cd2.cdid, cd2.artist, cd2.title, cd2.year, cd2.genreid, cd2.single_track
+ FROM
+ (SELECT cd3.cdid,cd3.artist,cd3.title,cd3.year,cd3.genreid,cd3.single_track
+ FROM
+ (SELECT me.cdid,me.artist,me.title,me.year,me.genreid,me.single_track
+ FROM cd me WHERE ( id < ? ) ) cd3
+ WHERE ( id > ? ) ) cd2)",
+ [
+ [ 'id', 40 ],
+ [ 'id', 20 ]
+ ],
+ );
+
+}
+
+{
+ my $rs = $cdrs->search({
+ year => {
+ '=' => $cdrs->search(
+ { artistid => { '=' => \'me.artistid' } },
+ { alias => 'inner' }
+ )->get_column('year')->max_rs->as_query,
+ },
+ });
+ my $arr = $rs->as_query;
+ my ($query, @bind) = @{$$arr};
+ is_same_sql_bind(
+ $query, \@bind,
+ "(SELECT me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track FROM cd me WHERE year = (SELECT MAX(inner.year) FROM cd inner WHERE artistid = me.artistid))",
+ [],
+ );
+}
+
+{
+ my $rs = $cdrs->search(
+ {},
+ {
+ alias => 'cd2',
+ from => [
+ { cd2 => $cdrs->search({ title => 'Thriller' })->as_query },
+ ],
+ },
+ );
+
+ my $arr = $rs->as_query;
+ my ($query, @bind) = @{$$arr};
+ is_same_sql_bind(
+ $query, \@bind,
+ "(SELECT cd2.cdid, cd2.artist, cd2.title, cd2.year, cd2.genreid, cd2.single_track FROM (SELECT me.cdid,me.artist,me.title,me.year,me.genreid,me.single_track FROM cd me WHERE ( title = ? ) ) cd2)",
+ [ [ 'title', 'Thriller' ] ],
+ );
+}
+
+__END__
Modified: DBIx-Class/0.08/trunk/t/resultset/as_query.t
===================================================================
--- DBIx-Class/0.08/trunk/t/resultset/as_query.t 2009-05-12 05:02:33 UTC (rev 6218)
+++ DBIx-Class/0.08/trunk/t/resultset/as_query.t 2009-05-12 05:02:56 UTC (rev 6219)
@@ -7,7 +7,7 @@
use Test::More;
-plan ( tests => 4 );
+plan ( tests => 5 );
use lib qw(t/lib);
use DBICTest;
@@ -65,3 +65,12 @@
[ [ rank => 2 ], [ name => 'Billy Joel' ] ],
);
}
+
+{
+ my $rs = $schema->resultset("CD")->search(
+ { 'artist.name' => 'Caterwauler McCrae' },
+ { join => [qw/artist/]}
+ );
+ my $subsel_rs = $schema->resultset("CD")->search( { cdid => { IN => $rs->get_column('cdid')->as_query } } );
+ is($subsel_rs->count, $rs->count, 'Subselect on PK got the same row count');
+}
Modified: DBIx-Class/0.08/trunk/t/search/subquery.t
===================================================================
--- DBIx-Class/0.08/trunk/t/search/subquery.t 2009-05-12 05:02:33 UTC (rev 6218)
+++ DBIx-Class/0.08/trunk/t/search/subquery.t 2009-05-12 05:02:56 UTC (rev 6219)
@@ -7,7 +7,7 @@
use Test::More;
-plan ( tests => 7 );
+plan ( tests => 8 );
use lib qw(t/lib);
use DBICTest;
@@ -85,8 +85,10 @@
my ($query, @bind) = @{$$arr};
is_same_sql_bind(
$query, \@bind,
- "( SELECT cd2.cdid, cd2.artist, cd2.title, cd2.year, cd2.genreid, cd2.single_track FROM (SELECT me.cdid,me.artist,me.title,me.year,me.genreid,me.single_track FROM cd me WHERE id > 20) cd2 )",
- [],
+ "( SELECT cd2.cdid, cd2.artist, cd2.title, cd2.year, cd2.genreid, cd2.single_track FROM (SELECT me.cdid,me.artist,me.title,me.year,me.genreid,me.single_track FROM cd me WHERE id > ?) cd2 )",
+ [
+ [ 'id', 20 ]
+ ],
);
}
@@ -137,10 +139,13 @@
(SELECT cd3.cdid,cd3.artist,cd3.title,cd3.year,cd3.genreid,cd3.single_track
FROM
(SELECT me.cdid,me.artist,me.title,me.year,me.genreid,me.single_track
- FROM cd me WHERE id < 40) cd3
- WHERE id > 20) cd2
+ FROM cd me WHERE id < ?) cd3
+ WHERE id > ?) cd2
)",
- [],
+ [
+ [ 'id', 40 ],
+ [ 'id', 20 ]
+ ],
);
}
@@ -163,4 +168,28 @@
);
}
+{
+ my $rs = $cdrs->search(
+ {},
+ {
+ alias => 'cd2',
+ from => [
+ { cd2 => $cdrs->search({ title => 'Thriller' })->as_query },
+ ],
+ },
+ );
+
+ my $arr = $rs->as_query;
+ my ($query, @bind) = @{$$arr};
+ is_same_sql_bind(
+ $query, \@bind,
+ "(SELECT cd2.cdid, cd2.artist, cd2.title, cd2.year, cd2.genreid, cd2.single_track FROM (SELECT me.cdid,me.artist,me.title,me.year,me.genreid,me.single_track FROM cd me WHERE title = ?) cd2)",
+ [
+ [ 'title',
+ 'Thriller'
+ ]
+ ],
+ );
+}
+
__END__
More information about the Bast-commits
mailing list