[Dbix-class] InflateColumn with objects external to the
database (like InflateColumn::FS)
Marc Mims
marc at questright.com
Fri Apr 17 20:51:57 GMT 2009
* Francesc Rom? i Frigol? <francesc.roma+dbix at gmail.com> [090417 11:39]:
> Marc is more comfortable with a solution that instead of modifying the
> source object, it creates a new row object like this:
>
> my $copy = bless { %$self, _column_data => $col_data, _inflated_column =>
> $inflated_col }, ref $self;
> $copy = $copy->next::method($changes);
>
> But either way, the implementation assumes some knowledge of the
> implementation of the base object.
>
> sub copy {
> my ($self, $changes) = @_;
>
> $changes ||= {};
> my $col_data = $self->{_column_data};
> my $inflated_col = $self->{_inflated_column} ;
>
> foreach my $col ( keys %$col_data ) {
> my $column_info = $self->result_source->column_info($col);
> if ( $column_info->{is_fs_column}
> && defined $col_data->{$col} # nothing special required for
> NULLs
> && !exists $changes->{$col} ) {
>
> # pass the original file to produce a copy on deflate
> my $accessor = $column_info->{accessor} || $col;
> $changes->{$col} = $self->$accessor;
>
> $col_data->{$col} = undef;
> }
> }
>
> my $copy = $self->next::method($changes);
>
> # force reinflation of fs colmuns on next access
> delete $copy->{_inflated_column}{$_}
> for grep { $self->result_source->column_info($_)->{is_fs_column} }
> keys %$col_data;
>
> return $copy;
> }
>
> links to cpan and repository:
> http://search.cpan.org/perldoc?DBIx::Class::InflateColumn::FS
> http://dev.catalyst.perl.org/svnweb/bast/revision?rev=5889
Francesc and I have been batting this back and forth off list. My
current, un-committed implemention for ::FS::copy is:
sub copy {
my ($self, $changes) = @_;
$changes ||= {};
my $col_data = { %{$self->{_column_data}} };
foreach my $col ( keys %$col_data ) {
my $column_info = $self->result_source->column_info($col);
if ( $column_info->{is_fs_column}
&& defined $col_data->{$col} ) { # nothing special required for NULLs
$col_data->{$col} = undef;
# pass the original file to produce a copy on deflate
my $accessor = $column_info->{accessor} || $col;
$changes->{$col} ||= $self->$accessor;
}
}
my $temp = bless { _column_data => $col_data }, ref $self;
$temp->result_source($self->result_source);
my $copy = $temp->next::method($changes);
# force reinflation of fs colmuns on next access
delete $copy->{_inflated_column}{$_}
for grep { $self->result_source->column_info($_)->{is_fs_column} }
keys %$col_data;
return $copy;
}
When ::FS deflates a column, it makes a copy of the source file in its
own storage path (fs_column_path) UNLESS the inflated value and the
current deflated value (in _column_data) arleady represent the same
file.
So, I create the shallowest copy I can, in ::FS::copy to represent the
source row with the appropriate _column_data set to undef to force a
copy on deflate. Then I let ::Row::copy do the rest.
After the copy, I delete the inflated fs_columns from _inflated_column
to force inflation from the new copies.
So, DBIC:IC::FS::copy duplicates some of the DBIC:Row internals. The
question is: Is there a better way?
-Marc
More information about the DBIx-Class
mailing list