Last active
          August 19, 2016 08:46 
        
      - 
      
 - 
        
Save solnic/9b9deedd7891e2c7ac83 to your computer and use it in GitHub Desktop.  
    Virtus pg array type for Sequel
  
        
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | module Virtus | |
| class PGArray < Attribute | |
| primitive Sequel::Postgres::PGArray | |
| def primitive | |
| options[:primitive] | |
| end | |
| def coerce(value) | |
| Sequel.pg_array(value) | |
| rescue | |
| value | |
| end | |
| def value_coerced?(value) | |
| value.instance_of?(Sequel::Postgres::PGArray) | |
| end | |
| end | |
| end | |
| class Params | |
| include Virtus.model(strict: true) | |
| attribute :arr, Virtus::PGArray | |
| end | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | irb(main):007:0> Virtus::Attribute.build(Virtus::PGArray, strict: true).coerce([1,2,3]) | |
| => [1, 2, 3] | |
| irb(main):008:0> Virtus::Attribute.build(Virtus::PGArray, strict: true).coerce('') | |
| Virtus::CoercionError: Failed to coerce "" into Sequel::Postgres::PGArray | 
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment
  
            
tl;dr: You may not need to call
primitivemethod within the custom attribute class body, unless you want to make Virtus use the custom attribute#coercemethod to define all attributes of the given primitive.I just found out that unless you want to write a generic coercer for any value of class
Foo, you better omit theprimitive Foopart.For example, I wrote a custom coercer for BigDecimal, let's call it
BigDecimalWithOneDecimalPoint. It tried to coerce the given value to a BigDecimal and then round it to one decimal point.However, because I used
primitive BigDecimalwithin theBigDecimalWithOneDecimalPointdefinition, Virtus was using it for all BigDecimal values. Even if I specified that BigDecimal is the type of an attribute:…Virtus would still use
BigDecimalWithOneDecimalPointfor the coercion.Removing the
primitivecall seems to solve the problem. However, in order to make the strict mode error message correct, you can no longer useoptions[:primitive]in theprimitivemethod. For now, I just made mine method return the desired primitive.I made a reproduction of the issue. However, I'm not sure if I should submit it as a separate Virtus issue, because I think calling
primitiveor definingvalue_coerced?is using the private API of Virtus. And yeah, I remember you're not working on Virtus. 😉So I post it here to make people aware of the caveats of calling
primitive.