DBIO

 view release on metacpan or  search on metacpan

lib/DBIO/Row.pm  view on Meta::CPAN

      $rsrc ||= $self->result_source;
      my $info = $rsrc->relationship_info($key);
      my $acc_type = $info->{attrs}{accessor} || '';

      if ($acc_type eq 'single') {
        my $rel_obj = delete $upd->{$key};
        $self->set_from_related($key => $rel_obj);
        $self->{_relationship_data}{$key} = $rel_obj;
      }
      elsif ($acc_type eq 'multi') {
        $self->throw_exception(
          "Recursive update is not supported over relationships of type '$acc_type' ($key)"
        );
      }
      elsif (
        $rsrc->has_column($key)
          and
        exists $rsrc->column_info($key)->{_inflate_info}
      ) {
        $self->set_inflated_column($key, delete $upd->{$key});
      }
    }
  }
  $self->set_columns($upd);
}


sub copy {
  my ($self, $changes) = @_;

  # ProxyResultSetMethod (integrated helper): proxied values are not
  # real columns and must not be carried into the copy.
  delete local @{$self->{_column_data}}{@{$self->_proxy_slots||[]}};

  $changes ||= {};
  my $col_data = { $self->get_columns };

  my $rsrc = $self->result_source;

  my $colinfo = $rsrc->columns_info;
  foreach my $col (keys %$col_data) {
    delete $col_data->{$col}
      if ( ! $colinfo->{$col} or $colinfo->{$col}{is_auto_increment} );
  }

  my $new = { _column_data => $col_data };
  bless $new, ref $self;

  $new->result_source($rsrc);
  $new->set_inflated_columns($changes);
  $new->insert;

  # Its possible we'll have 2 relations to the same Source. We need to make
  # sure we don't try to insert the same row twice else we'll violate unique
  # constraints
  my $rel_names_copied = {};

  foreach my $rel_name ($rsrc->relationships) {
    my $rel_info = $rsrc->relationship_info($rel_name);

    next unless $rel_info->{attrs}{cascade_copy};

    my $resolved = $rsrc->_resolve_condition(
      $rel_info->{cond}, $rel_name, $new, $rel_name
    );

    my $copied = $rel_names_copied->{ $rel_info->{source} } ||= {};
    foreach my $related ($self->search_related($rel_name)->all) {
      $related->copy($resolved)
        unless $copied->{$related->ID}++;
    }

  }
  return $new;
}


sub store_column {
  my ($self, $column, $value) = @_;
  $self->throw_exception( "No such column '${column}' on " . ref $self )
    unless exists $self->{_column_data}{$column} || $self->result_source->has_column($column);
  $self->throw_exception( "set_column called for ${column} without value" )
    if @_ < 3;
  return $self->{_column_data}{$column} = $value;
}


