Expand notabs/eol testing to .pod and some files at the root
[dbsrgits/DBIx-Class.git] / t / 72pg.t
index 738a5ff..5e4ec84 100644 (file)
--- a/t/72pg.t
+++ b/t/72pg.t
@@ -3,18 +3,22 @@ use warnings;
 
 use Test::More;
 use Test::Exception;
+use Sub::Name;
+use DBIx::Class::Optional::Dependencies ();
 use lib qw(t/lib);
 use DBICTest;
 
+plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('test_rdbms_pg')
+  unless DBIx::Class::Optional::Dependencies->req_ok_for ('test_rdbms_pg');
 
 my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_PG_${_}" } qw/DSN USER PASS/};
 
-plan skip_all => <<EOM unless $dsn && $user;
-Set \$ENV{DBICTEST_PG_DSN}, _USER and _PASS to run this test
+plan skip_all => <<'EOM' unless $dsn && $user;
+Set $ENV{DBICTEST_PG_DSN}, _USER and _PASS to run this test
 ( NOTE: This test drops and creates tables called 'artist', 'cd',
 'timestamp_primary_key_test', 'track', 'casecheck', 'array_test' and
 'sequence_test' as well as following sequences: 'pkid1_seq', 'pkid2_seq' and
-'nonpkid_seq''. as well as following schemas: 'dbic_t_schema',
+'nonpkid_seq'. as well as following schemas: 'dbic_t_schema',
 'dbic_t_schema_2', 'dbic_t_schema_3', 'dbic_t_schema_4', and 'dbic_t_schema_5')
 EOM
 
