Fix func_rs() and as_subselect_rs() to start behaving as advertised
[dbsrgits/DBIx-Class.git] / t / 88result_set_column.t
index c26f207..7abf670 100644 (file)
@@ -1,12 +1,19 @@
+BEGIN { do "./t/lib/ANFANG.pm" or die ( $@ || $! ) }
+
 use strict;
 use warnings;
 
 use Test::More;
 use Test::Warn;
 use Test::Exception;
-use lib qw(t/lib);
-use DBICTest;
-use DBIC::SqlMakerTest;
+
+# MASSIVE FIXME - there is a hole in ::RSC / as_subselect_rs
+# losing the order. Needs a rework/extract of the realiaser,
+# and that's a whole another bag of dicks
+BEGIN { $ENV{DBIC_SHUFFLE_UNORDERED_RESULTSETS} = 0 }
+
+
+use DBICTest ':DiffSQL';
 
 my $schema = DBICTest->init_schema();
 
@@ -33,6 +40,13 @@ while (my $r = $rs_title->next) {
 
 is_deeply (\@all_titles, \@nexted_titles, 'next works');
 
+my @list_ctx;
+warnings_exist {
+  @list_ctx = $rs_year->func_rs('DISTINCT');
+} [qr/\Qfunc_rs() always returns a ResultSet instance regardless of calling context/];
+is( scalar @list_ctx, 1, 'wantarray context does not affect func_rs');
+isa_ok( $list_ctx[0], 'DBIx::Class::ResultSet' );
+isa_ok( scalar( $rs_year->func_rs('DISTINCT') ), 'DBIx::Class::ResultSet' );
 is_deeply( [ sort $rs_year->func('DISTINCT') ], [ 1997, 1998, 1999, 2001 ],  "wantarray context okay");
 ok ($max_year->next == $rs_year->max, q/get_column (\'FUNC') ok/);
 
@@ -41,14 +55,16 @@ is($rs_title->min, 'Caterwaulin\' Blues', "min okay for title");
 
 cmp_ok($rs_year->sum, '==', 9996, "three artists returned");
 
-my $rso_year = $rs->search({}, { order_by => 'cdid' })->get_column('year');
-is($rso_year->next, 1999, "reset okay");
+{
+  my $rso_year = $rs->search({}, { order_by => 'cdid' })->get_column('year');
+  is($rso_year->next, 1999, "reset okay");
 
-is($rso_year->first, 1999, "first okay");
+  is($rso_year->first, 1999, "first okay");
 
-warnings_exist (sub {
-  is($rso_year->single, 1999, "single okay");
-}, qr/Query returned more than one row/, 'single warned');
+  warnings_exist (sub {
+    is($rso_year->single, 1999, "single okay");
+  }, qr/Query returned more than one row/, 'single warned');
+}
 
 
 # test distinct propagation
@@ -58,6 +74,51 @@ is_deeply (
   'distinct => 1 is passed through properly',
 );
 
+# test illogical distinct
+my $dist_rs = $rs->search ({}, {
+  columns => ['year'],
+  distinct => 1,
+  order_by => { -desc => [qw( cdid year )] },
+});
+
+is_same_sql_bind(
+  $dist_rs->as_query,
+  '(
+    SELECT me.year
+      FROM cd me
+    GROUP BY me.year
+    ORDER BY MAX(cdid) DESC, year DESC
+  )',
+  [],
+  'Correct SQL on external-ordered distinct',
+);
+
+is_same_sql_bind(
+  $dist_rs->count_rs->as_query,
+  '(
+    SELECT COUNT( * )
+      FROM (
+        SELECT me.year
+          FROM cd me
+        GROUP BY me.year
+      ) me
+  )',
+  [],
+  'Correct SQL on count of external-orderdd distinct',
+);
+
+is (
+  $dist_rs->count_rs->next,
+  4,
+  'Correct rs-count',
+);
+
+is (
+  $dist_rs->count,
+  4,
+  'Correct direct count',
+);
+
 # test +select/+as for single column
 my $psrs = $schema->resultset('CD')->search({},
     {
@@ -172,7 +233,7 @@ is_same_sql_bind (
   'Correct SQL for prefetch/order_by/group_by'
 );
 
-# test aggregate on a function
+# test aggregate on a function (create an extra track on one cd)
 {
   my $tr_rs = $schema->resultset("Track");
   $tr_rs->create({ cd => 2, title => 'dealbreaker' });
@@ -197,4 +258,87 @@ is_same_sql_bind (
   );
 }
 
+# test exotic scenarious (create a track-less cd)
+# "How many CDs (not tracks) have been released per year where a given CD has at least one track and the artist isn't evancarroll?"
+{
+
+  $schema->resultset('CD')->create({ artist => 1, title => 'dealbroker no tracks', year => 2001 });
+
+  my $yp1 = \[ 'year + ?', 1 ];
+
+  my $rs = $schema->resultset ('CD')->search (
+    { 'artist.name' => { '!=', 'evancarrol' }, 'tracks.trackid' => { '!=', undef } },
+    {
+      order_by => 'me.year',
+      join => [qw(artist tracks)],
+      columns => [
+        'year',
+        { cnt => { count => 'me.cdid' } },
+        {  year_plus_one => $yp1 },
+      ],
+    },
+  );
+
+  my $rstypes = {
+    'explicitly grouped' => $rs->search_rs({}, { group_by => [ 'year', $yp1 ] } ),
+    'implicitly grouped' => $rs->search_rs({}, { distinct => 1 }),
+  };
+
+  for my $type (keys %$rstypes) {
+    is ($rstypes->{$type}->count, 4, "correct cd count with $type column");
+
+    is_deeply (
+      [ $rstypes->{$type}->get_column ('year')->all ],
+      [qw(1997 1998 1999 2001)],
+      "Getting $type column works",
+    );
+  }
+
+  # Why do we test this - we want to make sure that the selector *will* actually make
+  # it to the group_by as per the distinct => 1 contract. Before 0.08251 this situation
+  # would silently drop the group_by entirely, likely ending up with nonsensival results
+  # With the current behavior the user will at least get a nice fat exception from the
+  # RDBMS (or maybe the RDBMS will even decide to handle the situation sensibly...)
+  for (
+    [ cnt => 'COUNT( me.cdid )' ],
+    [ year_plus_one => 'year + ?' => [ {} => 1 ] ],
+  ) {
+    my ($col, $sel_grp_sql, @sel_grp_bind) = @$_;
+
+    warnings_exist { is_same_sql_bind(
+      $rstypes->{'implicitly grouped'}->get_column($col)->as_query,
+      "(
+        SELECT $sel_grp_sql
+          FROM cd me
+          JOIN artist artist
+            ON artist.artistid = me.artist
+          LEFT JOIN track tracks
+            ON tracks.cd = me.cdid
+        WHERE artist.name != ? AND tracks.trackid IS NOT NULL
+        GROUP BY $sel_grp_sql
+        ORDER BY MIN(me.year)
+      )",
+      [
+        @sel_grp_bind,
+        [ { dbic_colname => 'artist.name', sqlt_datatype => 'varchar', sqlt_size => 100 }
+          => 'evancarrol' ],
+        @sel_grp_bind,
+      ],
+      'Expected (though nonsensical) SQL generated on rscol-with-distinct-over-function',
+    ) } qr/
+      \QUse of distinct => 1 while selecting anything other than a column \E
+      \Qdeclared on the primary ResultSource is deprecated (you selected '$col')\E
+    /x, 'deprecation warning';
+  }
+
+  {
+    local $TODO = 'multiplying join leaks through to the count aggregate... this may never actually work';
+    is_deeply (
+      [ $rstypes->{'explicitly grouped'}->get_column ('cnt')->all ],
+      [qw(1 1 1 2)],
+      "Get aggregate over group works",
+    );
+  }
+}
+
 done_testing;