Merge 'DBIx-Class-current' into 'trunk'
David Kamholz [Wed, 1 Mar 2006 08:56:06 +0000 (08:56 +0000)]
15 files changed:
Changes
MANIFEST [deleted file]
lib/DBIx/Class/DB.pm
lib/DBIx/Class/InflateColumn.pm
lib/DBIx/Class/Manual/Cookbook.pod
lib/DBIx/Class/Manual/ExampleSchema.pod [new file with mode: 0644]
lib/DBIx/Class/ResultSet.pm
lib/DBIx/Class/ResultSetProxy.pm
lib/DBIx/Class/Schema.pm
lib/DBIx/Class/Storage/DBI.pm
t/50fork.t
t/lib/DBICTest/Schema.pm
t/lib/DBICTest/Schema/Serialized.pm [new file with mode: 0644]
t/lib/sqlite.sql
t/run/08inflate.tl

diff --git a/Changes b/Changes
index 0438e98..1a96f7f 100644 (file)
--- a/Changes
+++ b/Changes
@@ -28,7 +28,8 @@ Revision history for DBIx::Class
           keys of the related table are not fetched
         - fix count for group_by as scalar
         - add horrific fix to make Oracle's retarded limit syntax work
-        - remove Carp require
+        - changed UUIDColumns to use new UUIDMaker classes for uuid creation
+        using whatever module may be available
 
 0.05003 2006-02-08 17:50:20
         - add component_class accessors and use them for *_class
