X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FRow.pm;h=d2def31b63e6a6bcda8db3dc5c4d48da37d74ef8;hb=9c0df5f32b68e23c670c89ce6cdbff60b4bd0ed0;hp=00bd0a2d5429f48678d96c8cbc24cc308c703bf3;hpb=04dac7a4cc70864592dfdb0989073c0c964788f5;p=dbsrgits%2FDBIx-Class.git diff --git a/lib/DBIx/Class/Row.pm b/lib/DBIx/Class/Row.pm index 00bd0a2..d2def31 100644 --- a/lib/DBIx/Class/Row.pm +++ b/lib/DBIx/Class/Row.pm @@ -50,7 +50,9 @@ sub new { my ($class, $attrs) = @_; $class = ref $class if ref $class; - my $new = { _column_data => {} }; + my $new = { + _column_data => {}, + }; bless $new, $class; if (my $handle = delete $attrs->{-source_handle}) { @@ -138,6 +140,9 @@ be set, or the class to have a result_source_instance method. To insert an entirely new object into the database, use C (see L). +To fetch an uninserted row object, call +L on a resultset. + This will also insert any uninserted, related objects held inside this one, see L for more details. @@ -159,11 +164,9 @@ sub insert { %{$self->{_inflated_column} || {}}); if(!$self->{_rel_in_storage}) { - $source->storage->txn_begin; # The guard will save us if we blow out of this scope via die - - $rollback_guard = Scope::Guard->new(sub { $source->storage->txn_rollback }); + $rollback_guard = $source->storage->txn_scope_guard; ## Should all be in relationship_data, but we need to get rid of the ## 'filter' reltype.. @@ -206,7 +209,8 @@ sub insert { } } - $source->storage->insert($source, { $self->get_columns }); + my $updated_cols = $source->storage->insert($source, { $self->get_columns }); + $self->set_columns($updated_cols); ## PK::Auto my @auto_pri = grep { @@ -246,8 +250,7 @@ sub insert { } } } - $source->storage->txn_commit; - $rollback_guard->dismiss; + $rollback_guard->commit; } $self->in_storage(1); @@ -262,7 +265,13 @@ sub insert { $obj->in_storage; # Get value $obj->in_storage(1); # Set value -Indicates whether the object exists as a row in the database or not +Indicates whether the object exists as a row in the database or +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. =cut @@ -281,9 +290,10 @@ UPDATE query to commit any changes to the object to the database if required. Also takes an options hashref of C<< column_name => value> pairs >> to update -first. But be aware that this hashref might be edited in place, so dont rely on -it being the same after a call to C. If you need to preserve the hashref, -it is sufficient to pass a shallow copy to C, e.g. ( { %{ $href } } ) +first. But be aware that the hashref will be passed to +C, which might edit it in place, so dont rely on it being +the same after a call to C. If you need to preserve the hashref, it is +sufficient to pass a shallow copy to C, e.g. ( { %{ $href } } ) =cut @@ -294,38 +304,7 @@ sub update { $self->throw_exception("Cannot safely update a row in a PK-less table") if ! keys %$ident_cond; - if ($upd) { - foreach my $key (keys %$upd) { - if (ref $upd->{$key}) { - my $info = $self->relationship_info($key); - if ($info && $info->{attrs}{accessor} - && $info->{attrs}{accessor} eq 'single') - { - my $rel = delete $upd->{$key}; - $self->set_from_related($key => $rel); - $self->{_relationship_data}{$key} = $rel; - } elsif ($info && $info->{attrs}{accessor} - && $info->{attrs}{accessor} eq 'multi' - && ref $upd->{$key} eq 'ARRAY') { - my $others = delete $upd->{$key}; - foreach my $rel_obj (@$others) { - if(!Scalar::Util::blessed($rel_obj)) { - $rel_obj = $self->create_related($key, $rel_obj); - } - } - $self->{_relationship_data}{$key} = $others; -# $related->{$key} = $others; - next; - } - elsif ($self->has_column($key) - && exists $self->column_info($key)->{_inflate_info}) - { - $self->set_inflated_column($key, delete $upd->{$key}); - } - } - } - $self->set_columns($upd); - } + $self->set_inflated_columns($upd) if $upd; my %to_update = $self->get_dirty_columns; return $self unless keys %to_update; my $rows = $self->result_source->storage->update( @@ -352,7 +331,7 @@ usable, but C<< ->in_storage() >> will now return 0 and the object must reinserted using C<< ->insert() >> before C<< ->update() >> can be used on it. If you delete an object in a class with a C relationship, all the related objects will be deleted as well. To turn -this behavior off, pass C 0> in the C<$attr> +this behavior off, pass C<< cascade_delete => 0 >> in the C<$attr> hashref. Any database-level cascade or restrict will take precedence over a DBIx-Class-based cascading delete. See also L. @@ -386,10 +365,11 @@ sub delete { my $val = $obj->get_column($col); -Gets a column value from a row object. Does not do any queries; the column -must have already been fetched from the database and stored in the object. If -there is an inflated value stored that has not yet been deflated, it is deflated -when the method is invoked. +Returns a raw column value from the row object, if it has already +been fetched from the database or set by an accessor. + +If an L has been set, it +will be deflated and returned. =cut @@ -427,7 +407,7 @@ sub has_column_loaded { my %data = $obj->get_columns; -Does C, for all column values at once. +Does C, for all loaded column values at once. =cut @@ -458,9 +438,10 @@ sub get_dirty_columns { =head2 get_inflated_columns - my $inflated_data = $obj->get_inflated_columns; + my %inflated_data = $obj->get_inflated_columns; -Similar to get_columns but objects are returned for inflated columns instead of their raw non-inflated values. +Similar to get_columns but objects are returned for inflated columns +instead of their raw non-inflated values. =cut @@ -476,9 +457,13 @@ sub get_inflated_columns { $obj->set_column($col => $val); -Sets a column value. If the new value is different from the old one, +Sets a raw column value. If the new value is different from the old one, the column is marked as dirty for when you next call $obj->update. +If passed an object or reference, this will happily attempt store the +value, and a later insert/update will try and stringify/numify as +appropriate. + =cut sub set_column { @@ -488,7 +473,11 @@ sub set_column { my $old = $self->get_column($column); my $ret = $self->store_column(@_); $self->{_dirty_columns}{$column} = 1 - if (defined $old ^ defined $ret) || (defined $old && $old ne $ret); + if (defined $old xor defined $ret) || (defined $old && $old ne $ret); + + # XXX clear out the relation cache for this column + delete $self->{related_resultsets}{$column}; + return $ret; } @@ -508,11 +497,59 @@ sub set_columns { return $self; } +=head2 set_inflated_columns + + my $copy = $orig->set_inflated_columns({ $col => $val, $rel => $obj, ... }); + +Sets more than one column value at once, taking care to respect inflations and +relationships if relevant. Be aware that this hashref might be edited in place, +so dont rely on it being the same after a call to C. If +you need to preserve the hashref, it is sufficient to pass a shallow copy to +C, e.g. ( { %{ $href } } ) + +=cut + +sub set_inflated_columns { + my ( $self, $upd ) = @_; + foreach my $key (keys %$upd) { + if (ref $upd->{$key}) { + my $info = $self->relationship_info($key); + if ($info && $info->{attrs}{accessor} + && $info->{attrs}{accessor} eq 'single') + { + my $rel = delete $upd->{$key}; + $self->set_from_related($key => $rel); + $self->{_relationship_data}{$key} = $rel; + } elsif ($info && $info->{attrs}{accessor} + && $info->{attrs}{accessor} eq 'multi' + && ref $upd->{$key} eq 'ARRAY') { + my $others = delete $upd->{$key}; + foreach my $rel_obj (@$others) { + if(!Scalar::Util::blessed($rel_obj)) { + $rel_obj = $self->create_related($key, $rel_obj); + } + } + $self->{_relationship_data}{$key} = $others; +# $related->{$key} = $others; + next; + } + elsif ($self->has_column($key) + && exists $self->column_info($key)->{_inflate_info}) + { + $self->set_inflated_column($key, delete $upd->{$key}); + } + } + } + $self->set_columns($upd); +} + =head2 copy my $copy = $orig->copy({ change => $to, ... }); -Inserts a new row with the specified changes. +Inserts a new row with the specified changes. If the row has related +objects in a C then those objects may be copied too depending +on the C relationship attribute. =cut @@ -529,7 +566,7 @@ sub copy { bless $new, ref $self; $new->result_source($self->result_source); - $new->set_columns($changes); + $new->set_inflated_columns($changes); $new->insert; # Its possible we'll have 2 relations to the same Source. We need to make @@ -646,7 +683,8 @@ sub inflate_result { $obj->update_or_insert -Updates the object if it's already in the db, else inserts it. +Updates the object if it's already in the database, according to +L, else inserts it. =head2 insert_or_update @@ -748,6 +786,22 @@ sub throw_exception { } } +=head2 id + +Returns the primary key(s) for a row. Can't be called as a class method. +Actually implemented in L + +=head2 discard_changes + +Re-selects the row from the database, losing any changes that had +been made. + +This method can also be used to refresh from storage, retrieving any +changes made since the row was last read from storage. Actually +implemented in L + +=cut + 1; =head1 AUTHORS