[Dbix-class] update value of a column when another column changes

Alexander Hartmaier alexander.hartmaier at t-systems.at
Tue May 28 15:12:57 GMT 2013


Hi list,
after wasting a day with several approaches to the problem I'm asking here.

I want to update the column accept_datetime to DateTime->now when the
accept column is changed.
My current code has the problem of getting called by create as well and
thus overwriting the accept_datetime if it is included in the hashref
passed to create which is required for testing and also scripts that
create 'active' requests.

I didn't find a way to distinguish between a change and the initial
setting of the column value.
Because the column is nullable an old value of undefined is no
indication that store_column was called by create either.

The different solutions I tried today where:
1. use DBIx::Class::Helper::Row::OnColumnChange:
This updates the column on update which is too late because I want to be
able to instantiate request objects in memory using new_result and
running my tests against that.

2. don't do it in store_column but in the column accessor instead:
This fails because my form code in the app uses the rel_accept
relationship which, when updated, doesn't call the column accessor but
set_column instead. If I move my code from store_column to set_column my
problem persists.
The Cookbook has an example code for that:
https://metacpan.org/module/RIBASUSHI/DBIx-Class-0.08250/lib/DBIx/Class/Manual/Cookbook.pod#Changing-one-field-whenever-another-changes

#######################

package NAC::Model::DBIC::Table::FW_Request;
use Moose;
use namespace::autoclean;

extends 'NAC::Model::DBIC::Table::Parent::Request';

__PACKAGE__->table('fw_request');

__PACKAGE__->add_columns(
  "id_fw_request",
  {
    data_type => "NUMBER",
    default_value => undef,
    is_auto_increment => 1,
    is_nullable => 0,
    size => 6,
    #sequence => __PACKAGE__->schemaname . 'seq_fw_request',
  },
  "req_desc",
  {
    data_type => "VARCHAR2",
    default_value => undef,
    is_nullable => 0,
    size => 128,
  },
  "req_dn",
  {
    data_type => "VARCHAR2",
    default_value => undef,
    is_nullable => 0,
    size => 128,
  },
  "req_name",
  {
    data_type => "VARCHAR2",
    default_value => undef,
    is_nullable => 0,
    size => 128,
  },
  "req_email",
  {
    data_type => "VARCHAR2",
    default_value => undef,
    is_nullable => 1,
    size => 128,
  },
  "dst_kst_ktr",
  {
    data_type => "VARCHAR2",
    default_value => undef,
    is_nullable => 0,
    size => 19,
  },
  "req_datetime",
  {
    data_type => "DATETIME",
    is_nullable => 0,
    size => 19,
    timezone => "UTC",
    set_on_create => 1,
  },
  "req_status",
  {
    data_type => "NUMBER",
    default_value => 1,
    is_foreign_key => 1,
    is_nullable => 0,
    size => 6,
  },
  "req_status_datetime",
  { data_type => "DATETIME", default_value => undef, is_nullable => 1,
size => 19, timezone => "UTC" },
  "req_agent",
  {
    data_type => "VARCHAR2",
    default_value => undef,
    is_nullable => 1,
    size => 128,
  },
  "accept",
  {
    data_type => "NUMBER",
    default_value => undef,
    is_foreign_key => 1,
    is_nullable => 1,
    size => 1,
  },
  "accept_datetime",
  { data_type => "DATETIME", default_value => undef, is_nullable => 1,
size => 19, timezone => "UTC" },
  "accept_agent",
  {
    data_type => "VARCHAR2",
    default_value => undef,
    is_nullable => 1,
    size => 128,
  },
  "agent_comment",
  {
    data_type => "VARCHAR2",
    default_value => undef,
    is_nullable => 1,
    size => 1024,
  },
  "req_id",
  {
    data_type => "NUMBER",
    default_value => undef,
    is_auto_increment => 1,
    is_nullable => 0,
    size => 6,
  },
  "req_customer",
  {
    data_type => "NUMBER",
    default_value => undef,
    is_foreign_key => 1,
    is_nullable => 1,
    size => 6,
  },
  "req_comment",
  {
    data_type => "VARCHAR2",
    default_value => undef,
    is_nullable => 1,
    size => 1024,
  },
);

__PACKAGE__->set_primary_key("id_fw_request");

__PACKAGE__->belongs_to(
  "rel_accept",
  "NAC::Model::DBIC::Table::Bool_vals",
  { id_bool_vals => "accept" },
  { join_type => "LEFT" },
);
__PACKAGE__->belongs_to(
  "rel_req_status",
  "NAC::Model::DBIC::Table::Request_Status",
  { id_fw_status => "req_status" },
);
__PACKAGE__->belongs_to(
  "rel_req_customer",
  "NAC::Model::DBIC::Table::Customer",
  { id_customer => "req_customer" },
  # can not be changed until all requests have a customer assigned!
  { join_type => "LEFT" },
);

__PACKAGE__->has_many(
    "entries",
    "NAC::Model::DBIC::Table::FW_Rules",
    'fk_fw_request',
    { order_by => 'rule_index' },
);

__PACKAGE__->has_one(
  "view_version",
  "NAC::Model::DBIC::Table::View_FW_Request_Version",
  undef,
  { proxy => [qw/ version /] },
);
__PACKAGE__->has_one(
  "view_latest",
  "NAC::Model::DBIC::Table::View_FW_Request_Latest",
  {
    "foreign.req_id"                => "self.req_id",
    "foreign.req_datetime_latest"   => "self.req_datetime",
  },
  { proxy => [qw/ req_datetime_latest /] },
);

__PACKAGE__->resultset_class('NAC::Model::DBIC::ResultSet::FW_Request');

__PACKAGE__->meta->make_immutable;

1;

# this is actually defined in the base class
NAC::Model::DBIC::Table::Parent::Request

sub store_column {
    my ( $self, $name, $value ) = @_;

    {
        my $now = DateTime->now( time_zone => 'UTC' );

        # $value might be undefined for column accept
        no warnings 'uninitialized';

        # update the datetime when the accept status changes
        if ( $name eq 'accept' && $value ne $self->accept ) {
            $self->accept_datetime($now);
            if ( $value == NO ) {

                # set request status to rejected and update agent and
datetime
                $self->req_status(REQ_STATE_REJECTED);
            }
            elsif ( !defined $value || $value eq '' ) {
                $self->req_status(REQ_STATE_REQUESTED);
            }
        }
        elsif (
               $name eq 'req_status'
            && $value ne $self->req_status
            && (
                # if request isn't in storage it's a newly created one for
                # which we don't need to check if it's the newest version
                !$self->in_storage

                # only update the newest version to keep the original date
                # when the request was activated or rejected
                || $self->is_newest
            )
            )
        {
            $self->req_status_datetime($now);

            # clear the request agent and datetime in case the request was
            # re-opened
            if ( $value eq REQ_STATE_REQUESTED ) {
                $self->req_agent(undef);
                $self->req_status_datetime(undef);
            }
        }
        elsif (
               $name eq 'req_agent'
            && $value eq $self->accept_agent

            # rejected request do have the same accept and realization agent
            && $self->accept == YES
            )
        {
            $self->throw_exception(
                "the accept and request agent must not be the same person");
        }
    }

    $self->next::method( $name, $value );
}

--
Best regards, Alex



*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*
T-Systems Austria GesmbH Rennweg 97-99, 1030 Wien
Handelsgericht Wien, FN 79340b
*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*
Notice: This e-mail contains information that is confidential and may be privileged.
If you are not the intended recipient, please notify the sender and then
delete this e-mail immediately.
*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*



More information about the DBIx-Class mailing list