store_model 0.7.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/README.md +3 -2
 - data/lib/active_model/validations/store_model_validator.rb +2 -2
 - data/lib/store_model.rb +5 -0
 - data/lib/store_model/combine_errors_strategies/merge_error_strategy.rb +2 -1
 - data/lib/store_model/model.rb +37 -1
 - data/lib/store_model/nested_attributes.rb +2 -2
 - data/lib/store_model/type_builders.rb +6 -6
 - data/lib/store_model/types.rb +13 -2
 - data/lib/store_model/types/many.rb +48 -0
 - data/lib/store_model/types/{array_type.rb → many_base.rb} +17 -27
 - data/lib/store_model/types/many_polymorphic.rb +53 -0
 - data/lib/store_model/types/{json_type.rb → one.rb} +5 -29
 - data/lib/store_model/types/one_base.rb +67 -0
 - data/lib/store_model/types/one_of.rb +23 -0
 - data/lib/store_model/types/one_polymorphic.rb +89 -0
 - data/lib/store_model/types/polymorphic_helper.rb +13 -0
 - data/lib/store_model/version.rb +1 -1
 - metadata +18 -12
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 1c612c06744ac1427fd3c3d718e414592ce983734f6aa547e7ffe052b6ac0ef3
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 349b6f3625d2d94a585c119a3e2080519f9509ee738633062a95364ffd47eb98
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: d1df9be55ae81ae2648a1d1c9dc287731ae2954cbfbe9ea618d27aa50b954e5c867900b147aa7ede58382ecf21fcba8e62e6f1b2571700e1e64e76c834c16f69
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 9224ce8f181e58f02e0fec9864acf1ba4c22e8a575d40ad6e3a66e354178c4c2b4478cb19e8290304da98fe06b0d862fd8da558f71f91ae4dc577d1f2a827000
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -1,4 +1,4 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # StoreModel [](https://rubygems.org/gems/store_model) [](https://rubygems.org/gems/store_model) [](https://coveralls.io/github/DmitryTsepelev/store_model?branch=master)
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            **StoreModel** gem allows you to wrap JSON-backed DB columns with ActiveModel-like classes.
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
         @@ -44,7 +44,7 @@ This approach works fine when you don't have a lot of keys with logic around the 
     | 
|
| 
       44 
44 
     | 
    
         | 
| 
       45 
45 
     | 
    
         
             
            For instance, try to find a way to validate `:model` value to be required. Despite of the fact, that you'll have to write this validation by hand, it violates single-repsponsibility principle: why parent model (`Product`) should know about the logic related to a child (`Configuration`)?
         
     | 
| 
       46 
46 
     | 
    
         | 
