Maintain full coherence between filtered cache and unfiltered results, including...
Peter Rabbitson [Mon, 10 May 2010 11:39:56 +0000 (11:39 +0000)]
lib/DBIx/Class/FilterColumn.pm
t/03podcoverage.t
t/row/filter_column.t

index a6bda53..9002058 100644 (file)
@@ -66,7 +66,28 @@ sub get_filtered_column {
   return $self->{_filtered_column}{$col} = $self->_column_from_storage($col, $val);
 }
 
-sub set_column {
+sub get_column {
+  my ($self, $col) = @_;
+  if (exists $self->{_filtered_column}{$col}) {
+    return $self->{_column_data}{$col} ||= $self->_column_to_storage ($col, $self->{_filtered_column}{$col});
+  }
+
+  return $self->next::method ($col);
+}
+
+# sadly a separate codepath in Row.pm ( used by insert() )
+sub get_columns {
+  my $self = shift;
+
+  foreach my $col (keys %{$self->{_filtered_column}||{}}) {
+    $self->{_column_data}{$col} ||= $self->_column_to_storage ($col, $self->{_filtered_column}{$col})
+      if exists $self->{_filtered_column}{$col};
+  }
+
+  $self->next::method (@_);
+}
+
+sub store_column {
   my ($self, $col) = (shift, @_);
 
   # blow cache
@@ -89,19 +110,23 @@ sub set_filtered_column {
 
   $self->set_column($col, $self->_column_to_storage($col, $filtered));
 
-  return $filtered;
+  return $self->{_filtered_column}{$col} = $filtered;
 }
 
 sub update {
   my ($self, $attrs, @rest) = @_;
+
   foreach my $key (keys %{$attrs||{}}) {
-    if ($self->has_column($key) &&
-          exists $self->column_info($key)->{_filter_info}) {
-      my $val = delete $attrs->{$key};
-      $self->set_filtered_column($key, $val);
-      $attrs->{$key} = $self->_column_to_storage($key, $val)
+    if (
+      $self->has_column($key)
+        &&
+      exists $self->column_info($key)->{_filter_info}
+    ) {
+      $self->set_filtered_column($key, delete $attrs->{$key});
+      $self->get_column($key);
     }
   }
+
   return $self->next::method($attrs, @rest);
 }
 
@@ -114,10 +139,10 @@ sub new {
   foreach my $key (keys %{$attrs||{}}) {
     if ($obj->has_column($key) &&
           exists $obj->column_info($key)->{_filter_info} ) {
-      my $val = delete $attrs->{$key};
-      $obj->set_filtered_column($key, $val);
+      $obj->set_filtered_column($key, $attrs->{$key});
     }
   }
+
   return $obj;
 }
 
index 0b2bbbe..095a2d2 100644 (file)
@@ -50,7 +50,9 @@ my $exceptions = {
         ignore => [qw/
             new
             update
-            set_column
+            store_column
+            get_column
+            get_columns
         /],
     },
     'DBIx::Class::ResultSource' => {
index ef2b880..e896cc9 100644 (file)
@@ -96,10 +96,6 @@ CACHE_TEST: {
   ok ($artist->is_column_changed ('rank'), 'Column marked as dirty');
 
   $artist->rank;
-  is $from_storage_ran, ++$expected_from, 'from ran once';
-  is $to_storage_ran, $expected_to,  'to did not run';
-
-  $artist->rank;
   is $from_storage_ran, $expected_from, 'from did not run';
   is $to_storage_ran, $expected_to,  'to did not run';
 
@@ -119,17 +115,8 @@ CACHE_TEST: {
 
   $artist->store_column(rank => 4);
   ok (! $artist->is_column_changed ('rank'), 'Column not marked as dirty on differing store_column value');
-  is ($artist->rank, '6', 'Filtered column still contains old value (cache not blown)');
-  is $from_storage_ran, $expected_from, 'from did not run';
-  is $to_storage_ran, $expected_to,  'to did not run';
-
-  $artist->set_column(rank => 4);
-  TODO: {
-    local $TODO = 'There seems to be no way around that much wizardry... which is ok';
-    ok ($artist->is_column_changed ('rank'), 'Column marked as dirty on out-of-sync set_column value');
-  }
-  is ($artist->rank, '8', 'Column set properly (cache blown)');
-  is $from_storage_ran, ++$expected_from, 'from ran once (set_column blew cache)';
+  is ($artist->rank, '8', 'Cache properly blown');
+  is $from_storage_ran, ++$expected_from, 'from did not run';
   is $to_storage_ran, $expected_to,  'to did not run';
 }