[Dbix-class] InflateColumn impact on ResultSet searches

Eric Waters ewaters at xmission.com
Sat May 26 00:22:06 GMT 2007


InflateColumn::DateTime overloads inflate/deflate, but doesn't affect search conditions.

So, while ref($row->dte) == 'DateTime', if you were to do a search for a particular value of dte:

  $rs->search({ dte => DateTime->now() })

... the DateTime object would be passed to SQL::Abstract where it would be stringified.  This is not intuitive.

While I'm told by <ilmari> that this is being worked on in a SQL::Abstract refactoring, I didn't want to wait.  Below is a patch on DBIx::Class::ResultSet that will deflate any references found in the WHERE args before submitting to the driver.  I've put this here rather than at the Storage level because it seems that the result_source data (which seems to contain the column_info data that InflateColumn modifies) is not available further down the chain.  While it'd be nice to include this in DBIx::Class::InflateColumn, I don't see a way to do that.  Please let me know if I'm off base here.

With the attached code, one would be able to do a search using a ref and have it behave the same as getting/setting the value on a row.  This end behavior is more intuitive.  This is not throughly tested.

Eric Waters

-- patch follows --

*** ResultSet.pm	Fri May 25 16:51:58 2007
--- /home/users/e/ewaters/lib/perl5/DBIx/Class/ResultSet.pm	Fri May 25 16:50:04 2007
*************** sub search_rs {
*** 230,235 ****
--- 230,237 ----
          : $cond);
    }
  
+   $self->_deflate_references($new_attrs->{where}) if defined $new_attrs->{where};
+ 
    if (defined $having) {
      $new_attrs->{having} = (
        defined $new_attrs->{having}
*************** sub search_rs {
*** 249,254 ****
--- 251,286 ----
    return $rs;
  }
  
+ ## Given a reference to a WHERE structure, replace value references with deflated scalar
+ #  Called from any point the user defines WHERE parameters (new(), single())
+ sub _deflate_references {
+   my ($self, $where) = @_;
+   
+   while (my ($key, $value) = each %$where) {
+     # Handle -or, -and
+	  if (ref($value) && ref($value) eq 'ARRAY') {
+ 	    $self->_deflate_references($_) foreach @$value;
+ 	    next;
+ 	  }
+	  unless (ref($value) && ref($value) eq 'HASH') {
+ 	    next;
+ 	  }
+ 	  my $col = $key;
+ 
+ 	  # Do we need to deflate this column?
+ 	  my $info = $self->result_source->column_info($col)->{_inflate_info};
+ 	  next if ! $info;
+ 	  my $deflator = $info->{deflate};
+ 	  $self->throw_exception("No deflator for $col") unless defined $deflator;
+ 
+ 	  foreach my $col_val (values %$value) {
+ 	    # Is the column value comparator a non-simple reference
+ 	    next if ! ref($col_val) || ref($col_val) =~ m/^(SCALAR|ARRAY|HASH)$/;
+ 	    $col_val = $deflator->($col_val, $self);
+ 	  }
+   }
+ }
+ 
  =head2 search_literal
  
  =over 4
*************** sub single {
*** 520,525 ****
--- 552,558 ----
    my ($self, $where) = @_;
    my $attrs = { %{$self->_resolved_attrs} };
    if ($where) {
+     $self->_deflate_references($where);
      if (defined $attrs->{where}) {
        $attrs->{where} = {
          '-and' =>



More information about the Dbix-class mailing list