DBIx-QuickORM

 view release on metacpan or  search on metacpan

worktrees/audit-fixes-master/lib/DBIx/QuickORM/Row.pm  view on Meta::CPAN

Delete the row from the database (requires a stored row with a primary
key).

=item $result = $row->cas($input, \%changes)

Compare-and-set this row: write the changes only while a set of guard values
still match, so a concurrent writer cannot overwrite it unnoticed. C<$input> is
the guard: a where hashref, an arrayref of field names, or a single field name
(field names are checked against the row's currently stored values). Returns a
L<DBIx::QuickORM::CAS::Result> that is true only when the row was updated; a
failed guard is a normal C<lost> result, not an exception. C<\%changes> should
set a new value for at least one guard column (C<cas> warns otherwise), for
example:

 my $result = $row->cas('version', {version => $row->field('version') + 1});

See the C<cas> method in L<DBIx::QuickORM::Handle> for the full description.

=back

=cut

sub force_sync {
    my $self = shift;
    delete $self->row_data->{+DESYNC};
    return $self;
}

# Fetch new data from the db
sub refresh {
    my $self = shift;

    my $row = $self->_stored_handle->one;
    return $row if $row;

    $self->connection->state_invalidate(source => $self->source, row => $self, reason => "row no longer exists in the database");
    croak "Cannot refresh: this row no longer exists in the database";
}

# Remove pending changes (and clear desync)
sub discard {
    my $self = shift;

    delete $self->row_data->{+DESYNC};
    delete $self->row_data->{+PENDING};

    return $self;
}

sub delete {
    my $self = shift;
    return $self->_stored_handle->delete;
}

sub cas {
    my $self = shift;
    my ($input, $changes) = @_;
    return $self->_stored_handle->cas($input, $changes);
}

sub update {
    my $self = shift;

    my $changes;
    if (@_ == 1) {
        ($changes) = @_;
    }
    else {
        $changes = {@_};
    }

    $self->check_pk;

    my $source = $self->source;
    for my $field (keys %$changes) {
        croak "This row does not have a '$field' field" unless $source->has_field($field);
        croak "Cannot set field '$field': it is a database-generated column"
            if $source->field_is_generated($field);
    }

    $self->_check_stale;

    # Validate desync BEFORE staging so that a croak never leaves
    # the update's changes armed in PENDING.  The fields being
    # updated are allowed to be desynced (they are about to be
    # overwritten), but any *other* desynced field is an error.
    if ($self->track_desync) {
        if (my $desync = $self->row_data->{+DESYNC}) {
            my %remaining = %$desync;
            delete $remaining{$_} for keys %$changes;
            croak <<"    EOT" if keys %remaining;

This row is out of sync, this means it was refreshed while it had pending
changes and the data retrieved from the database does not match what was in
place when the pending changes were set.

To fix such conditions you need to either use row->discard() to clear the
pending changes, or you need to call ->force_sync() to clear the desync flags
allowing you to save the row despite the discrepency.

In addition it would be a good idea to call ->refresh() to have the most up to
date data.

    EOT
        }
    }

    # Stage the changes against the current transaction so a rollback
    # discards them along with the transaction's frame.
    $self->{+ROW_DATA}->change_state({TRANSACTION() => $self->connection->current_txn, PENDING() => {%$changes}});

    my $row_data = $self->row_data;
    if (my $desync = $row_data->{+DESYNC}) {
        delete $desync->{$_} for keys %$changes;
        delete $row_data->{+DESYNC} unless keys %$desync;
    }

    $self->save();
    return $self;
}



( run in 1.187 second using v1.01-cache-2.11-cpan-600a1bdf6e4 )