On May 12, 6:27 am, byrnejb <[email protected]> wrote:
> We have an ActiveRecord model class which is choking on an attribute
> that has both a default value of 'infinity' and a NOT NULL
> constraint.  Basically, AR tries to insert a NULL because Ruby does
> not understand 'infinity' and AR explicitly sets all columns with
> defaults to those values (when it understands them) when inserting a
> row.
>
> I am contemplating moving this class to Sequel but I would like to
> know whether Sequel handles this situation any differently?

Sequel::Model typecasting uses Kernel#Float by default, which doesn't
appear to like 'infinity':

  DB.create_table!(:a){Float :a}
  Sequel::Model(:a).new.a = 'infinity'
  Sequel::InvalidValue: ArgumentError: invalid value for Float():
"infinity"

You can disable such typecasting errors, and you'll be able to save
records:

  Sequel::Model.raise_on_typecast_failure = false
  DB.create_table!(:a){Float :a}
  a = Sequel::Model(:a).create(:a => 'infinity')

Unfortunately, while that will save an infinite float, loading the
record won't get you the same result:

  a.a # => 0.0

This is because String#to_f is used on retrieval, and "Infinity".to_f
results in 0.0.

The good news is that if you modify String#to_f, things will work
fine:

  class String
    alias old_to_f to_f
    def to_f() self =~ /\A([+-])?infinity\z/i ? (Float::MAX * (($1 ==
'-' ) ? -2 : 2)) : old_to_f end
  end

Until you try to update an existing record, as Sequel doesn't
literalize infinite floats properly.  That's possible to fix too:

  class Sequel::Dataset
    alias old_literal_float literal_float
    def literal_float(v) v.infinite? ? literal("#{'-'  if v < 0}
infinity") : old_literal_float(v) end
  end

And patching Kernel#Float will make typecasting work correctly:

  module Kernel
    alias old_Float Float
    def Float(v) v =~ /\A([+-])?infinity\z/i ? (Float::MAX * (($1 ==
'-' ) ? -2 : 2)) : old_Float(v) end
  end

With the modifications to String#to_f, Kernel#Float, and
Sequel::Dataset, you should be able to handle things correctly.  I'm
open to making the Sequel::Dataset modification part of Sequel, but
I'm not sure that's wise until ruby itself fixes String#to_f and
Kernel#Float.

I should point out that if you are using sequel_pg, the retrieval
probably won't be fixable without modifying the extension, as does the
type conversion in C:

  rv = rb_float_new(rb_cstr_to_dbl(v, Qfalse));

Jeremy

-- 
You received this message because you are subscribed to the Google Groups 
"sequel-talk" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/sequel-talk?hl=en.

Reply via email to