sub inflate_result {
  my ($class, $rsrc, $me, $prefetch) = @_;

  my $new = bless
    { _column_data => $me, _result_source => $rsrc },
    ref $class || $class
  ;

  if ($prefetch) {
    for my $rel_name ( keys %$prefetch ) {

      my $relinfo = $rsrc->relationship_info($rel_name) or do {
        my $err = sprintf
          "Inflation into non-existent relationship '%s' of '%s' requested",
          $rel_name,
          $rsrc->source_name,
        ;
        if (my ($colname) = sort { length($a) <=> length ($b) } keys %{$prefetch->{$rel_name}[0] || {}} ) {
          $err .= sprintf ", check the inflation specification (columns/as) ending in '...%s.%s'",
          $rel_name,
          $colname,
        }

        $rsrc->throw_exception($err);
      };

      $class->throw_exception("No accessor type declared for prefetched relationship '$rel_name'")
        unless $relinfo->{attrs}{accessor};

      my $rel_rs = $new->related_resultset($rel_name);

      my @rel_objects;
      if (
        @{ $prefetch->{$rel_name} || [] }

lib/DBIO/Row.pm  view on Meta::CPAN

object to the database if required (see L</get_dirty_columns>).
It throws an exception if a proper WHERE clause uniquely identifying
the database row can not be constructed (see
L<significance of primary keys|DBIO::Manual::Intro/The Significance and Importance of Primary Keys>
for more details).

Also takes an optional hashref of C<< column_name => value >> pairs
to update on the object first. Be aware that the hashref will be
passed to C<set_inflated_columns>, which might edit it in place, so
don't rely on it being the same after a call to C<update>.  If you
need to preserve the hashref, it is sufficient to pass a shallow copy
to C<update>, e.g. ( { %{ $href } } )

If the values passed or any of the column values set on the object
contain scalar references, e.g.:

  $result->last_modified(\'NOW()')->update();
  # OR
  $result->update({ last_modified => \'NOW()' });

The update will pass the values verbatim into SQL. (See
L<SQL::Abstract> 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</discard_changes> after the
update.

  $result->update()->discard_changes();

To determine before calling this method, which column values have
changed and will be updated, call L</get_dirty_columns>.

To check if any columns will be updated, call L</is_changed>.

To force a column to be updated, call L</make_column_dirty> before
this method.

=head2 delete

  $result->delete

=over

=item Arguments: none

=item Return Value: L<$result|DBIO::Manual::ResultClass>

=back

Throws an exception if the object is not in the database according to
L</in_storage>. Also throws an exception if a proper WHERE clause
uniquely identifying the database row can not be constructed (see
L<significance of primary keys|DBIO::Manual::Intro/The Significance and Importance of Primary Keys>
for more details).

The object is still perfectly usable, but L</in_storage> will
now return 0 and the object must be reinserted using L</insert>
before it can be used to L</update> the row again.

If you delete an object in a class with a C<has_many> relationship, an
attempt is made to delete all the related objects as well. To turn
this behaviour off, pass C<< cascade_delete => 0 >> in the C<$attr>
hashref of the relationship, see L<DBIO::Relationship>. Any
database-level cascade or restrict will take precedence over a
DBIO-based cascading delete, since DBIO B<deletes the
main row first> and only then attempts to delete any remaining related
rows.

If you delete an object within a txn_do() (see L<DBIO::Storage/txn_do>)
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
the database. This would allow a subsequent C<< $obj->delete >> to work
as expected.

See also L<DBIO::ResultSet/delete>.

=head2 get_column

  my $val = $result->get_column($col);

=over

=item Arguments: $columnname

=item Return Value: The value of the column

=back

Throws an exception if the column name given doesn't exist according
to L<has_column|DBIO::ResultSource/has_column>.

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<inflated value|DBIO::InflateColumn> has been set, it
will be deflated and returned.

Note that if you used the C<columns> or the C<select/as>
L<search attributes|DBIO::ResultSet/ATTRIBUTES> on the resultset from
which C<$result> was derived, and B<did not include> C<$columnname> in the list,
this method will return C<undef> even if the database contains some value.

To retrieve all loaded column values as a hash, use L</get_columns>.

=head2 has_column_loaded

  if ( $result->has_column_loaded($col) ) {
     print "$col has been loaded from db";
  }

=over

=item Arguments: $columnname

=item Return Value: 0|1

=back

Returns a true value if the column value has been loaded from the
database (or set locally).

=head2 get_columns

lib/DBIO/Row.pm  view on Meta::CPAN


=back

Sets multiple column, raw value pairs at once.

Works as L</set_column>.

=head2 set_inflated_columns

  $result->set_inflated_columns({ $col => $val, $rel_name => $obj, ... });

=over

=item Arguments: \%columndata

=item Return Value: L<$result|DBIO::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 Result objects, using the relation name as a
key, are reduced to the appropriate foreign key values and stored. If
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
L<DBIO::Relationship/has_many> key, and create the related
objects if necessary.

Be aware that the input hashref might be edited in place, so don't rely
on it being the same after a call to C<set_inflated_columns>. If you
need to preserve the hashref, it is sufficient to pass a shallow copy
to C<set_inflated_columns>, e.g. ( { %{ $href } } )

See also L<DBIO::Relationship::Base/set_from_related>.

=head2 copy

  my $copy = $orig->copy({ change => $to, ... });

=over

=item Arguments: \%replacementdata

=item Return Value: L<$result|DBIO::Manual::ResultClass> copy

=back

Inserts a new row into the database, as a copy of the original
object. If a hashref of replacement data is supplied, these will take
precedence over data in the original. Also any columns which have
the L<column info attribute|DBIO::ResultSource/add_columns>
C<< is_auto_increment => 1 >> are explicitly removed before the copy,
so that the database can insert its own autoincremented values into
the new object.

Relationships will be followed by the copy procedure B<only> if the
relationship specifies a true value for its
L<cascade_copy|DBIO::Relationship::Base> attribute. C<cascade_copy>
is set by default on C<has_many> relationships and unset on all others.

=head2 store_column

  $result->store_column($col => $val);

=over

=item Arguments: $columnname, $value

=item Return Value: The value sent to storage

=back

Set a raw value for a column without marking it as changed. This
method is used internally by L</set_column> which you should probably
be using.

This is the lowest level at which data is set on a result object,
extend this method to catch all data setting methods.

=head2 inflate_result

  Class->inflate_result($result_source, \%me, \%prefetch?)

=over

=item Arguments: L<$result_source|DBIO::ResultSource>, \%columndata, \%prefetcheddata

=item Return Value: L<$result|DBIO::Manual::ResultClass>

=back

All L<DBIO::ResultSet> methods that retrieve data from the
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.

Reblessing can also be done more easily by setting C<result_class> in
your Result class. See L<DBIO::ResultSource/result_class>.

Different types of results can also be created from a particular
L<DBIO::ResultSet>, see L<DBIO::ResultSet/result_class>.

=head2 update_or_insert

  $result->update_or_insert

=over

=item Arguments: none

=item Return Value: Result of update or insert operation

=back

L</update>s the object if it's already in the database, according to
L</in_storage>, else L</insert>s it.



( run in 1.748 second using v1.01-cache-2.11-cpan-7fcb06a456a )