| 
       47 
     | 
    
         
            -
            > 📖 Read more about the motivation in the [Wrapping JSON-based ActiveRecord attributes with classes](https:// 
     | 
| 
      
 47 
     | 
    
         
            +
            > 📖 Read more about the motivation in the [Wrapping JSON-based ActiveRecord attributes with classes](https://evilmartians.com/chronicles/wrapping-json-based-active-record-attributes-with-classes) post
         
     | 
| 
       48 
48 
     | 
    
         | 
| 
       49 
49 
     | 
    
         
             
            ## Getting started
         
     | 
| 
       50 
50 
     | 
    
         | 
| 
         @@ -88,6 +88,7 @@ product.save 
     | 
|
| 
       88 
88 
     | 
    
         
             
              * [Nested models](./docs/nested_models.md)
         
     | 
| 
       89 
89 
     | 
    
         
             
              * [Unknown attributes](./docs/unknown_attributes.md)
         
     | 
| 
       90 
90 
     | 
    
         
             
            3. [Array of stored models](./docs/array_of_stored_models.md)
         
     | 
| 
      
 91 
     | 
    
         
            +
            4. [One of](./docs/one_of.md)
         
     | 
| 
       91 
92 
     | 
    
         
             
            4. [Alternatives](./docs/alternatives.md)
         
     | 
| 
       92 
93 
     | 
    
         
             
            5. [Defining custom types](./docs/defining_custom_types.md)
         
     | 
| 
       93 
94 
     | 
    
         | 
| 
         @@ -21,9 +21,9 @@ module ActiveModel 
     | 
|
| 
       21 
21 
     | 
    
         
             
                    end
         
     | 
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         
             
                    case record.type_for_attribute(attribute).type
         
     | 
| 
       24 
     | 
    
         
            -
                    when :json
         
     | 
| 
      
 24 
     | 
    
         
            +
                    when :json, :polymorphic
         
     | 
| 
       25 
25 
     | 
    
         
             
                      call_json_strategy(attribute, record.errors, value)
         
     | 
| 
       26 
     | 
    
         
            -
                    when :array
         
     | 
| 
      
 26 
     | 
    
         
            +
                    when :array, :polymorphic_array
         
     | 
| 
       27 
27 
     | 
    
         
             
                      call_array_strategy(attribute, record.errors, value)
         
     | 
| 
       28 
28 
     | 
    
         
             
                    end
         
     | 
| 
       29 
29 
     | 
    
         
             
                  end
         
     | 
    
        data/lib/store_model.rb
    CHANGED
    
    
| 
         @@ -13,7 +13,8 @@ module StoreModel 
     | 
|
| 
       13 
13 
     | 
    
         
             
                  # attribute
         
     | 
| 
       14 
14 
     | 
    
         
             
                  def call(attribute, base_errors, store_model_errors)
         
     | 
| 
       15 
15 
     | 
    
         
             
                    if Rails::VERSION::MAJOR < 6 || Rails::VERSION::MAJOR == 6 && Rails::VERSION::MINOR.zero?
         
     | 
| 
       16 
     | 
    
         
            -
                      base_errors. 
     | 
| 
      
 16 
     | 
    
         
            +
                      base_errors.delete(attribute)
         
     | 
| 
      
 17 
     | 
    
         
            +
                      store_model_errors.each { |field, error| base_errors.add(field, error) }
         
     | 
| 
       17 
18 
     | 
    
         
             
                    else
         
     | 
| 
       18 
19 
     | 
    
         
             
                      store_model_errors.errors.each do |error|
         
     | 
| 
       19 
20 
     | 
    
         
             
                        base_errors.add(attribute, :invalid, message: error.full_message)
         
     | 
    
        data/lib/store_model/model.rb
    CHANGED
    
    | 
         @@ -11,10 +11,13 @@ module StoreModel 
     | 
|
| 
       11 
11 
     | 
    
         
             
                def self.included(base) # :nodoc:
         
     | 
| 
       12 
12 
     | 
    
         
             
                  base.include ActiveModel::Model
         
     | 
| 
       13 
13 
     | 
    
         
             
                  base.include ActiveModel::Attributes
         
     | 
| 
      
 14 
     | 
    
         
            +
                  base.include ActiveModel::AttributeMethods
         
     | 
| 
       14 
15 
     | 
    
         
             
                  base.include StoreModel::NestedAttributes
         
     | 
| 
       15 
16 
     | 
    
         | 
| 
       16 
17 
     | 
    
         
             
                  base.extend StoreModel::Enum
         
     | 
| 
       17 
18 
     | 
    
         
             
                  base.extend StoreModel::TypeBuilders
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  base.attribute_method_suffix "?"
         
     | 
| 
       18 
21 
     | 
    
         
             
                end
         
     | 
| 
       19 
22 
     | 
    
         | 
| 
       20 
23 
     | 
    
         
             
                attr_accessor :parent
         
     | 
| 
         @@ -70,13 +73,37 @@ module StoreModel 
     | 
|
| 
       70 
73 
     | 
    
         | 
| 
       71 
74 
     | 
    
         
             
                # Checks if the attribute with a given name is defined
         
     | 
| 
       72 
75 
     | 
    
         
             
                #
         
     | 
| 
      
 76 
     | 
    
         
            +
                # @example
         
     | 
| 
      
 77 
     | 
    
         
            +
                #    class Person
         
     | 
| 
      
 78 
     | 
    
         
            +
                #      include StoreModel::Model
         
     | 
| 
      
 79 
     | 
    
         
            +
                #      attribute :name, :string
         
     | 
| 
      
 80 
     | 
    
         
            +
                #      alias_attribute :new_name, :name
         
     | 
| 
      
 81 
     | 
    
         
            +
                #    end
         
     | 
| 
      
 82 
     | 
    
         
            +
                #
         
     | 
| 
      
 83 
     | 
    
         
            +
                #    Person.has_attribute?('name')     # => true
         
     | 
| 
      
 84 
     | 
    
         
            +
                #    Person.has_attribute?('new_name') # => true
         
     | 
| 
      
 85 
     | 
    
         
            +
                #    Person.has_attribute?(:age)       # => true
         
     | 
| 
      
 86 
     | 
    
         
            +
                #    Person.has_attribute?(:nothing)   # => false
         
     | 
| 
      
 87 
     | 
    
         
            +
                #
         
     | 
| 
       73 
88 
     | 
    
         
             
                # @param attr_name [String] name of the attribute
         
     | 
| 
       74 
89 
     | 
    
         
             
                #
         
     | 
| 
       75 
90 
     | 
    
         
             
                # @return [Boolean]
         
     | 
| 
       76 
91 
     | 
    
         
             
                # rubocop:disable Naming/PredicateName
         
     | 
| 
       77 
92 
     | 
    
         
             
                def has_attribute?(attr_name)
         
     | 
| 
       78 
     | 
    
         
            -
                   
     | 
| 
      
 93 
     | 
    
         
            +
                  attr_name = attr_name.to_s
         
     | 
| 
      
 94 
     | 
    
         
            +
                  attr_name = self.class.attribute_aliases[attr_name] || attr_name
         
     | 
| 
      
 95 
     | 
    
         
            +
                  attribute_types.key?(attr_name)
         
     | 
| 
      
 96 
     | 
    
         
            +
                end
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                # Legacy implementation of #has_attribute?
         
     | 
| 
      
 99 
     | 
    
         
            +
                #
         
     | 
| 
      
 100 
     | 
    
         
            +
                # @param attr_name [String] name of the attribute
         
     | 
| 
      
 101 
     | 
    
         
            +
                #
         
     | 
| 
      
 102 
     | 
    
         
            +
                # @return [Boolean]
         
     | 
| 
      
 103 
     | 
    
         
            +
                def _has_attribute?(attr_name)
         
     | 
| 
      
 104 
     | 
    
         
            +
                  attribute_types.key?(attr_name)
         
     | 
| 
       79 
105 
     | 
    
         
             
                end
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
       80 
107 
     | 
    
         
             
                # rubocop:enable Naming/PredicateName
         
     | 
| 
       81 
108 
     | 
    
         | 
| 
       82 
109 
     | 
    
         
             
                # Contains a hash of attributes which are not defined but exist in the
         
     | 
| 
         @@ -86,5 +113,14 @@ module StoreModel 
     | 
|
| 
       86 
113 
     | 
    
         
             
                def unknown_attributes
         
     | 
| 
       87 
114 
     | 
    
         
             
                  @unknown_attributes ||= {}
         
     | 
| 
       88 
115 
     | 
    
         
             
                end
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
                private
         
     | 
| 
      
 118 
     | 
    
         
            +
             
     | 
| 
      
 119 
     | 
    
         
            +
                def attribute?(attribute)
         
     | 
| 
      
 120 
     | 
    
         
            +
                  case value = attributes[attribute]
         
     | 
| 
      
 121 
     | 
    
         
            +
                  when 0 then false
         
     | 
| 
      
 122 
     | 
    
         
            +
                  else value.present?
         
     | 
| 
      
 123 
     | 
    
         
            +
                  end
         
     | 
| 
      
 124 
     | 
    
         
            +
                end
         
     | 
| 
       89 
125 
     | 
    
         
             
              end
         
     | 
| 
       90 
126 
     | 
    
         
             
            end
         
     | 
| 
         @@ -14,9 +14,9 @@ module StoreModel 
     | 
|
| 
       14 
14 
     | 
    
         
             
                  def accepts_nested_attributes_for(*associations)
         
     | 
| 
       15 
15 
     | 
    
         
             
                    associations.each do |association|
         
     | 
| 
       16 
16 
     | 
    
         
             
                      case attribute_types[association.to_s]
         
     | 
| 
       17 
     | 
    
         
            -
                      when Types:: 
     | 
| 
      
 17 
     | 
    
         
            +
                      when Types::One
         
     | 
| 
       18 
18 
     | 
    
         
             
                        alias_method "#{association}_attributes=", "#{association}="
         
     | 
| 
       19 
     | 
    
         
            -
                      when Types:: 
     | 
| 
      
 19 
     | 
    
         
            +
                      when Types::Many
         
     | 
| 
       20 
20 
     | 
    
         
             
                        define_method "#{association}_attributes=" do |attributes|
         
     | 
| 
       21 
21 
     | 
    
         
             
                          assign_nested_attributes_for_collection_association(association, attributes)
         
     | 
| 
       22 
22 
     | 
    
         
             
                        end
         
     | 
| 
         @@ -3,16 +3,16 @@ 
     | 
|
| 
       3 
3 
     | 
    
         
             
            module StoreModel
         
     | 
| 
       4 
4 
     | 
    
         
             
              # Contains methods for converting StoreModel::Model to ActiveModel::Type::Value.
         
     | 
| 
       5 
5 
     | 
    
         
             
              module TypeBuilders
         
     | 
| 
       6 
     | 
    
         
            -
                # Converts StoreModel::Model to Types:: 
     | 
| 
       7 
     | 
    
         
            -
                # @return [Types:: 
     | 
| 
      
 6 
     | 
    
         
            +
                # Converts StoreModel::Model to Types::One
         
     | 
| 
      
 7 
     | 
    
         
            +
                # @return [Types::One]
         
     | 
| 
       8 
8 
     | 
    
         
             
                def to_type
         
     | 
| 
       9 
     | 
    
         
            -
                  Types:: 
     | 
| 
      
 9 
     | 
    
         
            +
                  Types::One.new(self)
         
     | 
| 
       10 
10 
     | 
    
         
             
                end
         
     | 
| 
       11 
11 
     | 
    
         | 
| 
       12 
     | 
    
         
            -
                # Converts StoreModel::Model to Types:: 
     | 
| 
       13 
     | 
    
         
            -
                # @return [Types:: 
     | 
| 
      
 12 
     | 
    
         
            +
                # Converts StoreModel::Model to Types::Many
         
     | 
| 
      
 13 
     | 
    
         
            +
                # @return [Types::Many]
         
     | 
| 
       14 
14 
     | 
    
         
             
                def to_array_type
         
     | 
| 
       15 
     | 
    
         
            -
                  Types:: 
     | 
| 
      
 15 
     | 
    
         
            +
                  Types::Many.new(self)
         
     | 
| 
       16 
16 
     | 
    
         
             
                end
         
     | 
| 
       17 
17 
     | 
    
         
             
              end
         
     | 
| 
       18 
18 
     | 
    
         
             
            end
         
     | 
    
        data/lib/store_model/types.rb
    CHANGED
    
    | 
         @@ -1,12 +1,23 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
            require "store_model/types/ 
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
      
 3 
     | 
    
         
            +
            require "store_model/types/polymorphic_helper"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            require "store_model/types/one_base"
         
     | 
| 
      
 6 
     | 
    
         
            +
            require "store_model/types/one"
         
     | 
| 
      
 7 
     | 
    
         
            +
            require "store_model/types/one_polymorphic"
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            require "store_model/types/many_base"
         
     | 
| 
      
 10 
     | 
    
         
            +
            require "store_model/types/many"
         
     | 
| 
      
 11 
     | 
    
         
            +
            require "store_model/types/many_polymorphic"
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
       5 
13 
     | 
    
         
             
            require "store_model/types/enum_type"
         
     | 
| 
       6 
14 
     | 
    
         | 
| 
      
 15 
     | 
    
         
            +
            require "store_model/types/one_of"
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
       7 
17 
     | 
    
         
             
            module StoreModel
         
     | 
| 
       8 
18 
     | 
    
         
             
              # Contains all custom types.
         
     | 
| 
       9 
19 
     | 
    
         
             
              module Types
         
     | 
| 
       10 
20 
     | 
    
         
             
                class CastError < StandardError; end
         
     | 
| 
      
 21 
     | 
    
         
            +
                class ExpandWrapperError < StandardError; end
         
     | 
| 
       11 
22 
     | 
    
         
             
              end
         
     | 
| 
       12 
23 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,48 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require "active_model"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module StoreModel
         
     | 
| 
      
 6 
     | 
    
         
            +
              module Types
         
     | 
| 
      
 7 
     | 
    
         
            +
                # Implements ActiveModel::Type::Value type for handling an array of
         
     | 
| 
      
 8 
     | 
    
         
            +
                # StoreModel::Model
         
     | 
| 
      
 9 
     | 
    
         
            +
                class Many < ManyBase
         
     | 
| 
      
 10 
     | 
    
         
            +
                  # Initializes type for model class
         
     | 
| 
      
 11 
     | 
    
         
            +
                  #
         
     | 
| 
      
 12 
     | 
    
         
            +
                  # @param model_klass [StoreModel::Model] model class to handle
         
     | 
| 
      
 13 
     | 
    
         
            +
                  #
         
     | 
| 
      
 14 
     | 
    
         
            +
                  # @return [StoreModel::Types::Many]
         
     | 
| 
      
 15 
     | 
    
         
            +
                  def initialize(model_klass)
         
     | 
| 
      
 16 
     | 
    
         
            +
                    @model_klass = model_klass
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  # Returns type
         
     | 
| 
      
 20 
     | 
    
         
            +
                  #
         
     | 
| 
      
 21 
     | 
    
         
            +
                  # @return [Symbol]
         
     | 
| 
      
 22 
     | 
    
         
            +
                  def type
         
     | 
| 
      
 23 
     | 
    
         
            +
                    :array
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  protected
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  def ensure_model_class(array)
         
     | 
| 
      
 29 
     | 
    
         
            +
                    array.map do |object|
         
     | 
| 
      
 30 
     | 
    
         
            +
                      object.is_a?(@model_klass) ? object : cast_model_type_value(object)
         
     | 
| 
      
 31 
     | 
    
         
            +
                    end
         
     | 
| 
      
 32 
     | 
    
         
            +
                  end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  def cast_model_type_value(value)
         
     | 
| 
      
 35 
     | 
    
         
            +
                    model_klass_type.cast_value(value)
         
     | 
| 
      
 36 
     | 
    
         
            +
                  end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                  def model_klass_type
         
     | 
| 
      
 39 
     | 
    
         
            +
                    @model_klass_type ||= @model_klass.to_type
         
     | 
| 
      
 40 
     | 
    
         
            +
                  end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                  def raise_cast_error(value)
         
     | 
| 
      
 43 
     | 
    
         
            +
                    raise StoreModel::Types::CastError,
         
     | 
| 
      
 44 
     | 
    
         
            +
                          "failed casting #{value.inspect}, only String or Array instances are allowed"
         
     | 
| 
      
 45 
     | 
    
         
            +
                  end
         
     | 
| 
      
 46 
     | 
    
         
            +
                end
         
     | 
| 
      
 47 
     | 
    
         
            +
              end
         
     | 
| 
      
 48 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -6,21 +6,12 @@ module StoreModel 
     | 
|
| 
       6 
6 
     | 
    
         
             
              module Types
         
     | 
| 
       7 
7 
     | 
    
         
             
                # Implements ActiveModel::Type::Value type for handling an array of
         
     | 
| 
       8 
8 
     | 
    
         
             
                # StoreModel::Model
         
     | 
| 
       9 
     | 
    
         
            -
                class  
     | 
| 
       10 
     | 
    
         
            -
                  # Initializes type for model class
         
     | 
| 
       11 
     | 
    
         
            -
                  #
         
     | 
| 
       12 
     | 
    
         
            -
                  # @param model_klass [StoreModel::Model] model class to handle
         
     | 
| 
       13 
     | 
    
         
            -
                  #
         
     | 
| 
       14 
     | 
    
         
            -
                  # @return [StoreModel::Types::ArrayType]
         
     | 
| 
       15 
     | 
    
         
            -
                  def initialize(model_klass)
         
     | 
| 
       16 
     | 
    
         
            -
                    @model_klass = model_klass
         
     | 
| 
       17 
     | 
    
         
            -
                  end
         
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
      
 9 
     | 
    
         
            +
                class ManyBase < ActiveModel::Type::Value
         
     | 
| 
       19 
10 
     | 
    
         
             
                  # Returns type
         
     | 
| 
       20 
11 
     | 
    
         
             
                  #
         
     | 
| 
       21 
12 
     | 
    
         
             
                  # @return [Symbol]
         
     | 
| 
       22 
13 
     | 
    
         
             
                  def type
         
     | 
| 
       23 
     | 
    
         
            -
                     
     | 
| 
      
 14 
     | 
    
         
            +
                    raise NotImplementedError
         
     | 
| 
       24 
15 
     | 
    
         
             
                  end
         
     | 
| 
       25 
16 
     | 
    
         | 
| 
       26 
17 
     | 
    
         
             
                  # Casts +value+ from DB or user to StoreModel::Model instance
         
     | 
| 
         @@ -34,8 +25,7 @@ module StoreModel 
     | 
|
| 
       34 
25 
     | 
    
         
             
                    when Array then ensure_model_class(value)
         
     | 
| 
       35 
26 
     | 
    
         
             
                    when nil then value
         
     | 
| 
       36 
27 
     | 
    
         
             
                    else
         
     | 
| 
       37 
     | 
    
         
            -
                       
     | 
| 
       38 
     | 
    
         
            -
                            "failed casting #{value.inspect}, only String or Array instances are allowed"
         
     | 
| 
      
 28 
     | 
    
         
            +
                      raise_cast_error(value)
         
     | 
| 
       39 
29 
     | 
    
         
             
                    end
         
     | 
| 
       40 
30 
     | 
    
         
             
                  end
         
     | 
| 
       41 
31 
     | 
    
         | 
| 
         @@ -64,28 +54,28 @@ module StoreModel 
     | 
|
| 
       64 
54 
     | 
    
         
             
                    cast_value(raw_old_value) != new_value
         
     | 
| 
       65 
55 
     | 
    
         
             
                  end
         
     | 
| 
       66 
56 
     | 
    
         | 
| 
       67 
     | 
    
         
            -
                   
     | 
| 
      
 57 
     | 
    
         
            +
                  protected
         
     | 
| 
       68 
58 
     | 
    
         | 
| 
       69 
     | 
    
         
            -
                   
     | 
| 
       70 
     | 
    
         
            -
             
     | 
| 
       71 
     | 
    
         
            -
                    decoded = ActiveSupport::JSON.decode(array_value) rescue []
         
     | 
| 
       72 
     | 
    
         
            -
                    decoded.map { |attributes| cast_model_type_value(attributes) }
         
     | 
| 
      
 59 
     | 
    
         
            +
                  def ensure_model_class(_array)
         
     | 
| 
      
 60 
     | 
    
         
            +
                    raise NotImplementedError
         
     | 
| 
       73 
61 
     | 
    
         
             
                  end
         
     | 
| 
       74 
     | 
    
         
            -
                  # rubocop:enable Style/RescueModifier
         
     | 
| 
       75 
62 
     | 
    
         | 
| 
       76 
     | 
    
         
            -
                  def  
     | 
| 
       77 
     | 
    
         
            -
                     
     | 
| 
       78 
     | 
    
         
            -
                      object.is_a?(@model_klass) ? object : cast_model_type_value(object)
         
     | 
| 
       79 
     | 
    
         
            -
                    end
         
     | 
| 
      
 63 
     | 
    
         
            +
                  def cast_model_type_value(_value)
         
     | 
| 
      
 64 
     | 
    
         
            +
                    raise NotImplementedError
         
     | 
| 
       80 
65 
     | 
    
         
             
                  end
         
     | 
| 
       81 
66 
     | 
    
         | 
| 
       82 
     | 
    
         
            -
                  def  
     | 
| 
       83 
     | 
    
         
            -
                     
     | 
| 
      
 67 
     | 
    
         
            +
                  def raise_cast_error(_value)
         
     | 
| 
      
 68 
     | 
    
         
            +
                    raise NotImplementedError
         
     | 
| 
       84 
69 
     | 
    
         
             
                  end
         
     | 
| 
       85 
70 
     | 
    
         | 
| 
       86 
     | 
    
         
            -
                   
     | 
| 
       87 
     | 
    
         
            -
             
     | 
| 
      
 71 
     | 
    
         
            +
                  private
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                  # rubocop:disable Style/RescueModifier
         
     | 
| 
      
 74 
     | 
    
         
            +
                  def decode_and_initialize(array_value)
         
     | 
| 
      
 75 
     | 
    
         
            +
                    decoded = ActiveSupport::JSON.decode(array_value) rescue []
         
     | 
| 
      
 76 
     | 
    
         
            +
                    decoded.map { |attributes| cast_model_type_value(attributes) }
         
     | 
| 
       88 
77 
     | 
    
         
             
                  end
         
     | 
| 
      
 78 
     | 
    
         
            +
                  # rubocop:enable Style/RescueModifier
         
     | 
| 
       89 
79 
     | 
    
         
             
                end
         
     | 
| 
       90 
80 
     | 
    
         
             
              end
         
     | 
| 
       91 
81 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,53 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require "active_model"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module StoreModel
         
     | 
| 
      
 6 
     | 
    
         
            +
              module Types
         
     | 
| 
      
 7 
     | 
    
         
            +
                # Implements ActiveModel::Type::Value type for handling an array of
         
     | 
| 
      
 8 
     | 
    
         
            +
                # StoreModel::Model
         
     | 
| 
      
 9 
     | 
    
         
            +
                class ManyPolymorphic < ManyBase
         
     | 
| 
      
 10 
     | 
    
         
            +
                  include PolymorphicHelper
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  # Initializes type for model class
         
     | 
| 
      
 13 
     | 
    
         
            +
                  #
         
     | 
| 
      
 14 
     | 
    
         
            +
                  # @param model_wrapper [Proc] class to handle
         
     | 
| 
      
 15 
     | 
    
         
            +
                  #
         
     | 
| 
      
 16 
     | 
    
         
            +
                  # @return [StoreModel::Types::PolymorphicArrayType ]
         
     | 
| 
      
 17 
     | 
    
         
            +
                  def initialize(model_wrapper)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    @model_wrapper = model_wrapper
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  # Returns type
         
     | 
| 
      
 22 
     | 
    
         
            +
                  #
         
     | 
| 
      
 23 
     | 
    
         
            +
                  # @return [Symbol]
         
     | 
| 
      
 24 
     | 
    
         
            +
                  def type
         
     | 
| 
      
 25 
     | 
    
         
            +
                    :polymorphic_array
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  private
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  def ensure_model_class(array)
         
     | 
| 
      
 31 
     | 
    
         
            +
                    array.map do |object|
         
     | 
| 
      
 32 
     | 
    
         
            +
                      next object if implements_model?(object.class)
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                      cast_model_type_value(object)
         
     | 
| 
      
 35 
     | 
    
         
            +
                    end
         
     | 
| 
      
 36 
     | 
    
         
            +
                  end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                  def cast_model_type_value(value)
         
     | 
| 
      
 39 
     | 
    
         
            +
                    model_klass = @model_wrapper.call(value)
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                    raise_extract_wrapper_error(model_klass) unless implements_model?(model_klass)
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                    model_klass.to_type.cast_value(value)
         
     | 
| 
      
 44 
     | 
    
         
            +
                  end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                  def raise_cast_error(value)
         
     | 
| 
      
 47 
     | 
    
         
            +
                    raise StoreModel::Types::CastError,
         
     | 
| 
      
 48 
     | 
    
         
            +
                          "failed casting #{value.inspect}, only String, " \
         
     | 
| 
      
 49 
     | 
    
         
            +
                          "Hash or instances which implement StoreModel::Model are allowed"
         
     | 
| 
      
 50 
     | 
    
         
            +
                  end
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
              end
         
     | 
| 
      
 53 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -5,12 +5,12 @@ require "active_model" 
     | 
|
| 
       5 
5 
     | 
    
         
             
            module StoreModel
         
     | 
| 
       6 
6 
     | 
    
         
             
              module Types
         
     | 
| 
       7 
7 
     | 
    
         
             
                # Implements ActiveModel::Type::Value type for handling an instance of StoreModel::Model
         
     | 
| 
       8 
     | 
    
         
            -
                class  
     | 
| 
      
 8 
     | 
    
         
            +
                class One < OneBase
         
     | 
| 
       9 
9 
     | 
    
         
             
                  # Initializes type for model class
         
     | 
| 
       10 
10 
     | 
    
         
             
                  #
         
     | 
| 
       11 
11 
     | 
    
         
             
                  # @param model_klass [StoreModel::Model] model class to handle
         
     | 
| 
       12 
12 
     | 
    
         
             
                  #
         
     | 
| 
       13 
     | 
    
         
            -
                  # @return [StoreModel::Types:: 
     | 
| 
      
 13 
     | 
    
         
            +
                  # @return [StoreModel::Types::One]
         
     | 
| 
       14 
14 
     | 
    
         
             
                  def initialize(model_klass)
         
     | 
| 
       15 
15 
     | 
    
         
             
                    @model_klass = model_klass
         
     | 
| 
       16 
16 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -30,7 +30,7 @@ module StoreModel 
     | 
|
| 
       30 
30 
     | 
    
         
             
                  def cast_value(value)
         
     | 
| 
       31 
31 
     | 
    
         
             
                    case value
         
     | 
| 
       32 
32 
     | 
    
         
             
                    when String then decode_and_initialize(value)
         
     | 
| 
       33 
     | 
    
         
            -
                    when Hash then  
     | 
| 
      
 33 
     | 
    
         
            +
                    when Hash then model_instance(value)
         
     | 
| 
       34 
34 
     | 
    
         
             
                    when @model_klass, nil then value
         
     | 
| 
       35 
35 
     | 
    
         
             
                    else raise_cast_error(value)
         
     | 
| 
       36 
36 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -53,40 +53,16 @@ module StoreModel 
     | 
|
| 
       53 
53 
     | 
    
         
             
                    end
         
     | 
| 
       54 
54 
     | 
    
         
             
                  end
         
     | 
| 
       55 
55 
     | 
    
         | 
| 
       56 
     | 
    
         
            -
                  # Determines whether the mutable value has been modified since it was read
         
     | 
| 
       57 
     | 
    
         
            -
                  #
         
     | 
| 
       58 
     | 
    
         
            -
                  # @param raw_old_value [Object] old value
         
     | 
| 
       59 
     | 
    
         
            -
                  # @param new_value [Object] new value
         
     | 
| 
       60 
     | 
    
         
            -
                  #
         
     | 
| 
       61 
     | 
    
         
            -
                  # @return [Boolean]
         
     | 
| 
       62 
     | 
    
         
            -
                  def changed_in_place?(raw_old_value, new_value)
         
     | 
| 
       63 
     | 
    
         
            -
                    cast_value(raw_old_value) != new_value
         
     | 
| 
       64 
     | 
    
         
            -
                  end
         
     | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
       66 
56 
     | 
    
         
             
                  private
         
     | 
| 
       67 
57 
     | 
    
         | 
| 
       68 
     | 
    
         
            -
                  # rubocop:disable Style/RescueModifier
         
     | 
| 
       69 
     | 
    
         
            -
                  def decode_and_initialize(value)
         
     | 
| 
       70 
     | 
    
         
            -
                    decoded = ActiveSupport::JSON.decode(value) rescue nil
         
     | 
| 
       71 
     | 
    
         
            -
                    @model_klass.new(decoded) unless decoded.nil?
         
     | 
| 
       72 
     | 
    
         
            -
                  rescue ActiveModel::UnknownAttributeError => e
         
     | 
| 
       73 
     | 
    
         
            -
                    handle_unknown_attribute(decoded, e)
         
     | 
| 
       74 
     | 
    
         
            -
                  end
         
     | 
| 
       75 
     | 
    
         
            -
                  # rubocop:enable Style/RescueModifier
         
     | 
| 
       76 
     | 
    
         
            -
             
     | 
| 
       77 
58 
     | 
    
         
             
                  def raise_cast_error(value)
         
     | 
| 
       78 
59 
     | 
    
         
             
                    raise StoreModel::Types::CastError,
         
     | 
| 
       79 
60 
     | 
    
         
             
                          "failed casting #{value.inspect}, only String, " \
         
     | 
| 
       80 
61 
     | 
    
         
             
                          "Hash or #{@model_klass.name} instances are allowed"
         
     | 
| 
       81 
62 
     | 
    
         
             
                  end
         
     | 
| 
       82 
63 
     | 
    
         | 
| 
       83 
     | 
    
         
            -
                  def  
     | 
| 
       84 
     | 
    
         
            -
                     
     | 
| 
       85 
     | 
    
         
            -
                    value_symbolized = value.symbolize_keys
         
     | 
| 
       86 
     | 
    
         
            -
             
     | 
| 
       87 
     | 
    
         
            -
                    cast_value(value_symbolized.except(attribute)).tap do |configuration|
         
     | 
| 
       88 
     | 
    
         
            -
                      configuration.unknown_attributes[attribute.to_s] = value_symbolized[attribute]
         
     | 
| 
       89 
     | 
    
         
            -
                    end
         
     | 
| 
      
 64 
     | 
    
         
            +
                  def model_instance(value)
         
     | 
| 
      
 65 
     | 
    
         
            +
                    @model_klass.new(value)
         
     | 
| 
       90 
66 
     | 
    
         
             
                  end
         
     | 
| 
       91 
67 
     | 
    
         
             
                end
         
     | 
| 
       92 
68 
     | 
    
         
             
              end
         
     | 
| 
         @@ -0,0 +1,67 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require "active_model"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module StoreModel
         
     | 
| 
      
 6 
     | 
    
         
            +
              module Types
         
     | 
| 
      
 7 
     | 
    
         
            +
                # Implements ActiveModel::Type::Value type for handling an instance of StoreModel::Model
         
     | 
| 
      
 8 
     | 
    
         
            +
                class OneBase < ActiveModel::Type::Value
         
     | 
| 
      
 9 
     | 
    
         
            +
                  # Returns type
         
     | 
| 
      
 10 
     | 
    
         
            +
                  #
         
     | 
| 
      
 11 
     | 
    
         
            +
                  # @return [Symbol]
         
     | 
| 
      
 12 
     | 
    
         
            +
                  def type
         
     | 
| 
      
 13 
     | 
    
         
            +
                    raise NotImplementedError
         
     | 
| 
      
 14 
     | 
    
         
            +
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  # Casts +value+ from DB or user to StoreModel::Model instance
         
     | 
| 
      
 17 
     | 
    
         
            +
                  #
         
     | 
| 
      
 18 
     | 
    
         
            +
                  # @param value [Object] a value to cast
         
     | 
| 
      
 19 
     | 
    
         
            +
                  #
         
     | 
| 
      
 20 
     | 
    
         
            +
                  # @return StoreModel::Model
         
     | 
| 
      
 21 
     | 
    
         
            +
                  def cast_value(_value)
         
     | 
| 
      
 22 
     | 
    
         
            +
                    raise NotImplementedError
         
     | 
| 
      
 23 
     | 
    
         
            +
                  end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                  # Determines whether the mutable value has been modified since it was read
         
     | 
| 
      
 26 
     | 
    
         
            +
                  #
         
     | 
| 
      
 27 
     | 
    
         
            +
                  # @param raw_old_value [Object] old value
         
     | 
| 
      
 28 
     | 
    
         
            +
                  # @param new_value [Object] new value
         
     | 
| 
      
 29 
     | 
    
         
            +
                  #
         
     | 
| 
      
 30 
     | 
    
         
            +
                  # @return [Boolean]
         
     | 
| 
      
 31 
     | 
    
         
            +
                  def changed_in_place?(raw_old_value, new_value)
         
     | 
| 
      
 32 
     | 
    
         
            +
                    cast_value(raw_old_value) != new_value
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                  protected
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  def raise_cast_error(_value)
         
     | 
| 
      
 38 
     | 
    
         
            +
                    raise NotImplementedError
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  def model_instance(_value)
         
     | 
| 
      
 42 
     | 
    
         
            +
                    raise NotImplementedError
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                  private
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                  # rubocop:disable Style/RescueModifier
         
     | 
| 
      
 48 
     | 
    
         
            +
                  def decode_and_initialize(value)
         
     | 
| 
      
 49 
     | 
    
         
            +
                    decoded = ActiveSupport::JSON.decode(value) rescue nil
         
     | 
| 
      
 50 
     | 
    
         
            +
                    model_instance(decoded) unless decoded.nil?
         
     | 
| 
      
 51 
     | 
    
         
            +
                  rescue ActiveModel::UnknownAttributeError => e
         
     | 
| 
      
 52 
     | 
    
         
            +
                    handle_unknown_attribute(decoded, e)
         
     | 
| 
      
 53 
     | 
    
         
            +
                  end
         
     | 
| 
      
 54 
     | 
    
         
            +
                  # rubocop:enable Style/RescueModifier
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                  def handle_unknown_attribute(value, exception)
         
     | 
| 
      
 57 
     | 
    
         
            +
                    attribute = exception.attribute.to_sym
         
     | 
| 
      
 58 
     | 
    
         
            +
                    value_symbolized = value.symbolize_keys
         
     | 
| 
      
 59 
     | 
    
         
            +
                    value_symbolized = value_symbolized[:attributes] if value_symbolized.key?(:attributes)
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                    cast_value(value_symbolized.except(attribute)).tap do |configuration|
         
     | 
| 
      
 62 
     | 
    
         
            +
                      configuration.unknown_attributes[attribute.to_s] = value_symbolized[attribute]
         
     | 
| 
      
 63 
     | 
    
         
            +
                    end
         
     | 
| 
      
 64 
     | 
    
         
            +
                  end
         
     | 
| 
      
 65 
     | 
    
         
            +
                end
         
     | 
| 
      
 66 
     | 
    
         
            +
              end
         
     | 
| 
      
 67 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,23 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require "active_model"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module StoreModel
         
     | 
| 
      
 6 
     | 
    
         
            +
              module Types
         
     | 
| 
      
 7 
     | 
    
         
            +
                # Implements ActiveModel::Type::Value type for handling an array of
         
     | 
| 
      
 8 
     | 
    
         
            +
                # StoreModel::Model
         
     | 
| 
      
 9 
     | 
    
         
            +
                class OneOf
         
     | 
| 
      
 10 
     | 
    
         
            +
                  def initialize(&block)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    @block = block
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  def to_type
         
     | 
| 
      
 15 
     | 
    
         
            +
                    Types::OnePolymorphic.new(@block)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  def to_array_type
         
     | 
| 
      
 19 
     | 
    
         
            +
                    Types::ManyPolymorphic.new(@block)
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,89 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require "active_model"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module StoreModel
         
     | 
| 
      
 6 
     | 
    
         
            +
              module Types
         
     | 
| 
      
 7 
     | 
    
         
            +
                # Implements ActiveModel::Type::Value type for handling an instance of StoreModel::Model
         
     | 
| 
      
 8 
     | 
    
         
            +
                class OnePolymorphic < OneBase
         
     | 
| 
      
 9 
     | 
    
         
            +
                  include PolymorphicHelper
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                  # Initializes type for model class
         
     | 
| 
      
 12 
     | 
    
         
            +
                  #
         
     | 
| 
      
 13 
     | 
    
         
            +
                  # @param model_wrapper [Proc] class to handle
         
     | 
| 
      
 14 
     | 
    
         
            +
                  #
         
     | 
| 
      
 15 
     | 
    
         
            +
                  # @return [StoreModel::Types::OnePolymorphic ]
         
     | 
| 
      
 16 
     | 
    
         
            +
                  def initialize(model_wrapper)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    @model_wrapper = model_wrapper
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  # Returns type
         
     | 
| 
      
 21 
     | 
    
         
            +
                  #
         
     | 
| 
      
 22 
     | 
    
         
            +
                  # @return [Symbol]
         
     | 
| 
      
 23 
     | 
    
         
            +
                  def type
         
     | 
| 
      
 24 
     | 
    
         
            +
                    :polymorphic
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  # Casts +value+ from DB or user to StoreModel::Model instance
         
     | 
| 
      
 28 
     | 
    
         
            +
                  #
         
     | 
| 
      
 29 
     | 
    
         
            +
                  # @param value [Object] a value to cast
         
     | 
| 
      
 30 
     | 
    
         
            +
                  #
         
     | 
| 
      
 31 
     | 
    
         
            +
                  # @return StoreModel::Model
         
     | 
| 
      
 32 
     | 
    
         
            +
                  def cast_value(value)
         
     | 
| 
      
 33 
     | 
    
         
            +
                    case value
         
     | 
| 
      
 34 
     | 
    
         
            +
                    when String then decode_and_initialize(value)
         
     | 
| 
      
 35 
     | 
    
         
            +
                    when Hash then extract_model_klass(value).new(value)
         
     | 
| 
      
 36 
     | 
    
         
            +
                    when nil then value
         
     | 
| 
      
 37 
     | 
    
         
            +
                    else
         
     | 
| 
      
 38 
     | 
    
         
            +
                      raise_cast_error(value) unless value.class.ancestors.include?(StoreModel::Model)
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                      value
         
     | 
| 
      
 41 
     | 
    
         
            +
                    end
         
     | 
| 
      
 42 
     | 
    
         
            +
                  rescue ActiveModel::UnknownAttributeError => e
         
     | 
| 
      
 43 
     | 
    
         
            +
                    handle_unknown_attribute(value, e)
         
     | 
| 
      
 44 
     | 
    
         
            +
                  end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                  # Casts a value from the ruby type to a type that the database knows how
         
     | 
| 
      
 47 
     | 
    
         
            +
                  # to understand.
         
     | 
| 
      
 48 
     | 
    
         
            +
                  #
         
     | 
| 
      
 49 
     | 
    
         
            +
                  # @param value [Object] value to serialize
         
     | 
| 
      
 50 
     | 
    
         
            +
                  #
         
     | 
| 
      
 51 
     | 
    
         
            +
                  # @return [String] serialized value
         
     | 
| 
      
 52 
     | 
    
         
            +
                  def serialize(value)
         
     | 
| 
      
 53 
     | 
    
         
            +
                    case value
         
     | 
| 
      
 54 
     | 
    
         
            +
                    when Hash
         
     | 
| 
      
 55 
     | 
    
         
            +
                      ActiveSupport::JSON.encode(value)
         
     | 
| 
      
 56 
     | 
    
         
            +
                    else
         
     | 
| 
      
 57 
     | 
    
         
            +
                      return ActiveSupport::JSON.encode(value) if implements_model?(value.class)
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                      super
         
     | 
| 
      
 60 
     | 
    
         
            +
                    end
         
     | 
| 
      
 61 
     | 
    
         
            +
                  end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                  protected
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                  # Check if block returns an appropriate class and raise cast error if not
         
     | 
| 
      
 66 
     | 
    
         
            +
                  #
         
     | 
| 
      
 67 
     | 
    
         
            +
                  # @param value [Object] raw data
         
     | 
| 
      
 68 
     | 
    
         
            +
                  #
         
     | 
| 
      
 69 
     | 
    
         
            +
                  # @return [Class] which implements StoreModel::Model
         
     | 
| 
      
 70 
     | 
    
         
            +
                  def extract_model_klass(value)
         
     | 
| 
      
 71 
     | 
    
         
            +
                    model_klass = @model_wrapper.call(value)
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                    raise_extract_wrapper_error(model_klass) unless implements_model?(model_klass)
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                    model_klass
         
     | 
| 
      
 76 
     | 
    
         
            +
                  end
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                  def raise_cast_error(value)
         
     | 
| 
      
 79 
     | 
    
         
            +
                    raise StoreModel::Types::CastError,
         
     | 
| 
      
 80 
     | 
    
         
            +
                          "failed casting #{value.inspect}, only String, " \
         
     | 
| 
      
 81 
     | 
    
         
            +
                          "Hash or instances which implement StoreModel::Model are allowed"
         
     | 
| 
      
 82 
     | 
    
         
            +
                  end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                  def model_instance(value)
         
     | 
| 
      
 85 
     | 
    
         
            +
                    extract_model_klass(value).new(value)
         
     | 
| 
      
 86 
     | 
    
         
            +
                  end
         
     | 
| 
      
 87 
     | 
    
         
            +
                end
         
     | 
| 
      
 88 
     | 
    
         
            +
              end
         
     | 
| 
      
 89 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,13 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            # Shared methods for polymorphic classes
         
     | 
| 
      
 4 
     | 
    
         
            +
            module PolymorphicHelper
         
     | 
| 
      
 5 
     | 
    
         
            +
              def raise_extract_wrapper_error(invalid_klass)
         
     | 
| 
      
 6 
     | 
    
         
            +
                raise StoreModel::Types::ExpandWrapperError,
         
     | 
| 
      
 7 
     | 
    
         
            +
                      "#{invalid_klass.inspect} is an invalid model klass"
         
     | 
| 
      
 8 
     | 
    
         
            +
              end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
              def implements_model?(klass)
         
     | 
| 
      
 11 
     | 
    
         
            +
                klass&.ancestors&.include?(StoreModel::Model)
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/store_model/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | 
         @@ -1,14 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: store_model
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 0. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.10.0
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - DmitryTsepelev
         
     | 
| 
       8 
     | 
    
         
            -
            autorequire: 
     | 
| 
      
 8 
     | 
    
         
            +
            autorequire:
         
     | 
| 
       9 
9 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       10 
10 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
     | 
    
         
            -
            date:  
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2021-07-06 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
14 
     | 
    
         
             
              name: activerecord
         
     | 
| 
         @@ -56,16 +56,16 @@ dependencies: 
     | 
|
| 
       56 
56 
     | 
    
         
             
              name: rubocop
         
     | 
| 
       57 
57 
     | 
    
         
             
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
       58 
58 
     | 
    
         
             
                requirements:
         
     | 
| 
       59 
     | 
    
         
            -
                - -  
     | 
| 
      
 59 
     | 
    
         
            +
                - - '='
         
     | 
| 
       60 
60 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       61 
     | 
    
         
            -
                    version:  
     | 
| 
      
 61 
     | 
    
         
            +
                    version: 0.64.0
         
     | 
| 
       62 
62 
     | 
    
         
             
              type: :development
         
     | 
| 
       63 
63 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       64 
64 
     | 
    
         
             
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
       65 
65 
     | 
    
         
             
                requirements:
         
     | 
| 
       66 
     | 
    
         
            -
                - -  
     | 
| 
      
 66 
     | 
    
         
            +
                - - '='
         
     | 
| 
       67 
67 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       68 
     | 
    
         
            -
                    version:  
     | 
| 
      
 68 
     | 
    
         
            +
                    version: 0.64.0
         
     | 
| 
       69 
69 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       70 
70 
     | 
    
         
             
              name: coveralls
         
     | 
| 
       71 
71 
     | 
    
         
             
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
         @@ -106,15 +106,21 @@ files: 
     | 
|
| 
       106 
106 
     | 
    
         
             
            - lib/store_model/railtie.rb
         
     | 
| 
       107 
107 
     | 
    
         
             
            - lib/store_model/type_builders.rb
         
     | 
| 
       108 
108 
     | 
    
         
             
            - lib/store_model/types.rb
         
     | 
| 
       109 
     | 
    
         
            -
            - lib/store_model/types/array_type.rb
         
     | 
| 
       110 
109 
     | 
    
         
             
            - lib/store_model/types/enum_type.rb
         
     | 
| 
       111 
     | 
    
         
            -
            - lib/store_model/types/ 
     | 
| 
      
 110 
     | 
    
         
            +
            - lib/store_model/types/many.rb
         
     | 
| 
      
 111 
     | 
    
         
            +
            - lib/store_model/types/many_base.rb
         
     | 
| 
      
 112 
     | 
    
         
            +
            - lib/store_model/types/many_polymorphic.rb
         
     | 
| 
      
 113 
     | 
    
         
            +
            - lib/store_model/types/one.rb
         
     | 
| 
      
 114 
     | 
    
         
            +
            - lib/store_model/types/one_base.rb
         
     | 
| 
      
 115 
     | 
    
         
            +
            - lib/store_model/types/one_of.rb
         
     | 
| 
      
 116 
     | 
    
         
            +
            - lib/store_model/types/one_polymorphic.rb
         
     | 
| 
      
 117 
     | 
    
         
            +
            - lib/store_model/types/polymorphic_helper.rb
         
     | 
| 
       112 
118 
     | 
    
         
             
            - lib/store_model/version.rb
         
     | 
| 
       113 
119 
     | 
    
         
             
            homepage: https://github.com/DmitryTsepelev/store_model
         
     | 
| 
       114 
120 
     | 
    
         
             
            licenses:
         
     | 
| 
       115 
121 
     | 
    
         
             
            - MIT
         
     | 
| 
       116 
122 
     | 
    
         
             
            metadata: {}
         
     | 
| 
       117 
     | 
    
         
            -
            post_install_message: 
     | 
| 
      
 123 
     | 
    
         
            +
            post_install_message:
         
     | 
| 
       118 
124 
     | 
    
         
             
            rdoc_options: []
         
     | 
| 
       119 
125 
     | 
    
         
             
            require_paths:
         
     | 
| 
       120 
126 
     | 
    
         
             
            - lib
         
     | 
| 
         @@ -129,8 +135,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement 
     | 
|
| 
       129 
135 
     | 
    
         
             
                - !ruby/object:Gem::Version
         
     | 
| 
       130 
136 
     | 
    
         
             
                  version: '0'
         
     | 
| 
       131 
137 
     | 
    
         
             
            requirements: []
         
     | 
| 
       132 
     | 
    
         
            -
            rubygems_version: 3. 
     | 
| 
       133 
     | 
    
         
            -
            signing_key: 
     | 
| 
      
 138 
     | 
    
         
            +
            rubygems_version: 3.1.2
         
     | 
| 
      
 139 
     | 
    
         
            +
            signing_key:
         
     | 
| 
       134 
140 
     | 
    
         
             
            specification_version: 4
         
     | 
| 
       135 
141 
     | 
    
         
             
            summary: Gem for working with JSON-backed attributes as ActiveRecord models
         
     | 
| 
       136 
142 
     | 
    
         
             
            test_files: []
         
     |