Merge 'trunk' into 'DBIx-Class-current'
Brandon L. Black [Mon, 31 Jul 2006 20:31:20 +0000 (20:31 +0000)]
r11259@evoc8 (orig r2634):  ningu | 2006-07-27 01:22:57 -0500
add result_class to ResultSourceProxy; move _ident_cond into CDBI code, not needed elsewhere
r11260@evoc8 (orig r2635):  ningu | 2006-07-27 01:32:47 -0500
small cleanup to ResultSourceProxy
r11261@evoc8 (orig r2636):  castaway | 2006-07-27 02:13:53 -0500
Add some new docs

r11262@evoc8 (orig r2637):  castaway | 2006-07-27 02:28:11 -0500
Documentation improvements

r13028@evoc8 (orig r2641):  dwc | 2006-07-27 22:19:58 -0500
Add previous changes for 0.07001
r13029@evoc8 (orig r2642):  dwc | 2006-07-27 22:30:28 -0500
Remove anonymous blesses to avoid major speed hit on Fedora Core 5, or 'the anti-dead-rat fix'
r13030@evoc8 (orig r2643):  dwc | 2006-07-27 23:14:05 -0500
Pass attrs to find from update_or_create (reported by Nathan Kurz)
r13031@evoc8 (orig r2644):  dwc | 2006-07-27 23:20:15 -0500
Typo in scalar ref example
r13032@evoc8 (orig r2645):  dwc | 2006-07-27 23:25:35 -0500
Add missing quote to example.  I looked over this last night, but I guess my eyes aren't working as well anymore.
r13033@evoc8 (orig r2646):  dwc | 2006-07-27 23:55:37 -0500
Minor test cleanup (I think I'm losing my mind)
r13092@evoc8 (orig r2650):  blblack | 2006-07-31 15:31:05 -0500
added Cwd 3.19 + Alg::C3 0.02 to requirements

21 files changed:
Build.PL
Changes
lib/DBIx/Class/CDBICompat/ColumnGroups.pm
lib/DBIx/Class/CDBICompat/LazyLoading.pm
lib/DBIx/Class/DB.pm
lib/DBIx/Class/Manual/DocMap.pod
lib/DBIx/Class/Manual/FAQ.pod
lib/DBIx/Class/PK.pm
lib/DBIx/Class/ResultSet.pm
lib/DBIx/Class/ResultSetColumn.pm
lib/DBIx/Class/ResultSource.pm
lib/DBIx/Class/ResultSourceProxy.pm
lib/DBIx/Class/Row.pm
lib/DBIx/Class/Schema.pm
lib/DBIx/Class/Storage.pm
lib/DBIx/Class/Storage/DBI.pm
lib/DBIx/Class/Storage/Statistics.pm
t/80unique.t
t/lib/DBICTest/Schema.pm
t/lib/DBICTest/Schema/NoPrimaryKey.pm [new file with mode: 0644]
t/lib/sqlite.sql

index 2ab62b9..a43f626 100644 (file)
--- a/Build.PL
+++ b/Build.PL
@@ -6,10 +6,12 @@ my %arguments = (
     license            => 'perl',
     module_name        => 'DBIx::Class',
     requires           => {
+        'Cwd'                       => 3.19,
         'Data::Page'                => 2.00,
         'Scalar::Util'              => 0,
         'SQL::Abstract'             => 1.20,
         'SQL::Abstract::Limit'      => 0.101,
+        'Algorithm::C3'             => 0.02,
         'Class::C3'                 => 0.11,
         'Storable'                  => 0,
         'Class::Data::Accessor'     => 0.01,
diff --git a/Changes b/Changes
index 81c081b..33e2775 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,5 +1,14 @@
 Revision history for DBIx::Class
 
+0.07001
+        - pass $attrs to find from update_or_create so a specific key can be
+          provided
+        - remove anonymous blesses to avoid major speed hit on Fedora Core 5's
+          Perl and possibly others; for more information see:
+          https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=196836
+        - fix a pathological prefetch case
+        - table case fix for Oracle in columns_info_for
+
 0.07000 2006-07-23 02:30:00
         - supress warnings for possibly non-unique queries, since
           _is_unique_query doesn't infer properly in all cases
index 911fe2a..98e6508 100644 (file)
@@ -64,7 +64,8 @@ sub find_column {
 
 sub __grouper {
   my ($class) = @_;
-  return bless({ class => $class}, 'DBIx::Class::CDBICompat::ColumnGroups::GrouperShim');
+  my $grouper = { class => $class };
+  return bless($grouper, 'DBIx::Class::CDBICompat::ColumnGroups::GrouperShim');
 }
 
 sub _find_columns {
index 48a3110..b7d3633 100644 (file)
@@ -22,6 +22,11 @@ sub get_column {
   $self->next::method(@_[1..$#_]);
 }
 
+sub _ident_cond {
+  my ($class) = @_;
+  return join(" AND ", map { "$_ = ?" } $class->primary_columns);
+}
+
 sub _flesh {
   my ($self, @groups) = @_;
   @groups = ('All') unless @groups;
index 0fb7e8a..007c82a 100644 (file)
@@ -93,7 +93,8 @@ register themselves with it.
 
 sub setup_schema_instance {
   my $class = shift;
-  my $schema = bless({}, 'DBIx::Class::Schema');
+  my $schema = {};
+  bless $schema, 'DBIx::Class::Schema';
   $class->mk_classdata('schema_instance' => $schema);
 }
 
index 7631375..8d425bb 100644 (file)
@@ -8,6 +8,8 @@ DBIx::Class::Manual::DocMap - What documentation do we have?
 
 =item L<DBIx::Class::Manual> - User's Manual overview.
 
+=item L<DBIx::Class::Manual::FAQ> - Frequently Asked Questions, gathered from IRC and the mailing list.
+
 =item L<DBIx::Class::Manual::Intro> - Introduction to setting up and using DBIx::Class.
 
 =item L<DBIx::Class::Manual::Example> - Full example Schema.
@@ -36,12 +38,14 @@ DBIx::Class::Manual::DocMap - What documentation do we have?
 
 =item L<DBIx::Class::PK::Auto> - Magically retrieve auto-incrementing fields.
 
-=item L<DBIx::Class::Core> - Set of standard components.
+=item L<DBIx::Class::Core> - Set of standard components to load.
 
 =item L<DBIx::Class::Serialize::Storable> - ?
 
 =item L<DBIx::Class::InflateColumn> - Making objects out of your columns.
 
+=item L<DBIx::Class::InflateColumn::DateTime> - Magically turn your datetime or timestamp columns into DateTime objects.
+
 =item L<DBIx::Class::PK> - Dealing with primary keys.
 
 =item L<DBIx::Class::ResultSourceProxy::Table> - Turns the resultsource into a table.
@@ -56,6 +60,8 @@ DBIx::Class::Manual::DocMap - What documentation do we have?
 
 =item L<DBIx::Class::ResultSet> - Selecting and manipulating sets.
 
+=item L<DBIx::Class::ResultSetColumn> - Perform operations on entire columns of a ResultSet.
+
 =item L<DBIx::Class::Row> - Dealing with actual data.
 
 =item L<DBIx::Class::Storage::DBI> - Storage using L<DBI> and L<SQL::Abstract>.
index 30e856b..8b8baed 100644 (file)
@@ -190,12 +190,12 @@ Then you can use the alias in your C<group_by> attribute.
 The first argument to C<search> is a hashref of accessor names and
 values to filter them by, for example:
 
- ->search({'created_time' => { '>=', '2006-06-01 00:00:00'} })
+ ->search({'created_time' => { '>=', '2006-06-01 00:00:00' } })
 
 Note that to use a function here you need to make the whole value into
 a scalar reference:
 
- ->search({'created_time' => \'>= yesterday() })
+ ->search({'created_time' => \'>= yesterday()' })
 
 =item .. search in several tables simultaneously?
 
@@ -205,7 +205,7 @@ then supply the name of the relationship to the C<join> attribute in
 your search, for example when searching in the Books table for all the
 books by the author "Fred Bloggs":
 
- ->search({'authors.name' => 'Fred Bloggs'}, { join => 'authors'})
+ ->search({'authors.name' => 'Fred Bloggs'}, { join => 'authors' })
 
 The type of join created in your SQL depends on the type of
 relationship between the two tables, see L<DBIx::Class::Relationship>
@@ -288,7 +288,7 @@ the rows at once.
 To stop the column name from being quoted, you'll need to supply a
 scalar reference:
 
- ->update({ somecolumn => '\othercolumn'})
+ ->update({ somecolumn => \'othercolumn' })
 
 =back
 
index 9895edb..ea22a21 100644 (file)
@@ -20,11 +20,6 @@ depending on them.
 
 =cut
 
-sub _ident_cond {
-  my ($class) = @_;
-  return join(" AND ", map { "$_ = ?" } $class->primary_columns);
-}
-
 sub _ident_values {
   my ($self) = @_;
   return (map { $self->{_column_data}{$_} } $self->primary_columns);
index c94476d..b9c2948 100644 (file)
@@ -95,12 +95,6 @@ sub new {
 
   $attrs->{alias} ||= 'me';
 
-  # XXXX
-  # Use a named hash here and bless afterwards to avoid a huge performance hit
-  # in perl 5.8.8-5+ FC5 and later, and possibly other distributions.
-  #
-  # See https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=196836 for more
-  # information.
   my $self = {
     result_source => $source,
     result_class => $attrs->{result_class} || $source->result_class,
@@ -291,6 +285,9 @@ If the C<key> is specified as C<primary>, it searches only on the primary key.
 If no C<key> is specified, it searches on all unique constraints defined on the
 source, including the primary key.
 
+If your table does not have a primary key, you B<must> provide a value for the
+C<key> attribute matching one of the unique constraints on the source.
+
 See also L</find_or_create> and L</update_or_create>. For information on how to
 declare unique constraints, see
 L<DBIx::Class::ResultSource/add_unique_constraint>.
@@ -306,7 +303,7 @@ sub find {
     ? $self->result_source->unique_constraint_columns($attrs->{key})
     : $self->result_source->primary_columns;
   $self->throw_exception(
-    "Can't find unless a primary key or unique constraint is defined"
+    "Can't find unless a primary key is defined or unique constraint is specified"
   ) unless @cols;
 
   # Parse out a hashref from input
@@ -569,7 +566,7 @@ sub _collapse_query {
 
   my $max_length = $rs->get_column('length')->max;
 
-Returns a ResultSetColumn instance for $column based on $self
+Returns a L<DBIx::Class::ResultSetColumn> instance for a column of the ResultSet.
 
 =cut
 
@@ -1347,7 +1344,7 @@ sub update_or_create {
   my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {});
   my $cond = ref $_[0] eq 'HASH' ? shift : {@_};
 
-  my $row = $self->find($cond);
+  my $row = $self->find($cond, $attrs);
   if (defined $row) {
     $row->update($cond);
     return $row;
index 35f8fa4..49b8456 100644 (file)
@@ -16,7 +16,8 @@ use base 'DBIx::Class';
 
 =head1 DESCRIPTION
 
-A convenience class used to perform operations on a specific column of a resultset.
+A convenience class used to perform operations on a specific column of
+a resultset.
 
 =cut
 
@@ -26,7 +27,8 @@ A convenience class used to perform operations on a specific column of a results
 
   my $obj = DBIx::Class::ResultSetColumn->new($rs, $column);
 
-Creates a new resultset column object from the resultset and column passed as params
+Creates a new resultset column object from the resultset and column
+passed as params. Used internally by L<DBIx::Class::ResultSet/get_column>.
 
 =cut
 
@@ -52,9 +54,11 @@ sub new {
 
 =back
 
-Returns the next value of the column in the resultset (C<undef> is there is none).
+Returns the next value of the column in the resultset (or C<undef> if
+there is none).
 
-Much like $rs->next but just returning the one value
+Much like L<DBIx::Class::ResultSet/next> but just returning the 
+one value.
 
 =cut
 
@@ -76,9 +80,11 @@ sub next {
 
 =back
 
-Returns all values of the column in the resultset (C<undef> is there are none).
+Returns all values of the column in the resultset (or C<undef> if
+there are none).
 
-Much like $rs->all but returns values rather than row objects
+Much like L<DBIx::Class::ResultSet/all> but returns values rather
+than row objects.
 
 =cut
 
@@ -97,7 +103,10 @@ sub all {
 
 =back
 
-Wrapper for ->func. Returns the lowest value of the column in the resultset (C<undef> is there are none).
+  my $first_year = $year_col->min();
+
+Wrapper for ->func. Returns the lowest value of the column in the
+resultset (or C<undef> if there are none).
 
 =cut
 
@@ -116,7 +125,10 @@ sub min {
 
 =back
 
-Wrapper for ->func. Returns the highest value of the column in the resultset (C<undef> is there are none).
+  my $last_year = $year_col->max();
+
+Wrapper for ->func. Returns the highest value of the column in the
+resultset (or C<undef> if there are none).
 
 =cut
 
@@ -135,7 +147,10 @@ sub max {
 
 =back
 
-Wrapper for ->func. Returns the sum of all the values in the column of the resultset. Use on varchar-like columns at your own risk.
+  my $total = $prices_col->sum();
+
+Wrapper for ->func. Returns the sum of all the values in the column of
+the resultset. Use on varchar-like columns at your own risk.
 
 =cut
 
@@ -154,12 +169,13 @@ sub sum {
 
 =back
 
-Runs a query using the function on the column and returns the value. For example 
   $rs = $schema->resultset("CD")->search({});
   $length = $rs->get_column('title')->func('LENGTH');
 
-Produces the following SQL
-  SELECT LENGTH( title ) from cd me
+Runs a query using the function on the column and returns the
+value. Produces the following SQL:
+
+  SELECT LENGTH( title ) FROM cd me
 
 =cut
 
@@ -177,6 +193,8 @@ sub func {
 
 Luke Saunders <luke.saunders@gmail.com>
 
+Jess Robinson
+
 =head1 LICENSE
 
 You may distribute this code under the same terms as Perl itself.
index 12a7f40..f498490 100644 (file)
@@ -45,7 +45,10 @@ Creates a new ResultSource object.  Not normally called directly by end users.
 sub new {
   my ($class, $attrs) = @_;
   $class = ref $class if ref $class;
-  my $new = bless({ %{$attrs || {}}, _resultset => undef }, $class);
+
+  my $new = { %{$attrs || {}}, _resultset => undef };
+  bless $new, $class;
+
   $new->{resultset_class} ||= 'DBIx::Class::ResultSet';
   $new->{resultset_attributes} = { %{$new->{resultset_attributes} || {}} };
   $new->{_ordered_columns} = [ @{$new->{_ordered_columns}||[]}];
index 591927f..c1d6164 100644 (file)
@@ -8,6 +8,7 @@ use base qw/DBIx::Class/;
 
 sub iterator_class  { shift->result_source_instance->resultset_class(@_) }
 sub resultset_class { shift->result_source_instance->resultset_class(@_) }
+sub result_class { shift->result_source_instance->result_class(@_) }
 sub source_name { shift->result_source_instance->source_name(@_) }
 
 sub resultset_attributes {
@@ -26,13 +27,11 @@ sub add_columns {
 *add_column = \&add_columns;
 
 sub has_column {
-  my ($self, $column) = @_;
-  return $self->result_source_instance->has_column($column);
+  shift->result_source_instance->has_column(@_);
 }
 
 sub column_info {
-  my ($self, $column) = @_;
-  return $self->result_source_instance->column_info($column);
+  shift->result_source_instance->column_info(@_);
 }
 
 sub load_column_info_from_storage {
@@ -40,11 +39,11 @@ sub load_column_info_from_storage {
 }
 
 sub columns {
-  return shift->result_source_instance->columns(@_);
+  shift->result_source_instance->columns(@_);
 }
 
 sub remove_columns {
-  return shift->result_source_instance->remove_columns(@_);
+  shift->result_source_instance->remove_columns(@_);
 }
 
 *remove_column = \&remove_columns;
index 3efe418..ceed5a6 100644 (file)
@@ -34,7 +34,10 @@ Creates a new row object from column => value mappings passed as a hash ref
 sub new {
   my ($class, $attrs) = @_;
   $class = ref $class if ref $class;
-  my $new = bless { _column_data => {} }, $class;
+
+  my $new = { _column_data => {} };
+  bless $new, $class;
+
   if ($attrs) {
     $new->throw_exception("attrs must be a hashref")
       unless ref($attrs) eq 'HASH';
@@ -44,6 +47,7 @@ sub new {
       $new->store_column($k => $attrs->{$k});
     }
   }
+
   return $new;
 }
 
@@ -265,7 +269,10 @@ sub copy {
     delete $col_data->{$col}
       if $self->result_source->column_info($col)->{is_auto_increment};
   }
-  my $new = bless { _column_data => $col_data }, ref $self;
+
+  my $new = { _column_data => $col_data };
+  bless $new, ref $self;
+
   $new->result_source($self->result_source);
   $new->set_columns($changes);
   $new->insert;
@@ -310,11 +317,13 @@ Called by ResultSet to inflate a result from storage
 sub inflate_result {
   my ($class, $source, $me, $prefetch) = @_;
   #use Data::Dumper; print Dumper(@_);
-  my $new = bless({ result_source => $source,
-                    _column_data => $me,
-                    _in_storage => 1
-                  },
-                  ref $class || $class);
+  my $new = {
+    result_source => $source,
+    _column_data => $me,
+    _in_storage => 1
+  };
+  bless $new, (ref $class || $class);
+
   my $schema;
   foreach my $pre (keys %{$prefetch||{}}) {
     my $pre_val = $prefetch->{$pre};
index 9357566..3641f3c 100644 (file)
@@ -626,7 +626,9 @@ copy.
 
 sub clone {
   my ($self) = @_;
-  my $clone = bless({ (ref $self ? %$self : ()) }, ref $self || $self);
+  my $clone = { (ref $self ? %$self : ()) };
+  bless $clone, (ref $self || $self);
+
   foreach my $moniker ($self->sources) {
     my $source = $self->source($moniker);
     my $new = $source->new($source);
index 86b3a89..2efc930 100644 (file)
@@ -36,7 +36,8 @@ use overload '"' => sub {
 
 sub new {
   my $class = shift;
-  return bless {}, $class;
+  my $self = {};
+  return bless $self, $class;
 }
 
 1;
index dff783b..22aa2c1 100644 (file)
@@ -280,8 +280,8 @@ Constructor.  Only argument is the schema which instantiated us.
 sub new {
   my ($self, $schema) = @_;
 
-  my $new = bless({}, ref $self || $self);
-
+  my $new = {};
+  bless $new, (ref $_[0] || $_[0]);
   $new->set_schema($schema);
   $new->cursor("DBIx::Class::Storage::DBI::Cursor");
   $new->transaction_depth(0);
index 0599ed6..eaa3ee9 100644 (file)
@@ -30,7 +30,8 @@ Returns a new L<DBIx::Class::Storage::Statistics> object.
 
 =cut
 sub new {
-    my $self = bless({}, ref($_[0]) || $_[0]);
+    my $self = {};
+    bless $self, (ref($_[0]) || $_[0]);
 
     return $self;
 }
index 9c03fc4..eebb66e 100644 (file)
@@ -7,7 +7,7 @@ use DBICTest;
 
 my $schema = DBICTest->init_schema();
 
-plan tests => 39;
+plan tests => 43;
 
 # Check the defined unique constraints
 is_deeply(
@@ -151,3 +151,17 @@ my $track = $schema->resultset('Track')->find(
 
 is($track->get_column('cd'), 1, 'track cd is correct');
 is($track->get_column('position'), 3, 'track position is correct');
+
+# Test a table with a unique constraint but no primary key
+my $row = $schema->resultset('NoPrimaryKey')->update_or_create(
+  {
+    foo => 1,
+    bar => 2,
+    baz => 3,
+  },
+  { key => 'foo_bar' }
+);
+ok(! $row->is_changed, 'update_or_create on table without primary key: row is clean');
+is($row->foo, 1, 'foo is correct');
+is($row->bar, 2, 'bar is correct');
+is($row->baz, 3, 'baz is correct');
index 7c265dc..8e7597d 100644 (file)
@@ -33,7 +33,7 @@ __PACKAGE__->load_classes(qw/
     'Producer',
     'CD_to_Producer',
   ),
-  qw/SelfRefAlias TreeLike TwoKeyTreeLike Event/
+  qw/SelfRefAlias TreeLike TwoKeyTreeLike Event NoPrimaryKey/
 );
 
 1;
diff --git a/t/lib/DBICTest/Schema/NoPrimaryKey.pm b/t/lib/DBICTest/Schema/NoPrimaryKey.pm
new file mode 100644 (file)
index 0000000..1723390
--- /dev/null
@@ -0,0 +1,15 @@
+package # hide from PAUSE 
+    DBICTest::Schema::NoPrimaryKey;
+
+use base 'DBIx::Class::Core';
+
+DBICTest::Schema::NoPrimaryKey->table('noprimarykey');
+DBICTest::Schema::NoPrimaryKey->add_columns(
+  'foo' => { data_type => 'integer' },
+  'bar' => { data_type => 'integer' },
+  'baz' => { data_type => 'integer' },
+);
+
+DBICTest::Schema::NoPrimaryKey->add_unique_constraint(foo_bar => [ qw/foo bar/ ]);
+
+1;
index db76e3b..fd50c36 100644 (file)
@@ -164,6 +164,15 @@ CREATE TABLE twokeys (
 );
 
 --
+-- Table: noprimarykey
+--
+CREATE TABLE noprimarykey (
+  foo integer NOT NULL,
+  bar integer NOT NULL,
+  baz integer NOT NULL
+);
+
+--
 -- Table: fourkeys
 --
 CREATE TABLE fourkeys (
@@ -205,5 +214,6 @@ CREATE UNIQUE INDEX tktlnameunique_twokeytreelike on twokeytreelike (name);
 CREATE UNIQUE INDEX cd_artist_title_cd on cd (artist, title);
 CREATE UNIQUE INDEX track_cd_position_track on track (cd, position);
 CREATE UNIQUE INDEX track_cd_title_track on track (cd, title);
+CREATE UNIQUE INDEX foo_bar_noprimarykey on noprimarykey (foo, bar);
 CREATE UNIQUE INDEX prod_name_producer on producer (name);
 COMMIT;