anykeyh/clear

Custom Array Converters

zbaylin opened this issue · 4 comments

If I have a class Circle and a model Shapes, if I define a custom converter for Circle (CircleConverter) and do this:

class Shapes
  ...
  column circles : Array(Circle)
  ...
end

I get this error: Error: No converter found for Array(Circle).

How do I convert arrays of custom types/classes?

Hi,

You cannot use directly your circle converter with Array(Circle) because the way array is encoded might be different based on your implementation. You need to create a converter for Array(Circle) and add it like this:

Clear::Model::Converter.add_converter("Array(Circle)", ArrayCircleConverter)

How do you go about doing this? I have the Circle encoded as TEXT in the DB

I'm not sure about your data, but first you need to figure out what kind of data the pg gems detect.
It might be Slice or already Array(::PG::StringArray)

For that you can try a simple Select query like this:

# Assuming your column is living in models.circles
# I've not run this code so it might have some typo or errors :)
value = Clear::SQL.select.from("models").pluck_col("circles")
puts values.class.name
puts values

After that, just build your converter, based on the output you got; assuming it's a Array(::PG::StringArray) for example (code not tested but you get the idea):

module ArrayCircleConverter
  def self.to_column(x) : Array(Circle)?
    return nil unless x
    
    case x
    when ::Array(::PG::StringArray)
      return x.map{ |circle| CircleConverter.to_column(circle.to_s) } # Tricky `to_s` call here: circle could be a nested array but don't want to care about it.
    else
      raise "Cannot convert from #{x.class} to Array(Circle)"
    end
  end

  def self.to_db(arr : Array(Circle)? ) : Clear::SQL::Any
    return nil unless x
    arr.map do |c|
      Clear::Expression.unsafe({"Array[", CircleConverter.to_db(c), "]"}.join)
    end
  end

end

With some tweaking I got this to work, thanks!