diff --git a/MANIFEST b/MANIFEST
deleted file mode 100644 (file)
index 9e7f38b..0000000
--- a/MANIFEST
+++ /dev/null
@@ -1,232 +0,0 @@
-Build.PL
-Changes
-lib/DBIx/Class.pm
-lib/DBIx/Class/AccessorGroup.pm
-lib/DBIx/Class/CDBICompat.pm
-lib/DBIx/Class/CDBICompat/AccessorMapping.pm
-lib/DBIx/Class/CDBICompat/AttributeAPI.pm
-lib/DBIx/Class/CDBICompat/AutoUpdate.pm
-lib/DBIx/Class/CDBICompat/ColumnCase.pm
-lib/DBIx/Class/CDBICompat/ColumnGroups.pm
-lib/DBIx/Class/CDBICompat/Constraints.pm
-lib/DBIx/Class/CDBICompat/Constructor.pm
-lib/DBIx/Class/CDBICompat/DestroyWarning.pm
-lib/DBIx/Class/CDBICompat/GetSet.pm
-lib/DBIx/Class/CDBICompat/HasA.pm
-lib/DBIx/Class/CDBICompat/HasMany.pm
-lib/DBIx/Class/CDBICompat/ImaDBI.pm
-lib/DBIx/Class/CDBICompat/LazyLoading.pm
-lib/DBIx/Class/CDBICompat/LiveObjectIndex.pm
-lib/DBIx/Class/CDBICompat/MightHave.pm
-lib/DBIx/Class/CDBICompat/ObjIndexStubs.pm
-lib/DBIx/Class/CDBICompat/Pager.pm
-lib/DBIx/Class/CDBICompat/ReadOnly.pm
-lib/DBIx/Class/CDBICompat/Retrieve.pm
-lib/DBIx/Class/CDBICompat/Stringify.pm
-lib/DBIx/Class/CDBICompat/TempColumns.pm
-lib/DBIx/Class/CDBICompat/Triggers.pm
-lib/DBIx/Class/ClassResolver/PassThrough.pm
-lib/DBIx/Class/Componentised.pm
-lib/DBIx/Class/Core.pm
-lib/DBIx/Class/Cursor.pm
-lib/DBIx/Class/DB.pm
-lib/DBIx/Class/InflateColumn.pm
-lib/DBIx/Class/Manual.pod
-lib/DBIx/Class/Manual/Cookbook.pod
-lib/DBIx/Class/Manual/FAQ.pod
-lib/DBIx/Class/Manual/Glossary.pod
-lib/DBIx/Class/Manual/Intro.pod
-lib/DBIx/Class/Manual/SchemaIntro.pod
-lib/DBIx/Class/Manual/Troubleshooting.pod
-lib/DBIx/Class/PK.pm
-lib/DBIx/Class/PK/Auto.pm
-lib/DBIx/Class/PK/Auto/DB2.pm
-lib/DBIx/Class/PK/Auto/MSSQL.pm
-lib/DBIx/Class/PK/Auto/MySQL.pm
-lib/DBIx/Class/PK/Auto/Oracle.pm
-lib/DBIx/Class/PK/Auto/Pg.pm
-lib/DBIx/Class/PK/Auto/SQLite.pm
-lib/DBIx/Class/Relationship.pm
-lib/DBIx/Class/Relationship/Accessor.pm
-lib/DBIx/Class/Relationship/Base.pm
-lib/DBIx/Class/Relationship/BelongsTo.pm
-lib/DBIx/Class/Relationship/CascadeActions.pm
-lib/DBIx/Class/Relationship/HasMany.pm
-lib/DBIx/Class/Relationship/HasOne.pm
-lib/DBIx/Class/Relationship/Helpers.pm
-lib/DBIx/Class/Relationship/ManyToMany.pm
-lib/DBIx/Class/Relationship/ProxyMethods.pm
-lib/DBIx/Class/ResultSet.pm
-lib/DBIx/Class/ResultSetManager.pm
-lib/DBIx/Class/ResultSetProxy.pm
-lib/DBIx/Class/ResultSource.pm
-lib/DBIx/Class/ResultSource/Table.pm
-lib/DBIx/Class/ResultSourceProxy.pm
-lib/DBIx/Class/ResultSourceProxy/Table.pm
-lib/DBIx/Class/Row.pm
-lib/DBIx/Class/Schema.pm
-lib/DBIx/Class/Serialize/Storable.pm
-lib/DBIx/Class/Storage.pm
-lib/DBIx/Class/Storage/DBI.pm
-lib/DBIx/Class/Storage/DBI/Cursor.pm
-lib/DBIx/Class/Storage/DBI/DB2.pm
-lib/DBIx/Class/Storage/DBI/MSSQL.pm
-lib/DBIx/Class/Storage/DBI/mysql.pm
-lib/DBIx/Class/Storage/DBI/Oracle.pm
-lib/DBIx/Class/Storage/DBI/Pg.pm
-lib/DBIx/Class/Storage/DBI/SQLite.pm
-lib/DBIx/Class/Test/SQLite.pm
-lib/DBIx/Class/UUIDColumns.pm
-lib/DBIx/Class/UUIDMaker.pm
-lib/DBIx/Class/UUIDMaker/APR/UUID.pm
-lib/DBIx/Class/UUIDMaker/Data/Uniqid.pm
-lib/DBIx/Class/UUIDMaker/Data/UUID.pm
-lib/DBIx/Class/UUIDMaker/UUID.pm
-lib/DBIx/Class/UUIDMaker/Win32/Guidgen.pm
-lib/DBIx/Class/UUIDMaker/Win32API/GUID.pm
-lib/DBIx/Class/Validation.pm
-lib/SQL/Translator/Parser/DBIx/Class.pm
-lib/SQL/Translator/Producer/DBIx/Class/File.pm
-Makefile.PL
-MANIFEST                       This list of files
-README
-t/02pod.t
-t/03podcoverage.t.disabled
-t/04dont_break_c3.t
-t/18inserterror.t
-t/19quotes.t
-t/20setuperrors.t
-t/30dbicplain.t
-t/40resultsetmanager.t
-t/41orrible.t
-t/42toplimit.t
-t/50fork.t
-t/basicrels/01core.t
-t/basicrels/04db.t
-t/basicrels/05multipk.t
-t/basicrels/06relationship.t
-t/basicrels/07pager.t
-t/basicrels/08inflate.t
-t/basicrels/08inflate_has_a.t
-t/basicrels/09update.t
-t/basicrels/10auto.t
-t/basicrels/11mysql.t
-t/basicrels/12pg.t
-t/basicrels/13oracle.t
-t/basicrels/145db2.t
-t/basicrels/14mssql.t
-t/basicrels/15limit.t
-t/basicrels/16joins.t
-t/basicrels/17join_count.t
-t/basicrels/18self_referencial.t
-t/basicrels/19uuid.t
-t/basicrels/20unique.t
-t/basicrels/21serialize.t
-t/basicrels/22cascade_copy.t
-t/basicrels/23cache.t
-t/cdbi-sweet-t/08pager.t
-t/cdbi-t/01-columns.t
-t/cdbi-t/02-Film.t
-t/cdbi-t/03-subclassing.t
-t/cdbi-t/04-lazy.t
-t/cdbi-t/06-hasa.t
-t/cdbi-t/09-has_many.t
-t/cdbi-t/11-triggers.t
-t/cdbi-t/12-filter.t
-t/cdbi-t/13-constraint.t
-t/cdbi-t/14-might_have.t
-t/cdbi-t/15-accessor.t
-t/cdbi-t/16-reserved.t
-t/cdbi-t/18-has_a.t
-t/cdbi-t/19-set_sql.t
-t/cdbi-t/21-iterator.t
-t/cdbi-t/22-self_referential.t
-t/cdbi-t/30-pager.t
-t/cdbi-t/98-failure.t
-t/helperrels/01core.t
-t/helperrels/04db.t
-t/helperrels/05multipk.t
-t/helperrels/06relationship.t
-t/helperrels/07pager.t
-t/helperrels/08inflate.t
-t/helperrels/08inflate_has_a.t
-t/helperrels/09update.t
-t/helperrels/10auto.t
-t/helperrels/11mysql.t
-t/helperrels/12pg.t
-t/helperrels/13oracle.t
-t/helperrels/145db2.t
-t/helperrels/14mssql.t
-t/helperrels/15limit.t
-t/helperrels/16joins.t
-t/helperrels/17join_count.t
-t/helperrels/18self_referencial.t
-t/helperrels/19uuid.t
-t/helperrels/20unique.t
-t/helperrels/21transactions.t
-t/lib/DBICTest.pm
-t/lib/DBICTest/BasicRels.pm
-t/lib/DBICTest/Extra.pm
-t/lib/DBICTest/Extra/Foo.pm
-t/lib/DBICTest/HelperRels.pm
-t/lib/DBICTest/Plain.pm
-t/lib/DBICTest/Plain/Test.pm
-t/lib/DBICTest/Schema.pm
-t/lib/DBICTest/Schema/Artist.pm
-t/lib/DBICTest/Schema/ArtistUndirectedMap.pm
-t/lib/DBICTest/Schema/BasicRels.pm
-t/lib/DBICTest/Schema/CD.pm
-t/lib/DBICTest/Schema/CD_to_Producer.pm
-t/lib/DBICTest/Schema/FourKeys.pm
-t/lib/DBICTest/Schema/HelperRels.pm
-t/lib/DBICTest/Schema/LinerNotes.pm
-t/lib/DBICTest/Schema/OneKey.pm
-t/lib/DBICTest/Schema/Producer.pm
-t/lib/DBICTest/Schema/SelfRef.pm
-t/lib/DBICTest/Schema/SelfRefAlias.pm
-t/lib/DBICTest/Schema/Tag.pm
-t/lib/DBICTest/Schema/Track.pm
-t/lib/DBICTest/Schema/TreeLike.pm
-t/lib/DBICTest/Schema/TwoKeys.pm
-t/lib/DBICTest/Setup.pm
-t/lib/sqlite.sql
-t/run/01core.tl
-t/run/04db.tl
-t/run/05multipk.tl
-t/run/06relationship.tl
-t/run/07pager.tl
-t/run/08inflate.tl
-t/run/08inflate_has_a.tl
-t/run/09update.tl
-t/run/10auto.tl
-t/run/11mysql.tl
-t/run/12pg.tl
-t/run/13oracle.tl
-t/run/145db2.tl
-t/run/14mssql.tl
-t/run/15limit.tl
-t/run/16joins.tl
-t/run/17join_count.tl
-t/run/18self_referencial.tl
-t/run/19uuid.tl
-t/run/20unique.tl
-t/run/21transactions.tl
-t/testlib/Actor.pm
-t/testlib/ActorAlias.pm
-t/testlib/Binary.pm
-t/testlib/Blurb.pm
-t/testlib/CDBase.pm
-t/testlib/Director.pm
-t/testlib/Film.pm
-t/testlib/Lazy.pm
-t/testlib/Log.pm
-t/testlib/MyBase.pm
-t/testlib/MyFilm.pm
-t/testlib/MyFoo.pm
-t/testlib/MyStar.pm
-t/testlib/MyStarLink.pm
-t/testlib/MyStarLinkMCPK.pm
-t/testlib/Order.pm
-t/testlib/OtherFilm.pm
-t/testlib/PgBase.pm
-META.yml
index 14b421f..62d93a2 100644 (file)
@@ -67,7 +67,7 @@ it. See resolve_class below.
 =cut
 
 __PACKAGE__->mk_classdata('class_resolver' =>
-                            'DBIx::Class::ClassResolver::PassThrough');
+                          'DBIx::Class::ClassResolver::PassThrough');
 
 =head2 connection
 
