revert previous revision
Matt S Trout [Fri, 20 Feb 2009 07:07:46 +0000 (07:07 +0000)]
Changes
lib/DBIx/Class.pm
lib/DBIx/Class/Manual/Cookbook.pod
lib/DBIx/Class/Relationship/Accessor.pm
lib/DBIx/Class/Storage/DBI/Replicated/Pool.pm
t/66relationship.t
t/72pg.t
t/86sqlt.t
t/bindtype_columns.t
t/lib/DBIC/SqlMakerTest.pm
t/lib/sqlite.sql

diff --git a/Changes b/Changes
index 24cd9c6..9bdf1b9 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,5 +1,15 @@
 Revision history for DBIx::Class
+        - Add DBIC_MULTICREATE_DEBUG env var (undocumented, quasi-internal)
+        - Fix up multi-create to:
+          - correctly propagate columns loaded during multi-insert of rels
+          - not try and insert things tagged on via new_related unless required
         - Possible to set locale in IC::DateTime extra => {} config
+        - Calling the accessor of a belongs_to when the foreign_key
+          was NULL and the row was not stored would unexpectedly fail (groditi)
+        - Split sql statements for deploy only if SQLT::Producer returned a scalar
+          containing all statements to be executed
+        - Add as_query() for ResultSet and ResultSetColumn. This makes subqueries
+          possible. See the Cookbook for details. (robkinyon, michaelr)
 
 0.08099_06 2009-01-23 07:30:00 (UTC)
         - Allow a scalarref to be supplied to the 'from' resultset attribute
@@ -19,6 +29,7 @@ Revision history for DBIx::Class
         - PG array datatype supported with SQLA >= 1.50
         - insert should use store_column, not set_column to avoid marking
           clean just-stored values as dirty. New test for this (groditi)
+        - regression test for source_name (groditi)
 
 0.08099_05 2008-10-30 21:30:00 (UTC)
         - Rewritte of Storage::DBI::connect_info(), extended with an
index 31c7f12..6ea8116 100644 (file)
@@ -291,6 +291,8 @@ ribasushi: Peter Rabbitson <rabbit+dbic@rabbit.us>
 
 rjbs: Ricardo Signes <rjbs@cpan.org>
 
+robkinyon: Rob Kinyon <rkinyon@cpan.org>
+
 sc_: Just Another Perl Hacker
 
 scotty: Scotty Allen <scotty@scottyallen.com>
index f4a5a45..678e173 100644 (file)
@@ -1407,12 +1407,16 @@ passing them as bind values:
 
   $resultset->search(
     {
-      numbers => \[ '= ?', [1, 2, 3] ]
+      numbers => \[ '= ?', [numbers => [1, 2, 3]] ]
     }
   );
 
 See L<SQL::Abstract/array_datatypes> and L<SQL::Abstract/Literal SQL with
-placeholders and bind values (subqueries)> for more explanation.
+placeholders and bind values (subqueries)> for more explanation. Note that
+L<DBIx::Class> sets L<SQL::Abstract/bindtype> to C<columns>, so you must pass
+the bind values (the C<[1, 2, 3]> arrayref in the above example) wrapped in
+arrayrefs together with the column name, like this: C<< [column_name => value]
+>>.
 
 =head1 BOOTSTRAPPING/MIGRATING 
 
index dcb906e..6ec2f25 100644 (file)
@@ -31,6 +31,7 @@ sub add_relationship_accessor {
           $rel_info->{cond}, $rel, $self
         );
         if ($rel_info->{attrs}->{undef_on_null_fk}){
+          return unless ref($cond) eq 'HASH';
           return if grep { not defined } values %$cond;
         }
         my $val = $self->find_related($rel, {}, {});