@@ -23,23 +27,6 @@ EOM
 our @test_classes; #< array that will be pushed into by test classes defined in this file
 DBICTest::Schema->load_classes( map {s/.+:://;$_} @test_classes ) if @test_classes;
 
-my $test_server_supports_insert_returning = do {
-  my $s = DBICTest::Schema->connect($dsn, $user, $pass);
-  $s->storage->_determine_driver;
-  $s->storage->_supports_insert_returning;
-};
-
-my $schema;
-
-for my $use_insert_returning ($test_server_supports_insert_returning
-  ? (0,1)
-  : (0)
-) {
-  no warnings qw/redefine once/;
-  local *DBIx::Class::Storage::DBI::Pg::_supports_insert_returning = sub {
-    $use_insert_returning
-  };
-
 ###  pre-connect tests (keep each test separate as to make sure rebless() runs)
   {
     my $s = DBICTest::Schema->connect($dsn, $user, $pass);
@@ -48,8 +35,10 @@ for my $use_insert_returning ($test_server_supports_insert_returning
 
     # Check that datetime_parser returns correctly before we explicitly connect.
     SKIP: {
-        eval { require DateTime::Format::Pg };
-        skip "DateTime::Format::Pg required", 2 if $@;
+        skip (
+          "Pg parser detection test needs " . DBIx::Class::Optional::Dependencies->req_missing_for ('test_dt_pg'),
+          2
+        ) unless DBIx::Class::Optional::Dependencies->req_ok_for ('test_dt_pg');
 
         my $store = ref $s->storage;
         is($store, 'DBIx::Class::Storage::DBI', 'Started with generic storage');
@@ -60,6 +49,7 @@ for my $use_insert_returning ($test_server_supports_insert_returning
 
     ok (!$s->storage->_dbh, 'still not connected');
   }
+
   {
     my $s = DBICTest::Schema->connect($dsn, $user, $pass);
     # make sure sqlt_type overrides work (::Storage::DBI::Pg does this)
@@ -68,6 +58,79 @@ for my $use_insert_returning ($test_server_supports_insert_returning
     ok (!$s->storage->_dbh, 'still not connected');
   }
 
+# test LIMIT support
+{
+  my $schema = DBICTest::Schema->connect($dsn, $user, $pass);
+  drop_test_schema($schema);
+  create_test_schema($schema);
+  for (1..6) {
+    $schema->resultset('Artist')->create({ name => 'Artist ' . $_ });
+  }
+  my $it = $schema->resultset('Artist')->search( {},
+    { rows => 3,
+      offset => 2,
+      order_by => 'artistid' }
+  );
+  is( $it->count, 3, "LIMIT count ok" );  # ask for 3 rows out of 6 artists
+  is( $it->next->name, "Artist 3", "iterator->next ok" );
+  $it->next;
+  $it->next;
+  $it->next;
+  is( $it->next, undef, "next past end of resultset ok" );
+
+  # Limit with select-lock
+  lives_ok {
+    $schema->txn_do (sub {
+      isa_ok (
+        $schema->resultset('Artist')->find({artistid => 1}, {for => 'update', rows => 1}),
+        'DBICTest::Schema::Artist',
+      );
+    });
+  } 'Limited FOR UPDATE select works';
+}
+
+# check if we indeed do support stuff
+my $test_server_supports_insert_returning = do {
+
+  my $si = DBICTest::Schema->connect($dsn, $user, $pass)->storage->_server_info;
+  die "Unparseable Pg server version: $si->{dbms_version}\n"
+    unless $si->{normalized_dbms_version};
+
+  $si->{normalized_dbms_version} < 8.002 ? 0 : 1;
+};
+is (
+  DBICTest::Schema->connect($dsn, $user, $pass)->storage->_use_insert_returning,
+  $test_server_supports_insert_returning,
+  'insert returning capability guessed correctly'
+);
+
+my $schema;
+for my $use_insert_returning ($test_server_supports_insert_returning
+  ? (0,1)
+  : (0)
+) {
+
+  no warnings qw/once redefine/;
+  my $old_connection = DBICTest::Schema->can('connection');
+  local *DBICTest::Schema::connection = subname 'DBICTest::Schema::connection' => sub {
+    my $s = shift->$old_connection(@_);
+    $s->storage->_use_insert_returning ($use_insert_returning);
+    $s;
+  };
+
+### test capability override
+  {
+    my $s = DBICTest::Schema->connect($dsn, $user, $pass);
+
+    ok (!$s->storage->_dbh, 'definitely not connected');
+
+    ok (
+      ! ($s->storage->_use_insert_returning xor $use_insert_returning),
+      'insert returning capability set correctly',
+    );
+    ok (!$s->storage->_dbh, 'still not connected (capability override works)');
+  }
+
 ### connect, create postgres-specific test schema
 
   $schema = DBICTest::Schema->connect($dsn, $user, $pass);
@@ -137,7 +200,7 @@ for my $use_insert_returning ($test_server_supports_insert_returning
 
     use strict;
     use warnings;
-    use base 'DBIx::Class::Core';
+    use base 'DBICTest::BaseResult';
 
     __PACKAGE__->table('dbic_t_schema.array_test');
     __PACKAGE__->add_columns(qw/id arrayfield/);
@@ -146,40 +209,97 @@ for my $use_insert_returning ($test_server_supports_insert_returning
 
   }
   SKIP: {
-    skip "Need DBD::Pg 2.9.2 or newer for array tests", 5 if $DBD::Pg::VERSION < 2.009002;
+    skip "Need DBD::Pg 2.9.2 or newer for array tests", 4 if $DBD::Pg::VERSION < 2.009002;
+
+    my $arr_rs = $schema->resultset('ArrayTest');
 
     lives_ok {
-      $schema->resultset('ArrayTest')->create({
+      $arr_rs->create({
         arrayfield => [1, 2],
       });
     } 'inserting arrayref as pg array data';
 
     lives_ok {
-      $schema->resultset('ArrayTest')->update({
+      $arr_rs->update({
         arrayfield => [3, 4],
       });
     } 'updating arrayref as pg array data';
 
+    $arr_rs->create({
+      arrayfield => [5, 6],
+    });
+
     lives_ok {
-      my $row = $schema->resultset('ArrayTest')->next;
-      $row->arrayfield ([5, 6]);
-      $row->update;
-    } 'updating dirty arrayref as pg array data';
+      $schema->populate('ArrayTest', [
+        [ qw/arrayfield/ ],
+        [ [0,0]          ],
+      ]);
+    } 'inserting arrayref using void ctx populate';
 
-    $schema->resultset('ArrayTest')->create({
-      arrayfield => [7, 8],
-    });
+    # Search using arrays
+    lives_ok {
+      is_deeply (
+        $arr_rs->search({ arrayfield => { -value => [3,4] } })->first->arrayfield,
+        [3,4],
+        'Array value matches'
+      );
+    } 'searching by arrayref';
 
-    my $count;
     lives_ok {
-      $count = $schema->resultset('ArrayTest')->search({
-        arrayfield => \[ '= ?' => [arrayfield => [3, 4]] ],   #Todo anything less ugly than this?
-      })->count;
-    } 'comparing arrayref to pg array data does not blow up';
-    is($count, 1, 'comparing arrayref to pg array data gives correct result');
-  }
+      is_deeply (
+        $arr_rs->search({ arrayfield => { '=' => { -value => [3,4] }} })->first->arrayfield,
+        [3,4],,
+        'Array value matches explicit equal'
+      );
+    } 'searching by arrayref (explicit equal sign)';
 
+    lives_ok {
+      is_deeply (
+        $arr_rs->search({ arrayfield => { '>' => { -value => [3,1] }} })->first->arrayfield,
+        [3,4],
+        'Array value matches greater than'
+      );
+    } 'searching by arrayref (greater than)';
+
+    lives_ok {
+      is (
+        $arr_rs->search({ arrayfield => { '>' => { -value => [3,7] }} })->count,
+        1,
+        'Greater than search found [5,6]',
+      );
+    } 'searching by arrayref (greater than)';
+
+    # Find using arrays
+    lives_ok {
+      is_deeply (
+        $arr_rs->find({ arrayfield => { -value => [3,4] } })->arrayfield,
+        [3,4],
+        'Array value matches implicit equal'
+      );
+    } 'find by arrayref';
 
+    lives_ok {
+      is_deeply (
+        $arr_rs->find({ arrayfield => { '=' => { -value => [3,4] }} })->arrayfield,
+        [3,4],
+        'Array value matches explicit equal'
+      );
+    } 'find by arrayref (equal)';
+
+    # test inferred condition for creation
+    TODO: for my $cond (
+      { -value => [3,4] },
+      \[ '= ?' => [arrayfield => [3, 4]] ],
+    ) {
+      local $TODO = 'No introspection of complex conditions :(';
+      my $arr_rs_cond = $arr_rs->search({ arrayfield => $cond });
+
+      my $row = $arr_rs_cond->create({});
+      is_deeply ($row->arrayfield, [3,4], 'Array value taken from $rs condition');
+      $row->discard_changes;
+      is_deeply ($row->arrayfield, [3,4], 'Array value made it to storage');
+    }
+  }
 
 ########## Case check
 
@@ -207,12 +327,17 @@ for my $use_insert_returning ($test_server_supports_insert_returning
   is( $uc_name_info->{size}, 3, "Case insensitive matching info for 'uc_name'" );
 
 
-
+## Test ResultSet->update
+my $artist = $schema->resultset('Artist')->first;
+my $cds = $artist->cds_unordered->search({
+    year => { '!=' => 2010 }
+}, { prefetch => 'liner_notes' });
+lives_ok { $cds->update({ year => '2010' }) } 'Update on prefetched rs';
 
 ## Test SELECT ... FOR UPDATE
 
   SKIP: {
-      if(eval "require Sys::SigAction" && !$@) {
+      if(eval { require Sys::SigAction }) {
           Sys::SigAction->import( 'set_sig_handler' );
       }
       else {
@@ -244,12 +369,15 @@ for my $use_insert_returning ($test_server_supports_insert_returning
         $schema2->source("Artist")->name("dbic_t_schema.artist");
 
         $schema->txn_do( sub {
-          my $artist = $schema->resultset('Artist')->search(
+          my $rs = $schema->resultset('Artist')->search(
               {
                   artistid => 1
               },
               $t->{update_lock} ? { for => 'update' } : {}
-          )->first;
+          );
+          ok ($rs->count, 'Count works');
+
+          my $artist = $rs->next;
           is($artist->artistid, 1, "select returns artistid = 1");
 
           $timed_out = 0;
@@ -268,11 +396,6 @@ for my $use_insert_returning ($test_server_supports_insert_returning
       }
   }
 
-  # make sure subqueried count still works
-  lives_ok ( sub {
-
-  }, 'for does not propagate on count subqueries');
-
 
 ######## other older Auto-pk tests
 
@@ -289,7 +412,7 @@ for my $use_insert_returning ($test_server_supports_insert_returning
 
 ######## test non-serial auto-pk
 
-  if ($schema->storage->_supports_insert_returning) {
+  if ($schema->storage->_use_insert_returning) {
     $schema->source('TimestampPrimaryKey')->name('dbic_t_schema.timestamp_primary_key_test');
     my $row = $schema->resultset('TimestampPrimaryKey')->create({});
     ok $row->id;
@@ -311,7 +434,7 @@ for my $use_insert_returning ($test_server_supports_insert_returning
   } 'with_deferred_fk_checks code survived';
 
   is eval { $schema->resultset('Track')->find(999)->title }, 'deferred FK track',
-     'code in with_deferred_fk_checks worked'; 
+     'code in with_deferred_fk_checks worked';
 
   throws_ok {
     $schema->resultset('Track')->create({
@@ -325,7 +448,8 @@ done_testing;
 END {
     return unless $schema;
     drop_test_schema($schema);
-    eapk_drop_all( $schema)
+    eapk_drop_all($schema);
+    undef $schema;
 };
 
 
@@ -373,8 +497,7 @@ CREATE TABLE dbic_t_schema.track (
   position int,
   title varchar(255),
   last_updated_on date,
-  last_updated_at date,
-  small_dt date
+  last_updated_at date
 )
 EOS
 
@@ -449,12 +572,12 @@ sub drop_test_schema {
 
         for my $stat (
                       'DROP SCHEMA dbic_t_schema_5 CASCADE',
-                      'DROP SEQUENCE public.artist_artistid_seq',
+                      'DROP SEQUENCE public.artist_artistid_seq CASCADE',
                       'DROP SCHEMA dbic_t_schema_4 CASCADE',
                       'DROP SCHEMA dbic_t_schema CASCADE',
-                      'DROP SEQUENCE pkid1_seq',
-                      'DROP SEQUENCE pkid2_seq',
-                      'DROP SEQUENCE nonpkid_seq',
+                      'DROP SEQUENCE pkid1_seq CASCADE',
+                      'DROP SEQUENCE pkid2_seq CASCADE',
+                      'DROP SEQUENCE nonpkid_seq CASCADE',
                       'DROP SCHEMA dbic_t_schema_2 CASCADE',
                       'DROP SCHEMA dbic_t_schema_3 CASCADE',
                      ) {