@@ -106,7 +106,7 @@ Begins a transaction (does nothing if AutoCommit is off).
 
 =cut
 
-sub txn_begin { $_[0]->schema_instance->txn_begin }
+sub txn_begin { shift->schema_instance->txn_begin(@_); }
 
 =head2 txn_commit
 
@@ -114,7 +114,7 @@ Commits the current transaction.
 
 =cut
 
-sub txn_commit { $_[0]->schema_instance->txn_commit }
+sub txn_commit { shift->schema_instance->txn_commit(@_); }
 
 =head2 txn_rollback
 
@@ -122,7 +122,17 @@ Rolls back the current transaction.
 
 =cut
 
-sub txn_rollback { $_[0]->schema_instance->txn_rollback }
+sub txn_rollback { shift->schema_instance->txn_rollback(@_); }
+
+=head2 txn_do
+
+Executes a block of code transactionally. If this code reference
+throws an exception, the transaction is rolled back and the exception
+is rethrown. See txn_do in L<DBIx::Class::Schema> for more details.
+
+=cut
+
+sub txn_do { shift->schema_instance->txn_do(@_); }
 
 {
   my $warn;
index f60e112..6efbe13 100644 (file)
@@ -124,6 +124,18 @@ sub _inflated_column_op {
   return $obj;
 }
 
+sub update {
+  my ($class, $attrs, @rest) = @_;
+  $attrs ||= {};
+  foreach my $key (keys %$attrs) {
+    if (ref $attrs->{$key}
+          && exists $class->column_info($key)->{_inflate_info}) {
+      $attrs->{$key} = $class->_deflated_column($key, $attrs->{$key});
+    }
+  }
+  return $class->next::method($attrs, @rest);
+}
+
 sub new {
   my ($class, $attrs, @rest) = @_;
   $attrs ||= {};
index 1ab0e31..2552b92 100644 (file)
@@ -352,29 +352,42 @@ SQL statements:
 =head2 Transactions
 
 As of version 0.04001, there is improved transaction support in
-L<DBIx::Class::Storage::DBI>.  Here is an example of the recommended
-way to use it:
+L<DBIx::Class::Storage::DBI> and L<DBIx::Class::Schema>.  Here is an
+example of the recommended way to use it:
 
-  my $genus = Genus->find(12);
-  eval {
-    MyDB->txn_begin;
+  my $genus = $schema->resultset('Genus')->find(12);
+
+  my $coderef1 = sub {
+    my ($schema, $genus, $code) = @_;
     $genus->add_to_species({ name => 'troglodyte' });
     $genus->wings(2);
     $genus->update;
-    cromulate($genus); # Can have a nested transation
-    MyDB->txn_commit;
+    $schema->txn_do($code, $genus); # Can have a nested transation
+    return $genus->species;
+  };
+
+  my $coderef2 = sub {
+    my ($genus) = @_;
+    $genus->extinct(1);
+    $genus->update;
   };
-  if ($@) {
-    # Rollback might fail, too
-    eval {
-      MyDB->txn_rollback
-    };
+
+  my $rs;
+  eval {
+    $rs = $schema->txn_do($coderef1, $schema, $genus, $coderef2);
+  };
+
+  if ($@) {                             # Transaction failed
+    die "the sky is falling!"           #
+      if ($@ =~ /Rollback failed/);     # Rollback failed
+
+    deal_with_failed_transaction();
   }
 
-Currently, a nested commit will do nothing and a nested rollback will
-die.  The code at each level must be sure to call rollback in the case
-of an error, to ensure that the rollback will propagate to the top
-level and be issued.  Support for savepoints and for true nested
+Nested transactions will work as expected. That is, only the outermost
+transaction will actually issue a commit to the $dbh, and a rollback
+at any level of any transaction will cause the entire nested
+transaction to fail. Support for savepoints and for true nested
 transactions (for databases that support them) will hopefully be added
 in the future.
 
@@ -483,10 +496,10 @@ instead:
       validate             => $validate       ||  0,
       parser_args          => {
          'DBIx::Schema'    => $schema,
-                              }
+                              },
       producer_args   => {
           'prefix'         => 'My::Schema',
-                         }
+                         },
   );
   
   $translator->parser('DBIx::Class');
diff --git a/lib/DBIx/Class/Manual/ExampleSchema.pod b/lib/DBIx/Class/Manual/ExampleSchema.pod
new file mode 100644 (file)
index 0000000..e2a5166
--- /dev/null
@@ -0,0 +1,355 @@
+=head1 NAME
+
+DBIx::Class::Manual::Example - Simple CD database example
+
+=head1 DESCRIPTION
+
+This tutorial will guide you through the proeccess of setting up and
+testing a very basic CD database using SQLite, with DBIx::Class::Schema
+as the database frontend.
+
+The database consists of the following:
+
+ table 'artist' with columns:  artistid, name
+ table 'cd'     with columns:  cdid, artist, title
+ table 'track'  with columns:  trackid, cd, title
+
+
+And these rules exists:
+
+ one artist can have many cds
+ one cd belongs to one artist
+ one cd can have many tracks
+ one track belongs to one cd
+
+
+=head2 Installation
+
+Install DBIx::Class via CPAN should be sufficient.
+
+=head3 Create the database/tables.
+
+First make and change the directory:
+
+ mkdir app
+ cd app
+
+This example uses SQLite which is a dependency of DBIx::Class, so you
+shouldn't have to install extra software.
+
+Save the following into a example.sql
+
+ CREATE TABLE artist (
+ artistid INTEGER PRIMARY KEY,
+ name TEXT NOT NULL 
+ );
+
+ CREATE TABLE cd (
+ cdid INTEGER PRIMARY KEY,
+ artist INTEGER NOT NULL REFERENCES artist(artistid),
+ title TEXT NOT NULL);
+
+ CREATE TABLE track (
+ trackid INTEGER PRIMARY KEY,
+ cd INTEGER NOT NULL REFERENCES cd(cdid),
+ title TEXT NOT NULL) ;
+
+and create the sqlite database file:
+
+sqlite3 example.db < example.sql
+
+=head3 Set up DBIx::Class::Schema
+
+First, create some dirs and change working directory:
+
+ mkdir MyDatabase
+ mkdir MyDatabase/Main
+
+Then, create the following DBIx::Class::Schema classes:
+
+MyDatabase/Main.pm:
+   
+ package MyDatabase::Main;
+ use base qw/DBIx::Class::Schema/;
+ __PACKAGE__->load_classes(qw/Artist Cd Track/);
+
+ 1;
+
+
+MyDatabase/Main/Artist.pm:
+
+ package MyDatabase::Main::Artist;
+ use base qw/DBIx::Class/;
+ __PACKAGE__->load_components(qw/Core/);
+ __PACKAGE__->table('artist');
+ __PACKAGE__->add_columns(qw/ artistid name /);
+ __PACKAGE__->set_primary_key('artistid');
+ __PACKAGE__->has_many('cds' => 'MyDatabase::Main::Cd');
+
+ 1;
+
+
+MyDatabase/Main/Cd.pm:
+
+ package MyDatabase::Main::Cd;
+ use base qw/DBIx::Class/;
+ __PACKAGE__->load_components(qw/Core/);
+ __PACKAGE__->table('cd');
+ __PACKAGE__->add_columns(qw/ cdid artist title/);
+ __PACKAGE__->set_primary_key('cdid');
+ __PACKAGE__->belongs_to('artist' => 'MyDatabase::Main::Artist');
+ __PACKAGE__->has_many('tracks' => 'MyDatabase::Main::Track');
+
+ 1;
+
+
+MyDatabase/Main/Track.pm:
+
+ package MyDatabase::Main::Track;
+ use base qw/DBIx::Class/;
+ __PACKAGE__->load_components(qw/Core/);
+ __PACKAGE__->table('track');
+ __PACKAGE__->add_columns(qw/ trackid cd title/);
+ __PACKAGE__->set_primary_key('trackid');
+ __PACKAGE__->belongs_to('cd' => 'MyDatabase::Main::Cd');
+
+ 1;
+
+
+=head3 Write a script to insert some records.
+
+insertdb.pl
+
+ #!/usr/bin/perl -w
+
+ use MyDatabase::Main;
+ use strict;
+
+ my $schema = MyDatabase::Main->connect('dbi:SQLite:example.db');
+
+ #  here's some of the sql that is going to be generated by the schema
+ #  INSERT INTO artist VALUES (NULL,'Michael Jackson');
+ #  INSERT INTO artist VALUES (NULL,'Eminem');
+
+ my @artists = (['Michael Jackson'], ['Eminem']);
+ $schema->populate('Artist', [
+     [qw/name/],
+     @artists,
+ ]);
+
+ my %albums = (
+     'Thriller' => 'Michael Jackson',
+     'Bad' => 'Michael Jackson',
+     'The Marshall Mathers LP' => 'Eminem',
+     );
+
+ my @cds;
+ foreach my $lp (keys %albums) {
+     my $artist = $schema->resultset('Artist')->search({
+         name => $albums{$lp}
+     });
+     push @cds, [$lp, $artist->first];
+ }
+
+ $schema->populate('Cd', [
+     [qw/title artist/],
+     @cds,
+ ]);
+
+
+ my %tracks = (
+     'Beat It'         => 'Thriller',
+     'Billie Jean'     => 'Thriller',
+     'Dirty Diana'     => 'Bad',
+     'Smooth Criminal' => 'Bad',
+     'Leave Me Alone'  => 'Bad',
+     'Stan'            => 'The Marshall Mathers LP',
+     'The Way I Am'    => 'The Marshall Mathers LP',
+ );
+
+ my @tracks;
+ foreach my $track (keys %tracks) {
+     my $cdname = $schema->resultset('Cd')->search({
+         title => $tracks{$track},
+     });
+     push @tracks, [$cdname->first, $track];
+ }
+
+ $schema->populate('Track',[
+     [qw/cd title/],
+     @tracks,
+ ]);
+
+=head3 Create and run the scripts
+
+testdb.pl:
+
+ #!/usr/bin/perl -w
+
+ use MyDatabase::Main;
+ use strict;
+
+ my $schema = MyDatabase::Main->connect('dbi:SQLite:example.db');
+
+ get_tracks_by_cd('Bad');
+ get_tracks_by_artist('Michael Jackson');
+
+ get_cd_by_track('Stan');
+ get_cds_by_artist('Michael Jackson');
+
+ get_artist_by_track('Dirty Diana');
+ get_artist_by_cd('The Marshall Mathers LP');
+
+
+ sub get_tracks_by_cd {
+     my $cdtitle = shift;
+     print "get_tracks_by_cd($cdtitle):\n";
+     my $rs = $schema->resultset('Track')->search(
+         {
+             'cd.title' => $cdtitle
+         },
+         {
+             join     => [qw/ cd /],
+             prefetch => [qw/ cd /]
+         }
+     );
+     while (my $track = $rs->next) {
+         print $track->title . "\n";
+     }
+     print "\n";
+ }
+
+ sub get_tracks_by_artist {
+     my $artistname = shift;
+     print "get_tracks_by_artist($artistname):\n";
+     my $rs = $schema->resultset('Track')->search(
+         {
+             'artist.name' => $artistname
+         },
+         {
+             join => {
+                 'cd' => 'artist'
+             },
+         }
+     );
+     while (my $track = $rs->next) {
+         print $track->title . "\n";
+     }
+     print "\n";
+ }
+ sub get_cd_by_track {
+     my $tracktitle = shift;
+     print "get_cd_by_track($tracktitle):\n";
+     my $rs = $schema->resultset('Cd')->search(
+         {
+             'tracks.title' => $tracktitle
+         },
+         {
+             join     => [qw/ tracks /],
+         }
+     );
+     my $cd = $rs->first;
+     print $cd->title . "\n\n";
+ }
+ sub get_cds_by_artist {
+     my $artistname = shift;
+     print "get_cds_by_artist($artistname):\n";
+     my $rs = $schema->resultset('Cd')->search(
+         {
+             'artist.name' => $artistname
+         },
+         {
+             join     => [qw/ artist /],
+             prefetch => [qw/ artist /]
+         }
+     );
+     while (my $cd = $rs->next) {
+         print $cd->title . "\n";
+     }
+     print "\n";
+ }
+
+
+
+ sub get_artist_by_track {
+     my $tracktitle = shift;
+     print "get_artist_by_track($tracktitle):\n";
+     my $rs = $schema->resultset('Artist')->search(
+         {
+             'tracks.title' => $tracktitle
+         },
+         {
+            join => {
+            'cds' => 'tracks'
+             }
+         }
+     );
+     my $artist = $rs->first;
+     print $artist->name . "\n\n";
+ }
+
+ sub get_artist_by_cd {
+     my $cdtitle = shift;
+     print "get_artist_by_cd($cdtitle):\n";
+     my $rs = $schema->resultset('Artist')->search(
+         {
+             'cds.title' => $cdtitle
+         },
+         {
+             join     => [qw/ cds /],
+         }
+     );
+     my $artist = $rs->first;
+     print $artist->name . "\n\n";
+ }
+
+
+
+It should output:
+
+ get_tracks_by_cd(Bad):
+ Dirty Diana
+ Smooth Criminal
+ Leave Me Alone
+
+ get_tracks_by_artist(Michael Jackson):
+ Beat it
+ Billie Jean
+ Dirty Diana
+ Smooth Criminal
+ Leave Me Alone
+
+ get_cd_by_track(Stan):
+ The Marshall Mathers LP
+
+ get_cds_by_artist(Michael Jackson):
+ Thriller
+ Bad
+
+ get_artist_by_track(Dirty Diana):
+ Michael Jackson
+
+ get_artist_by_cd(The Marshall Mathers LP):
+ Eminem
+
+=head1 Notes
+
+With these scripts we're relying on @INC looking in the current
+working directory.  You may want to add the MyDatabase namespaces to
+@INC in a different way when it comes to deployemnt.
+
+The testdb.pl script is an excellent start for testing your database
+model.
+
+=head1 TODO
+
+=head1 AUTHOR
+
+  sc_ from irc.perl.org#dbix-class
+  Kieren Diment <kd@totaldatasolution.com>
+
+=cut
index 69ff26d..af51f79 100644 (file)
@@ -55,7 +55,7 @@ In the examples below, the following table classes are used:
 =head3 Arguments: ($source, \%$attrs)
 
 The resultset constructor. Takes a source object (usually a
-L<DBIx::Class::ResultSourceProxy::Table>) and an attribute hash (see L</ATRRIBUTES>
+L<DBIx::Class::ResultSourceProxy::Table>) and an attribute hash (see L</ATTRIBUTES>
 below).  Does not perform any queries -- these are executed as needed by the
 other methods.
 
index 7672052..22336ae 100644 (file)
@@ -2,13 +2,14 @@ package DBIx::Class::ResultSetProxy;
 
 use base qw/DBIx::Class/;
 
-sub search         { shift->resultset_instance->search(@_);         }
-sub search_literal { shift->resultset_instance->search_literal(@_); }
-sub search_like    { shift->resultset_instance->search_like(@_);    }
-sub count          { shift->resultset_instance->count(@_);          }
-sub count_literal  { shift->resultset_instance->count_literal(@_);  }
-sub find           { shift->resultset_instance->find(@_);           }
-sub create         { shift->resultset_instance->create(@_);         }
-sub find_or_create { shift->resultset_instance->find_or_create(@_); }
+sub search           { shift->resultset_instance->search(@_);           }
+sub search_literal   { shift->resultset_instance->search_literal(@_);   }
+sub search_like      { shift->resultset_instance->search_like(@_);      }
+sub count            { shift->resultset_instance->count(@_);            }
+sub count_literal    { shift->resultset_instance->count_literal(@_);    }
+sub find             { shift->resultset_instance->find(@_);             }
+sub create           { shift->resultset_instance->create(@_);           }
+sub find_or_create   { shift->resultset_instance->find_or_create(@_);   }
+sub update_or_create { shift->resultset_instance->update_or_create(@_); }
 
 1;
index 3f1f868..0a39ee8 100644 (file)
@@ -61,7 +61,7 @@ particular which module inherits off which.
 
 Registers a class which isa ResultSourceProxy; equivalent to calling
 
-  $schema->register_source($moniker, $class->result_source_instance);
+  $schema->register_source($moniker, $component_class->result_source_instance);
 
 =cut
 
index 657c919..43d5bf0 100644 (file)
@@ -147,16 +147,7 @@ sub _join_condition {
 sub _quote {
   my ($self, $label) = @_;
   return '' unless defined $label;
-  return "*" if $label eq '*';
   return $label unless $self->{quote_char};
-  if(ref $self->{quote_char} eq "ARRAY"){
-    return $self->{quote_char}->[0] . $label . $self->{quote_char}->[1]
-      if !defined $self->{name_sep};
-    my $sep = $self->{name_sep};
-    return join($self->{name_sep},
-        map { $self->{quote_char}->[0] . $_ . $self->{quote_char}->[1]  }
-       split(/\Q$sep\E/,$label));
-  }
   return $self->SUPER::_quote($label);
 }
 
@@ -303,8 +294,10 @@ sub ensure_connected {
 sub dbh {
   my ($self) = @_;
 
-  $self->_dbh(undef)
-    if $self->_connection_pid && $self->_connection_pid != $$;
+  if($self->_connection_pid && $self->_connection_pid != $$) {
+      $self->_dbh->{InactiveDestroy} = 1;
+      $self->_dbh(undef)
+  }
   $self->ensure_connected;
   return $self->_dbh;
 }
@@ -355,11 +348,15 @@ sub _connect {
 
 Calls begin_work on the current dbh.
 
+See L<DBIx::Class::Schema> for the txn_do() method, which allows for
+an entire code block to be executed transactionally.
+
 =cut
 
 sub txn_begin {
   my $self = shift;
-  $self->dbh->begin_work if $self->{transaction_depth}++ == 0 and $self->dbh->{AutoCommit};
+  $self->dbh->begin_work
+    if $self->{transaction_depth}++ == 0 and $self->dbh->{AutoCommit};
 }
 
 =head2 txn_commit
@@ -380,7 +377,9 @@ sub txn_commit {
 
 =head2 txn_rollback
 
-Issues a rollback against the current dbh.
+Issues a rollback against the current dbh. A nested rollback will
+throw a L<DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION> exception,
+which allows the rollback to propagate to the outermost transaction.
 
 =cut
 
@@ -412,8 +411,8 @@ sub _execute {
   my ($sql, @bind) = $self->sql_maker->$op($ident, @args);
   unshift(@bind, @$extra_bind) if $extra_bind;
   if ($self->debug) {
-      my @debug_bind = map { defined $_ ? $_ : 'NULL' } @bind;
-      $self->debugfh->print("$sql: @debug_bind\n");
+      my @debug_bind = map { defined $_ ? qq{`$_'} : q{`NULL'} } @bind;
+      $self->debugfh->print("$sql: " . join(', ', @debug_bind) . "\n");
   }
   my $sth = $self->sth($sql,$op);
   $self->throw_exception("no sth generated via sql: $sql") unless $sth;
index 0e40c6a..79ba7a6 100644 (file)
@@ -28,7 +28,10 @@ my ($first_rs, $joe_record);
 eval {
     my $dbh = PgTest->schema->storage->dbh;
 
-    $dbh->do("CREATE TABLE cd (cdid serial PRIMARY KEY, artist INTEGER NOT NULL UNIQUE, title VARCHAR(255) NOT NULL UNIQUE, year VARCHAR(255));");
+    eval {
+        $dbh->do("DROP TABLE cd");
+        $dbh->do("CREATE TABLE cd (cdid serial PRIMARY KEY, artist INTEGER NOT NULL UNIQUE, title VARCHAR(255) NOT NULL UNIQUE, year VARCHAR(255));");
+    };
 
     PgTest->resultset('CD')->create({ title => 'vacation in antarctica', artist => 123, year => 1901 });
     PgTest->resultset('CD')->create({ title => 'vacation in antarctica part 2', artist => 456, year => 1901 });
index 2355aeb..8090e51 100644 (file)
@@ -16,6 +16,7 @@ __PACKAGE__->load_classes(qw/
     OneKey
     #dummy
     TwoKeys
+    Serialized
   /]},
   (
     'FourKeys',
diff --git a/t/lib/DBICTest/Schema/Serialized.pm b/t/lib/DBICTest/Schema/Serialized.pm
new file mode 100644 (file)
index 0000000..16b73f0
--- /dev/null
@@ -0,0 +1,12 @@
+package DBICTest::Schema::Serialized;
+
+use base 'DBIx::Class::Core';
+
+DBICTest::Schema::Serialized->table('serialized');
+DBICTest::Schema::Serialized->add_columns(
+  'id' => { data_type => 'integer' },
+  'serialized' => { data_type => 'text' },
+);
+DBICTest::Schema::Serialized->set_primary_key('id');
+
+1;
index 8238674..391de14 100644 (file)
@@ -130,4 +130,12 @@ CREATE TABLE self_ref (
   name varchar NOT NULL
 );
 
+--
+-- Table: serialized
+--
+CREATE TABLE serialized (
+    id INTEGER PRIMARY KEY NOT NULL,
+    serialized text NOT NULL
+);
+
 COMMIT;
index e21a6c6..97d0778 100644 (file)
@@ -4,7 +4,7 @@ my $schema = shift;
 eval { require DateTime };
 plan skip_all => "Need DateTime for inflation tests" if $@;
 
-plan tests => 3;
+plan tests => 5;
 
 DBICTest::Schema::CD->inflate_column( 'year',
     { inflate => sub { DateTime->new( year => shift ) },
@@ -27,6 +27,34 @@ $cd->update;
 ($cd) = $schema->resultset("CD")->search( year => $now->year );
 is( $cd->year->year, $now->year, 'deflate ok' );
 
+use YAML;
+DBICTest::Schema::Serialized->inflate_column( 'serialized',
+    { inflate => sub { Load (shift) },
+      deflate => sub { die "Expecting a reference" unless (ref $_[0]); Dump (shift) } }
+);
+Class::C3->reinitialize;
+
+my $complex1 = {
+    id => 1,
+    serialized => {
+        a => 1,
+        b => 2,
+    },
+};
+
+my $complex2 = {
+    id => 1,
+    serialized => [qw/a b 1 2/],
+};
+
+my $rs = $schema->resultset('Serialized');
+
+my $entry = $rs->create($complex2);
+
+ok($entry->update ($complex1), "update with hashref deflating ok");
+
+ok($entry->update ($complex2), "update with arrayref deflating ok");
+
 }
 
 1;