[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