From: Matt S Trout Date: Fri, 3 Mar 2006 15:35:41 +0000 (+0000) Subject: Merge 'trunk' into 'DBIx-Class-current' X-Git-Tag: v0.06000~60^2~64 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=39e45539f3373a1f84da5cbefc5b9919484ee384;hp=e59c17fe744031457d375cb464250950881f4c56;p=dbsrgits%2FDBIx-Class.git Merge 'trunk' into 'DBIx-Class-current' r8257@obrien (orig r996): ningu | 2006-03-01 04:42:50 +0000 try to fix PK::Auto::Pg for sequences with quoted names r8259@obrien (orig r998): blblack | 2006-03-01 05:38:51 +0000 dbh->{InactiveDestroy} when reconnecting in child process (prevents auto-disconnecting a dbh still in use by the parent) r8260@obrien (orig r999): blblack | 2006-03-01 05:58:00 +0000 t/50fork.t made a little more resilient r8261@obrien (orig r1000): jguenther | 2006-03-01 08:34:34 +0000 - Changed documentation to use txn_do() for transactions - Fixed Storage::DBI trace such that each bind parameter is quoted on output, separated by commas - Fixed a couple typos in documentation r8263@obrien (orig r1002): zarquon | 2006-03-02 02:10:03 +0000 Altered example to populate the db with DBIC r8264@obrien (orig r1003): zarquon | 2006-03-02 02:11:07 +0000 Moved Example.pod to ExampleSchema.pod r8265@obrien (orig r1004): zarquon | 2006-03-02 02:12:24 +0000 Fixed a typo in the SQL::Translator section (missing comma in has assignment) r8266@obrien (orig r1005): blblack | 2006-03-02 11:29:53 +0000 add update_or_create proxy method r8269@obrien (orig r1008): zarquon | 2006-03-03 00:24:49 +0000 Changed the name of CD class to Cd to be compatible with default SchemaLoader monikerization r8273@obrien (orig r1011): matthewt | 2006-03-03 15:18:27 +0000 Fix to update(\%args) with inflation from test case by Peter Rabbitson r8274@obrien (orig r1012): matthewt | 2006-03-03 15:23:14 +0000 Missing svk add, as usual r8275@obrien (orig r1013): matthewt | 2006-03-03 15:35:13 +0000 MANIFEST nuked out of repo --- diff --git a/MANIFEST b/MANIFEST deleted file mode 100644 index 90d988a..0000000 --- a/MANIFEST +++ /dev/null @@ -1,241 +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/Example.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 -META.yml -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/21transactions.t -t/basicrels/22cascade_copy.t -t/basicrels/23cache.t -t/basicrels/24serialize.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/helperrels/22cascade_copy.t -t/helperrels/23cache.t -t/helperrels/24serialize.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/run/22cascade_copy.tl -t/run/23cache.tl -t/run/24serialize.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 diff --git a/README b/README index dd554e9..ae3a20d 100644 --- a/README +++ b/README @@ -112,7 +112,7 @@ CONTRIBUTORS Scotty Allen - Justin Guenther + Justin Guenther LICENSE You may distribute this code under the same terms as Perl itself. diff --git a/lib/DBIx/Class.pm b/lib/DBIx/Class.pm index 98054c0..e638295 100644 --- a/lib/DBIx/Class.pm +++ b/lib/DBIx/Class.pm @@ -168,6 +168,8 @@ sc_ Robert Sedlacek +Justin Guenther + =head1 LICENSE You may distribute this code under the same terms as Perl itself. diff --git a/lib/DBIx/Class/DB.pm b/lib/DBIx/Class/DB.pm index 14b421f..62d93a2 100644 --- a/lib/DBIx/Class/DB.pm +++ b/lib/DBIx/Class/DB.pm @@ -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 for more details. + +=cut + +sub txn_do { shift->schema_instance->txn_do(@_); } { my $warn; diff --git a/lib/DBIx/Class/InflateColumn.pm b/lib/DBIx/Class/InflateColumn.pm index f60e112..6efbe13 100644 --- a/lib/DBIx/Class/InflateColumn.pm +++ b/lib/DBIx/Class/InflateColumn.pm @@ -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 ||= {}; diff --git a/lib/DBIx/Class/Manual/Cookbook.pod b/lib/DBIx/Class/Manual/Cookbook.pod index 1ab0e31..2552b92 100644 --- a/lib/DBIx/Class/Manual/Cookbook.pod +++ b/lib/DBIx/Class/Manual/Cookbook.pod @@ -352,29 +352,42 @@ SQL statements: =head2 Transactions As of version 0.04001, there is improved transaction support in -L. Here is an example of the recommended -way to use it: +L and L. 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/Example.pod b/lib/DBIx/Class/Manual/ExampleSchema.pod similarity index 61% rename from lib/DBIx/Class/Manual/Example.pod rename to lib/DBIx/Class/Manual/ExampleSchema.pod index 365896e..c308b63 100644 --- a/lib/DBIx/Class/Manual/Example.pod +++ b/lib/DBIx/Class/Manual/ExampleSchema.pod @@ -4,7 +4,9 @@ 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 Mysql, with DBIx::Class::Schema as the database frontend. +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: @@ -23,69 +25,53 @@ And these rules exists: =head2 Installation -=head3 Create the database/tables and populate them with a few records +Install DBIx::Class via CPAN should be sufficient. - CREATE DATABASE cdtestdb ; - USE cdtestdb; +=head3 Create the database/tables. - CREATE TABLE artist ( - artistid INT NOT NULL AUTO_INCREMENT , - name CHAR( 40 ) NOT NULL , - PRIMARY KEY ( artistid ) - ); +First make and change the directory: - CREATE TABLE cd ( - cdid INT NOT NULL AUTO_INCREMENT , - artist INT NOT NULL , - title CHAR( 40 ) NOT NULL , - PRIMARY KEY ( cdid ) - ); + mkdir app + cd app - CREATE TABLE track ( - trackid INT NOT NULL AUTO_INCREMENT , - cd INT NOT NULL , - title CHAR( 40 ) NOT NULL , - PRIMARY KEY ( trackid ) - ; +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 - INSERT INTO artist VALUES - (NULL,'Michael Jackson'), - (NULL,'Eminem'); - - INSERT INTO cd VALUES - (NULL,'1','Thriller'), - (NULL,'1','Bad'), - (NULL,'2','The Marshall Mathers LP'); - - INSERT INTO track VALUES - (NULL,'1','Beat it'), - (NULL,'1','Billie Jean'), - (NULL,'2','Dirty Diana'), - (NULL,'2','Smooth Criminal'), - (NULL,'2','Leave Me Alone'), - (NULL,'3','Stan'), - (NULL,'3','The Way I Am'); + CREATE TABLE artist ( + artistid INTEGER PRIMARY KEY, + name TEXT NOT NULL + ); + + CREATE TABLE cd ( + cdid INTEGER PRIMARY KEY, + artist INTEGER NOT NULL REFERENCES artist(id) + title TEXT NOT NULL); + CREATE TABLE track ( + trackid INTEGER PRIMARY KEY, + cd INTEGER NOT NULL REFERENCES cd(id), + 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 app - mkdir app/DB - mkdir app/DB/Main - cd app + mkdir DB + mkdir DB/Main - Then, create the following DBIx::Class::Schema classes: DB/Main.pm: package DB::Main; use base qw/DBIx::Class::Schema/; - __PACKAGE__->load_classes(qw/Artist CD Track/); + __PACKAGE__->load_classes(qw/Artist Cd Track/); 1; @@ -98,14 +84,14 @@ DB/Main/Artist.pm: __PACKAGE__->table('artist'); __PACKAGE__->add_columns(qw/ artistid name /); __PACKAGE__->set_primary_key('artistid'); - __PACKAGE__->has_many('cds' => 'DB::Main::CD'); + __PACKAGE__->has_many('cds' => 'DB::Main::Cd'); 1; -DB/Main/CD.pm: +DB/Main/Cd.pm: - package DB::Main::CD; + package DB::Main::Cd; use base qw/DBIx::Class/; __PACKAGE__->load_components(qw/Core/); __PACKAGE__->table('cd'); @@ -113,10 +99,10 @@ DB/Main/CD.pm: __PACKAGE__->set_primary_key('cdid'); __PACKAGE__->belongs_to('artist' => 'DB::Main::Artist'); __PACKAGE__->has_many('tracks' => 'DB::Main::Track'); - + 1; - + DB/Main/Track.pm: package DB::Main::Track; @@ -125,12 +111,76 @@ DB/Main/Track.pm: __PACKAGE__->table('track'); __PACKAGE__->add_columns(qw/ trackid cd title/); __PACKAGE__->set_primary_key('trackid'); - __PACKAGE__->belongs_to('cd' => 'DB::Main::CD'); - + __PACKAGE__->belongs_to('cd' => 'DB::Main::Cd'); + 1; -=head3 Create and run the test script +=head3 Write a script to insert some records. + +insertdb.pl + + #!/usr/bin/perl -w + + use DB::Main; + use strict; + + my $schema = DB::Main->connect('dbi:SQLite:dbic_test.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: @@ -193,7 +243,7 @@ testdb.pl: sub get_cd_by_track { my $tracktitle = shift; print "get_cd_by_track($tracktitle):\n"; - my $rs = $schema->resultset('CD')->search( + my $rs = $schema->resultset('Cd')->search( { 'tracks.title' => $tracktitle }, @@ -208,7 +258,7 @@ testdb.pl: sub get_cds_by_artist { my $artistname = shift; print "get_cds_by_artist($artistname):\n"; - my $rs = $schema->resultset('CD')->search( + my $rs = $schema->resultset('Cd')->search( { 'artist.name' => $artistname }, @@ -286,8 +336,20 @@ It should output: 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 DB 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_ + sc_ from IRC. Please credit yourself properly! + Kieren Diment =cut diff --git a/lib/DBIx/Class/ResultSet.pm b/lib/DBIx/Class/ResultSet.pm index 8e61243..532e8b2 100644 --- a/lib/DBIx/Class/ResultSet.pm +++ b/lib/DBIx/Class/ResultSet.pm @@ -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) and an attribute hash (see L +L) and an attribute hash (see L below). Does not perform any queries -- these are executed as needed by the other methods. diff --git a/lib/DBIx/Class/ResultSetProxy.pm b/lib/DBIx/Class/ResultSetProxy.pm index 7672052..22336ae 100644 --- a/lib/DBIx/Class/ResultSetProxy.pm +++ b/lib/DBIx/Class/ResultSetProxy.pm @@ -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; diff --git a/lib/DBIx/Class/Schema.pm b/lib/DBIx/Class/Schema.pm index 3f1f868..2e6e6c0 100644 --- a/lib/DBIx/Class/Schema.pm +++ b/lib/DBIx/Class/Schema.pm @@ -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 @@ -373,12 +373,13 @@ sub txn_rollback { shift->storage->txn_rollback } =head2 txn_do -=head3 Arguments: , [@coderef_args] +=head3 Arguments: <$coderef>, [@coderef_args] -Executes with (optional) arguments <@coderef_args> transactionally, -returning its result (if any). If an exception is caught, a rollback is issued -and the exception is rethrown. If the rollback fails, (i.e. throws an -exception) an exception is thrown that includes a "Rollback failed" message. +Executes C<$coderef> with (optional) arguments C<@coderef_args> +transactionally, returning its result (if any). If an exception is +caught, a rollback is issued and the exception is rethrown. If the +rollback fails, (i.e. throws an exception) an exception is thrown that +includes a "Rollback failed" message. For example, @@ -410,7 +411,7 @@ For example, } } -Nested transactions should work as expected (i.e. only the outermost +Nested transactions work as expected (i.e. only the outermost transaction will issue a txn_commit on the Schema's storage) =cut diff --git a/lib/DBIx/Class/Storage/DBI.pm b/lib/DBIx/Class/Storage/DBI.pm index 657c919..0a3e9c4 100644 --- a/lib/DBIx/Class/Storage/DBI.pm +++ b/lib/DBIx/Class/Storage/DBI.pm @@ -303,8 +303,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 +357,15 @@ sub _connect { Calls begin_work on the current dbh. +See L 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 +386,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 exception, +which allows the rollback to propagate to the outermost transaction. =cut @@ -412,8 +420,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; diff --git a/t/50fork.t b/t/50fork.t index 0e40c6a..79ba7a6 100644 --- a/t/50fork.t +++ b/t/50fork.t @@ -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 }); diff --git a/t/lib/DBICTest/Schema.pm b/t/lib/DBICTest/Schema.pm index 2355aeb..8090e51 100644 --- a/t/lib/DBICTest/Schema.pm +++ b/t/lib/DBICTest/Schema.pm @@ -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 index 0000000..16b73f0 --- /dev/null +++ b/t/lib/DBICTest/Schema/Serialized.pm @@ -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; diff --git a/t/lib/sqlite.sql b/t/lib/sqlite.sql index 8238674..391de14 100644 --- a/t/lib/sqlite.sql +++ b/t/lib/sqlite.sql @@ -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; diff --git a/t/run/08inflate.tl b/t/run/08inflate.tl index e21a6c6..97d0778 100644 --- a/t/run/08inflate.tl +++ b/t/run/08inflate.tl @@ -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;