時計を壊せ

駆け出してからそこそこ経ったWebプログラマーの雑記

TengでRowObject自身を最新にする

以下のような、RowObject内の値が信頼出来なくなるようなupdateをかけたあとに、
masterからrefetchし直した値が引けると嬉しいのかなと思った。

say($row->xxx_pt); # 20
$row->update(+{ xxx_pt => \sprintf('xxx_pt + %d', 10) });
say($row->xxx_pt); # "xxx_pt's row data is untrusted. by your update query." で死ぬ

refetchした値を自分自身に適用して、ほげほげしてくれるといいのかなとおもった。

say($row->xxx_pt); # 20
$row->update(+{ xxx_pt => \sprintf('xxx_pt + %d', 10) }); ## 内部でrefetchして自分自身を更新する
say($row->xxx_pt); # 30? 40? ...

なんかRowObjectは不変であるべきな気もしてて、そういう意味では根本的に間違ってる気もするけど、
ScalarRefでなく普通の値を渡したときは新しい値がちゃんと取れる事を考えるとまあアリなアプローチなのかなとも思いつつ。

ユーザーに見せる場合はむしろ他の場所で行われたupdateは無視して30と表示させたほうが誤解されにくい気もしつつ、
SELECTしてくる前に他の場所でupdateが行われた場合にはそれでもあまり意味が無いなと思うと最新の値を表示させたほうがいいのかなと思いつつ。

もやもや。


実装自体はこんな感じで出来そうなきがする。

package Proj::DB::Row;
use strict;
use warnings;
use utf8;

use parent qw/Teng::Row/;

sub self_refetch {
    my($self, $teng) = @_;
    $self->{teng} = $teng if $teng;

    my $new = $self->refetch;
    %$self = %$new; ## shallow copy

    return $self;
}

sub update {
    my $self = shift;
    my $rows = $self->SUPER::update(@_);
    $self->self_refetch;
    return $rows;
}

1;