index 833ffad..76ca7f2 100644 (file)
@@ -187,17 +187,19 @@ bringing down your entire pool of databases.
 
 sub _safely_ensure_connected {
   my ($self, $replicant, @args) = @_;
-  my $return; eval {
-    $return = $replicant->ensure_connected(@args);
-  }; if ($@) {
+  eval {
+    $replicant->ensure_connected(@args);
+  }; 
+  if ($@) {
     $replicant
-        ->debugobj
-        ->print(
-            sprintf( "Exception trying to ->ensure_connected for replicant %s, error is %s",
-                $self->_dbi_connect_info->[0], $@)
+      ->debugobj
+      ->print(
+        sprintf( "Exception trying to ->ensure_connected for replicant %s, error is %s",
+          $replicant->_dbi_connect_info->[0], $@)
         );
+       return;
   }
-  return $return;
+  return 1;
 }
 
 =head2 connected_replicants
index 6a30aa3..0ae02e6 100644 (file)
@@ -8,7 +8,7 @@ use DBICTest;
 
 my $schema = DBICTest->init_schema();
 
-plan tests => 74;
+plan tests => 69;
 
 # has_a test
 my $cd = $schema->resultset("CD")->find(4);
index fa67d1c..45e614f 100644 (file)
--- a/t/72pg.t
+++ b/t/72pg.t
@@ -153,7 +153,7 @@ SKIP: {
   my $count;
   lives_ok {
     $count = $schema->resultset('ArrayTest')->search({
-      arrayfield => \[ '= ?' => [3, 4] ],   #TODO anything less ugly than this?
+      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');
index 531a8a3..24d573e 100644 (file)
@@ -10,7 +10,7 @@ plan skip_all => 'SQL::Translator required' if $@;
 
 my $schema = DBICTest->init_schema;
 
-plan tests => 132;
+plan tests => 133;
 
 my $translator = SQL::Translator->new( 
   parser_args => {
@@ -29,7 +29,7 @@ my $translator = SQL::Translator->new(
     $schema->source('Track')->sqlt_deploy_callback(sub {
       my ($self, $sqlt_table) = @_;
 
-      if ($sqlt_table->schema->translator->producer_type =~ /SQLite$/ ) {
+      if ($schema->storage->sqlt_type eq 'SQLite' ) {
         $sqlt_table->add_index( name => 'track_title', fields => ['title'] )
           or die $sqlt_table->error;
       }
index cf0649d..1462d9b 100644 (file)
@@ -21,8 +21,6 @@ my $dbh = $schema->storage->dbh;
     $dbh->do('DROP TABLE IF EXISTS bindtype_test');
 
     # the blob/clob are for reference only, will be useful when we switch to SQLT and can test Oracle along the way
-
-    # the blob/clob are for reference only, will be useful when we switch to SQLT and can test Oracle along the way
     $dbh->do(qq[
         CREATE TABLE bindtype_test 
         (
@@ -34,21 +32,57 @@ my $dbh = $schema->storage->dbh;
     ],{ RaiseError => 1, PrintError => 1 });
 }
 
+my $big_long_string    = "\x00\x01\x02 abcd" x 125000;
+
+my $new;
+# test inserting a row
+{
+  $new = $schema->resultset('BindType')->create({ bytea => $big_long_string });
+
+  ok($new->id, "Created a bytea row");
+  is($new->bytea,      $big_long_string, "Set the blob correctly.");
+}
+
 # test retrieval of the bytea column
 {
   my $row = $schema->resultset('BindType')->find({ id => $new->id });
   is($row->get_column('bytea'), $big_long_string, "Created the blob correctly.");
 }
 
-my $new = $schema->resultset('BindType')->create({ bytea => $big_long_string });
+TODO: {
+  local $TODO =
+    'Passing bind attributes to $sth->bind_param() should be implemented (it only works in $storage->insert ATM)';
 
-ok($new->id, "Created a bytea row");
-is($new->bytea,        $big_long_string, "Set the blob correctly.");
+  my $rs = $schema->resultset('BindType')->search({ bytea => $big_long_string });
 
-my $rs = $schema->resultset('BindType')->find({ id => $new->id });
+  # search on the bytea column (select)
+  {
+    my $row = $rs->first;
+    is($row ? $row->id : undef, $new->id, "Found the row searching on the bytea column.");
+  }
 
-is($rs->get_column('bytea'), $big_long_string, "Created the blob correctly.");
+  # search on the bytea column (update)
+  {
+    my $new_big_long_string = $big_long_string . "2";
+    $schema->txn_do(sub {
+      $rs->update({ bytea => $new_big_long_string });
+      my $row = $schema->resultset('BindType')->find({ id => $new->id });
+      is($row ? $row->get_column('bytea') : undef, $new_big_long_string,
+        "Updated the row correctly (searching on the bytea column)."
+      );
+      $schema->txn_rollback;
+    });
+  }
 
-$dbh->do("DROP TABLE bindtype_test");
+  # search on the bytea column (delete)
+  {
+    $schema->txn_do(sub {
+      $rs->delete;
+      my $row = $schema->resultset('BindType')->find({ id => $new->id });
+      is($row, undef, "Deleted the row correctly (searching on the bytea column).");
+      $schema->txn_rollback;
+    });
+  }
+}
 
 $dbh->do("DROP TABLE bindtype_test");
index 8c2406c..cf33fd9 100644 (file)
@@ -7,8 +7,11 @@ use base qw/Test::Builder::Module Exporter/;
 
 our @EXPORT = qw/
   &is_same_sql_bind
+  &is_same_sql
+  &is_same_bind
   &eq_sql
   &eq_bind
+  &eq_sql_bind
 /;
 
 
@@ -39,19 +42,59 @@ our @EXPORT = qw/
     $tb->ok($same_sql && $same_bind, $msg);
 
     if (!$same_sql) {
-      $tb->diag("SQL expressions differ\n"
-        . "     got: $sql1\n"
-        . "expected: $sql2\n"
-      );
+      _sql_differ_diag($sql1, $sql2);
     }
     if (!$same_bind) {
-      $tb->diag("BIND values differ\n"
-        . "     got: " . Dumper($bind_ref1)
-        . "expected: " . Dumper($bind_ref2)
-      );
+      _bind_differ_diag($bind_ref1, $bind_ref2);
     }
   }
 
+  sub is_same_sql
+  {
+    my ($sql1, $sql2, $msg) = @_;
+
+    my $same_sql = eq_sql($sql1, $sql2);
+
+    $tb->ok($same_sql, $msg);
+
+    if (!$same_sql) {
+      _sql_differ_diag($sql1, $sql2);
+    }
+  }
+
+  sub is_same_bind
+  {
+    my ($bind_ref1, $bind_ref2, $msg) = @_;
+
+    my $same_bind = eq_bind($bind_ref1, $bind_ref2);
+
+    $tb->ok($same_bind, $msg);
+
+    if (!$same_bind) {
+      _bind_differ_diag($bind_ref1, $bind_ref2);
+    }
+  }
+
+  sub _sql_differ_diag
+  {
+    my ($sql1, $sql2) = @_;
+
+    $tb->diag("SQL expressions differ\n"
+      . "     got: $sql1\n"
+      . "expected: $sql2\n"
+    );
+  }
+
+  sub _bind_differ_diag
+  {
+    my ($bind_ref1, $bind_ref2) = @_;
+
+    $tb->diag("BIND values differ\n"
+      . "     got: " . Dumper($bind_ref1)
+      . "expected: " . Dumper($bind_ref2)
+    );
+  }
+
   sub eq_sql
   {
     my ($left, $right) = @_;
@@ -68,6 +111,13 @@ our @EXPORT = qw/
 
     return eq_deeply($bind_ref1, $bind_ref2);
   }
+
+  sub eq_sql_bind
+  {
+    my ($sql1, $bind_ref1, $sql2, $bind_ref2) = @_;
+
+    return eq_sql($sql1, $sql2) && eq_bind($bind_ref1, $bind_ref2);
+  }
 }
 
 eval "use SQL::Abstract::Test;";
@@ -75,14 +125,20 @@ if ($@ eq '') {
   # SQL::Abstract::Test available
 
   *is_same_sql_bind = \&SQL::Abstract::Test::is_same_sql_bind;
+  *is_same_sql = \&SQL::Abstract::Test::is_same_sql;
+  *is_same_bind = \&SQL::Abstract::Test::is_same_bind;
   *eq_sql = \&SQL::Abstract::Test::eq_sql;
   *eq_bind = \&SQL::Abstract::Test::eq_bind;
+  *eq_sql_bind = \&SQL::Abstract::Test::eq_sql_bind;
 } else {
   # old SQL::Abstract
 
   *is_same_sql_bind = \&DBIC::SqlMakerTest::SQLATest::is_same_sql_bind;
+  *is_same_sql = \&DBIC::SqlMakerTest::SQLATest::is_same_sql;
+  *is_same_bind = \&DBIC::SqlMakerTest::SQLATest::is_same_bind;
   *eq_sql = \&DBIC::SqlMakerTest::SQLATest::eq_sql;
   *eq_bind = \&DBIC::SqlMakerTest::SQLATest::eq_bind;
+  *eq_sql_bind = \&DBIC::SqlMakerTest::SQLATest::eq_sql_bind;
 }
 
 
@@ -131,6 +187,28 @@ comparison of bind values.
 Compares given and expected pairs of C<($sql, \@bind)>, and calls
 L<Test::Builder/ok> on the result, with C<$test_msg> as message.
 
+=head2 is_same_sql
+
+  is_same_sql(
+    $given_sql,
+    $expected_sql,
+    $test_msg
+  );
+
+Compares given and expected SQL statement, and calls L<Test::Builder/ok> on the
+result, with C<$test_msg> as message.
+
+=head2 is_same_bind
+
+  is_same_bind(
+    \@given_bind, 
+    \@expected_bind,
+    $test_msg
+  );
+
+Compares given and expected bind value lists, and calls L<Test::Builder/ok> on
+the result, with C<$test_msg> as message.
+
 =head2 eq_sql
 
   my $is_same = eq_sql($given_sql, $expected_sql);
@@ -143,6 +221,16 @@ Compares the two SQL statements. Returns true IFF they are equivalent.
 
 Compares two lists of bind values. Returns true IFF their values are the same.
 
+=head2 eq_sql_bind
+
+  my $is_same = eq_sql_bind(
+    $given_sql, \@given_bind,
+    $expected_sql, \@expected_bind
+  );
+
+Compares the two SQL statements and the two lists of bind values. Returns true
+IFF they are equivalent and the bind values are the same.
+
 
 =head1 SEE ALSO
 
index ebc10cd..b364cb4 100644 (file)
@@ -1,6 +1,6 @@
 -- 
 -- Created by SQL::Translator::Producer::SQLite
--- Created on Sat Jan 17 19:40:47 2009
+-- Created on Sat Jan 24 19:42:15 2009
 -- 
 BEGIN TRANSACTION;
 
@@ -38,6 +38,18 @@ CREATE TABLE cd_artwork (
 CREATE INDEX cd_artwork_idx_cd_id_cd_artwor ON cd_artwork (cd_id);
 
 --
+-- Table: artwork_to_artist
+--
+CREATE TABLE artwork_to_artist (
+  artwork_cd_id integer NOT NULL,
+  artist_id integer NOT NULL,
+  PRIMARY KEY (artwork_cd_id, artist_id)
+);
+
+CREATE INDEX artwork_to_artist_idx_artist_id_artwork_to_arti ON artwork_to_artist (artist_id);
+CREATE INDEX artwork_to_artist_idx_artwork_cd_id_artwork_to_ ON artwork_to_artist (artwork_cd_id);
+
+--
 -- Table: bindtype_test
 --
 CREATE TABLE bindtype_test (