X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FRow.pm;h=39cd754c7665cce780d9f37d6e1a7b702bb93c5d;hb=52864fbd5c6035f8f3961173ad05c2cc58fe9a34;hp=a5f7eaa114a4991fdaa12d45b8458582e1bc7c04;hpb=0c11ad0ee5c8407f6b87d6e15c62a1b445076dc0;p=dbsrgits%2FDBIx-Class.git diff --git a/lib/DBIx/Class/Row.pm b/lib/DBIx/Class/Row.pm index a5f7eaa..39cd754 100644 --- a/lib/DBIx/Class/Row.pm +++ b/lib/DBIx/Class/Row.pm @@ -5,7 +5,6 @@ use warnings; use base qw/DBIx::Class/; -use DBIx::Class::Exception; use Scalar::Util 'blessed'; use List::Util 'first'; use Try::Tiny; @@ -23,6 +22,8 @@ BEGIN { use namespace::clean; +__PACKAGE__->mk_group_accessors ( simple => [ in_storage => '_in_storage' ] ); + =head1 NAME DBIx::Class::Row - Basic row methods @@ -34,14 +35,31 @@ DBIx::Class::Row - Basic row methods This class is responsible for defining and doing basic operations on rows derived from L objects. -Row objects are returned from Ls using the +Result objects are returned from Ls using the L, L, L and L methods, as well as invocations of 'single' ( L, L or L) -relationship accessors of L objects. +relationship accessors of L objects. + +=head1 NOTE + +All "Row objects" derived from a Schema-attached L +object (such as a typical C<< L->L >> call) are actually Result +instances, based on your application's +L. + +L implements most of the row-based communication with the +underlying storage, but a Result class B. +Usually, Result classes inherit from L, which in turn +combines the methods from several classes, one of them being +L. Therefore, while many of the methods available to a +L-derived Result class are described in the following +documentation, it does not detail all of the methods available to Result +objects. Refer to L for more info. =head1 METHODS @@ -55,11 +73,11 @@ relationship accessors of L objects. =item Arguments: \%attrs or \%colsandvalues -=item Returns: A Row object +=item Return Value: L<$result|DBIx::Class::Manual::ResultClass> =back -While you can create a new row object by calling C directly on +While you can create a new result object by calling C directly on this class, you are better off calling it on a L object. @@ -160,7 +178,7 @@ sub new { my ($class, $attrs) = @_; $class = ref $class if ref $class; - my $new = bless { _column_data => {} }, $class; + my $new = bless { _column_data => {}, _in_storage => 0 }, $class; if ($attrs) { $new->throw_exception("attrs must be a hashref") @@ -243,7 +261,7 @@ sub new { next; } } - $new->throw_exception("No such column $key on $class") + $new->throw_exception("No such column '$key' on $class") unless $class->has_column($key); $new->store_column($key => $attrs->{$key}); } @@ -255,6 +273,42 @@ sub new { return $new; } +=head2 $column_accessor + + # Each pair does the same thing + + # (un-inflated, regular column) + my $val = $row->get_column('first_name'); + my $val = $row->first_name; + + $row->set_column('first_name' => $val); + $row->first_name($val); + + # (inflated column via DBIx::Class::InflateColumn::DateTime) + my $val = $row->get_inflated_column('last_modified'); + my $val = $row->last_modified; + + $row->set_inflated_column('last_modified' => $val); + $row->last_modified($val); + +=over + +=item Arguments: $value? + +=item Return Value: $value + +=back + +A column accessor method is created for each column, which is used for +getting/setting the value for that column. + +The actual method name is based on the +L name given during the +L L. Like L, this +will not store the data in the database until L or L +is called on the row. + =head2 insert $row->insert; @@ -263,7 +317,7 @@ sub new { =item Arguments: none -=item Returns: The Row object +=item Return Value: L<$result|DBIx::Class::Manual::ResultClass> =back @@ -271,8 +325,8 @@ Inserts an object previously created by L into the database if it isn't already in there. Returns the object itself. To insert an entirely new row into the database, use L. -To fetch an uninserted row object, call -L on a resultset. +To fetch an uninserted result object, call +L on a resultset. This will also insert any uninserted, related objects held inside this one, see L for more details. @@ -416,7 +470,7 @@ sub insert { =item Arguments: none or 1|0 -=item Returns: 1|0 +=item Return Value: 1|0 =back @@ -425,16 +479,9 @@ not. This is set to true when L, L or L are used. -Creating a row object using L, or calling -L on one, sets it to false. +Creating a result object using L, or +calling L on one, sets it to false. -=cut - -sub in_storage { - my ($self, $val) = @_; - $self->{_in_storage} = $val if @_ > 1; - return $self->{_in_storage} ? 1 : 0; -} =head2 update @@ -444,11 +491,11 @@ sub in_storage { =item Arguments: none or a hashref -=item Returns: The Row object +=item Return Value: L<$result|DBIx::Class::Manual::ResultClass> =back -Throws an exception if the row object is not yet in the database, +Throws an exception if the result object is not yet in the database, according to L. This method issues an SQL UPDATE query to commit any changes to the @@ -473,7 +520,7 @@ contain scalar references, e.g.: $row->update({ last_modified => \'NOW()' }); The update will pass the values verbatim into SQL. (See -L docs). The values in your Row object will NOT change +L docs). The values in your Result object will NOT change as a result of the update call, if you want the object to be updated with the actual values from the database, call L after the update. @@ -522,7 +569,7 @@ sub update { =item Arguments: none -=item Returns: The Row object +=item Return Value: L<$result|DBIx::Class::Manual::ResultClass> =back @@ -546,7 +593,7 @@ main row first> and only then attempts to delete any remaining related rows. If you delete an object within a txn_do() (see L) -and the transaction subsequently fails, the row object will remain marked as +and the transaction subsequently fails, the result object will remain marked as not being in storage. If you know for a fact that the object is still in storage (i.e. by inspecting the cause of the transaction's failure), you can use C<< $obj->in_storage(1) >> to restore consistency between the object and @@ -567,7 +614,7 @@ sub delete { ); delete $self->{_column_data_in_storage}; - $self->in_storage(undef); + $self->in_storage(0); } else { my $rsrc = try { $self->result_source_instance } @@ -588,14 +635,14 @@ sub delete { =item Arguments: $columnname -=item Returns: The value of the column +=item Return Value: The value of the column =back Throws an exception if the column name given doesn't exist according to L. -Returns a raw column value from the row object, if it has already +Returns a raw column value from the result object, if it has already been fetched from the database or set by an accessor. If an L has been set, it @@ -632,7 +679,7 @@ sub get_column { =item Arguments: $columnname -=item Returns: 0|1 +=item Return Value: 0|1 =back @@ -656,7 +703,7 @@ sub has_column_loaded { =item Arguments: none -=item Returns: A hash of columnname, value pairs. +=item Return Value: A hash of columnname, value pairs. =back @@ -686,7 +733,7 @@ sub get_columns { =item Arguments: none -=item Returns: A hash of column, value pairs +=item Return Value: A hash of column, value pairs =back @@ -711,7 +758,7 @@ sub get_dirty_columns { =item Arguments: $columnname -=item Returns: undefined +=item Return Value: not defined =back @@ -721,6 +768,7 @@ Marks a column as having been changed regardless of whether it has really changed. =cut + sub make_column_dirty { my ($self, $column) = @_; @@ -751,7 +799,7 @@ sub make_column_dirty { =item Arguments: none -=item Returns: A hash of column, object|value pairs +=item Return Value: A hash of column, object|value pairs =back @@ -814,7 +862,7 @@ sub _is_column_numeric { =item Arguments: $columnname, $value -=item Returns: $value +=item Return Value: $value =back @@ -824,7 +872,7 @@ the column is marked as dirty for when you next call L. If passed an object or reference as a value, this method will happily attempt to store it, and a later L or L will try and stringify/numify as appropriate. To set an object to be deflated -instead, see L. +instead, see L, or better yet, use L. =cut @@ -924,7 +972,7 @@ sub _track_storage_value { =item Arguments: \%columndata -=item Returns: The Row object +=item Return Value: L<$result|DBIx::Class::Manual::ResultClass> =back @@ -950,16 +998,16 @@ sub set_columns { =item Arguments: \%columndata -=item Returns: The Row object +=item Return Value: L<$result|DBIx::Class::Manual::ResultClass> =back Sets more than one column value at once. Any inflated values are deflated and the raw values stored. -Any related values passed as Row objects, using the relation name as a +Any related values passed as Result objects, using the relation name as a key, are reduced to the appropriate foreign key values and stored. If -instead of related row objects, a hashref of column, value data is +instead of related result objects, a hashref of column, value data is passed, will create the related object first then store. Will even accept arrayrefs of data as a value to a @@ -1007,7 +1055,7 @@ sub set_inflated_columns { =item Arguments: \%replacementdata -=item Returns: The Row object copy +=item Return Value: L<$result|DBIx::Class::Manual::ResultClass> copy =back @@ -1078,7 +1126,7 @@ sub copy { =item Arguments: $columnname, $value -=item Returns: The value sent to storage +=item Return Value: The value sent to storage =back @@ -1086,7 +1134,7 @@ Set a raw value for a column without marking it as changed. This method is used internally by L which you should probably be using. -This is the lowest level at which data is set on a row object, +This is the lowest level at which data is set on a result object, extend this method to catch all data setting methods. =cut @@ -1106,14 +1154,14 @@ sub store_column { =over -=item Arguments: $result_source, \%columndata, \%prefetcheddata +=item Arguments: L<$result_source|DBIx::Class::ResultSource>, \%columndata, \%prefetcheddata -=item Returns: A Row object +=item Return Value: L<$result|DBIx::Class::Manual::ResultClass> =back All L methods that retrieve data from the -database and turn it into row objects call this method. +database and turn it into result objects call this method. Extend this method in your Result classes to hook into this process, for example to rebless the result into a different class. @@ -1129,76 +1177,39 @@ L, see L. sub inflate_result { my ($class, $source, $me, $prefetch) = @_; - $source = $source->resolve - if $source->isa('DBIx::Class::ResultSourceHandle'); - my $new = bless { _column_data => $me, _result_source => $source }, ref $class || $class ; - foreach my $pre (keys %{$prefetch||{}}) { - - my (@pre_vals, $is_multi); - if (ref $prefetch->{$pre}[0] eq 'ARRAY') { - $is_multi = 1; - @pre_vals = @{$prefetch->{$pre}}; - } - else { - @pre_vals = $prefetch->{$pre}; - } + if ($prefetch) { + for my $pre ( keys %$prefetch ) { - my $pre_source = try { - $source->related_source($pre) - } - catch { - $class->throw_exception(sprintf - - "Can't inflate manual prefetch into non-existent relationship '%s' from '%s', " - . "check the inflation specification (columns/as) ending in '%s.%s'.", - - $pre, - $source->source_name, - $pre, - (keys %{$pre_vals[0][0]})[0] || 'something.something...', - ); - }; - - my $accessor = $source->relationship_info($pre)->{attrs}{accessor} - or $class->throw_exception("No accessor type declared for prefetched $pre"); + my @pre_objects; + if ( + @{$prefetch->{$pre}||[]} + and + ref($prefetch->{$pre}) ne $DBIx::Class::ResultSource::RowParser::Util::null_branch_class + ) { + my $pre_source = $source->related_source($pre); - if (! $is_multi and $accessor eq 'multi') { - $class->throw_exception("Manual prefetch (via select/columns) not supported with accessor 'multi'"); - } + @pre_objects = map { + $pre_source->result_class->inflate_result( $pre_source, @$_ ) + } ( ref $prefetch->{$pre}[0] eq 'ARRAY' ? @{$prefetch->{$pre}} : $prefetch->{$pre} ); + } - my @pre_objects; - for my $me_pref (@pre_vals) { - - # FIXME - this should not be necessary - # the collapser currently *could* return bogus elements with all - # columns set to undef - my $has_def; - for (values %{$me_pref->[0]}) { - if (defined $_) { - $has_def++; - last; - } - } - next unless $has_def; + my $accessor = $source->relationship_info($pre)->{attrs}{accessor} + or $class->throw_exception("No accessor type declared for prefetched relationship '$pre'"); - push @pre_objects, $pre_source->result_class->inflate_result( - $pre_source, @$me_pref - ); - } + if ($accessor eq 'single') { + $new->{_relationship_data}{$pre} = $pre_objects[0]; + } + elsif ($accessor eq 'filter') { + $new->{_inflated_column}{$pre} = $pre_objects[0]; + } - if ($accessor eq 'single') { - $new->{_relationship_data}{$pre} = $pre_objects[0]; + $new->related_resultset($pre)->set_cache(\@pre_objects); } - elsif ($accessor eq 'filter') { - $new->{_inflated_column}{$pre} = $pre_objects[0]; - } - - $new->related_resultset($pre)->set_cache(\@pre_objects); } $new->in_storage (1); @@ -1213,7 +1224,7 @@ sub inflate_result { =item Arguments: none -=item Returns: Result of update or insert operation +=item Return Value: Result of update or insert operation =back @@ -1244,7 +1255,7 @@ sub update_or_insert { =item Arguments: none -=item Returns: 0|1 or @columnnames +=item Return Value: 0|1 or @columnnames =back @@ -1266,7 +1277,7 @@ sub is_changed { =item Arguments: $columname -=item Returns: 0|1 +=item Return Value: 0|1 =back @@ -1285,9 +1296,9 @@ sub is_column_changed { =over -=item Arguments: $result_source_instance +=item Arguments: L<$result_source?|DBIx::Class::ResultSource> -=item Returns: a ResultSource instance +=item Return Value: L<$result_source|DBIx::Class::ResultSource> =back @@ -1323,7 +1334,7 @@ sub result_source { =item Arguments: $columnname, \%columninfo -=item Returns: undefined +=item Return Value: not defined =back @@ -1354,11 +1365,11 @@ sub register_column { =item Arguments: \%attrs -=item Returns: A Row object +=item Return Value: A Result object =back -Fetches a fresh copy of the Row object from the database and returns it. +Fetches a fresh copy of the Result object from the database and returns it. Throws an exception if a proper WHERE clause identifying the database row can not be constructed (i.e. if the original object does not contain its entire @@ -1366,11 +1377,11 @@ entire ). If passed the \%attrs argument, will first apply these attributes to the resultset used to find the row. -This copy can then be used to compare to an existing row object, to +This copy can then be used to compare to an existing result object, to determine if any changes have been made in the database since it was created. -To just update your Row object with any latest changes from the +To just update your Result object with any latest changes from the database, use L instead. The \%attrs argument should be compatible with @@ -1390,7 +1401,7 @@ sub get_from_storage { return $resultset->find($self->_storage_ident_condition); } -=head2 discard_changes ($attrs?) +=head2 discard_changes $row->discard_changes @@ -1398,7 +1409,7 @@ sub get_from_storage { =item Arguments: none or $attrs -=item Returns: self (updates object in-place) +=item Return Value: self (updates object in-place) =back