iknow_view_models 3.1.8 → 3.2.4
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/.circleci/config.yml +6 -6
- data/.rubocop.yml +18 -0
- data/Appraisals +6 -6
- data/Gemfile +6 -2
- data/Rakefile +5 -5
- data/gemfiles/rails_5_2.gemfile +5 -5
- data/gemfiles/rails_6_0.gemfile +9 -0
- data/iknow_view_models.gemspec +40 -38
- data/lib/iknow_view_models.rb +9 -7
- data/lib/iknow_view_models/version.rb +1 -1
- data/lib/view_model.rb +31 -17
- data/lib/view_model/access_control.rb +5 -2
- data/lib/view_model/access_control/composed.rb +10 -9
- data/lib/view_model/access_control/open.rb +2 -0
- data/lib/view_model/access_control/read_only.rb +2 -0
- data/lib/view_model/access_control/tree.rb +11 -6
- data/lib/view_model/access_control_error.rb +4 -1
- data/lib/view_model/active_record.rb +17 -15
- data/lib/view_model/active_record/association_data.rb +2 -1
- data/lib/view_model/active_record/association_manipulation.rb +6 -4
- data/lib/view_model/active_record/cache.rb +114 -34
- data/lib/view_model/active_record/cache/cacheable_view.rb +2 -2
- data/lib/view_model/active_record/collection_nested_controller.rb +3 -3
- data/lib/view_model/active_record/controller.rb +68 -1
- data/lib/view_model/active_record/controller_base.rb +4 -1
- data/lib/view_model/active_record/nested_controller_base.rb +1 -0
- data/lib/view_model/active_record/update_context.rb +8 -6
- data/lib/view_model/active_record/update_data.rb +32 -30
- data/lib/view_model/active_record/update_operation.rb +17 -13
- data/lib/view_model/active_record/visitor.rb +0 -1
- data/lib/view_model/after_transaction_runner.rb +0 -1
- data/lib/view_model/callbacks.rb +3 -1
- data/lib/view_model/controller.rb +13 -3
- data/lib/view_model/deserialization_error.rb +15 -12
- data/lib/view_model/error.rb +12 -10
- data/lib/view_model/error_view.rb +3 -1
- data/lib/view_model/migratable_view.rb +78 -0
- data/lib/view_model/migration.rb +48 -0
- data/lib/view_model/migration/no_path_error.rb +26 -0
- data/lib/view_model/migration/one_way_error.rb +24 -0
- data/lib/view_model/migration/unspecified_version_error.rb +24 -0
- data/lib/view_model/migrator.rb +108 -0
- data/lib/view_model/record.rb +15 -14
- data/lib/view_model/reference.rb +3 -1
- data/lib/view_model/references.rb +8 -5
- data/lib/view_model/registry.rb +14 -2
- data/lib/view_model/schemas.rb +9 -4
- data/lib/view_model/serialization_error.rb +4 -1
- data/lib/view_model/serialize_context.rb +4 -4
- data/lib/view_model/test_helpers.rb +8 -3
- data/lib/view_model/test_helpers/arvm_builder.rb +21 -15
- data/lib/view_model/traversal_context.rb +2 -1
- data/nix/dependencies.nix +5 -0
- data/nix/gem/generate.rb +2 -1
- data/shell.nix +8 -3
- data/test/.rubocop.yml +14 -0
- data/test/helpers/arvm_test_models.rb +12 -9
- data/test/helpers/arvm_test_utilities.rb +5 -3
- data/test/helpers/controller_test_helpers.rb +55 -32
- data/test/helpers/match_enumerator.rb +1 -0
- data/test/helpers/query_logging.rb +2 -1
- data/test/helpers/test_access_control.rb +5 -3
- data/test/helpers/viewmodel_spec_helpers.rb +88 -22
- data/test/unit/view_model/access_control_test.rb +144 -144
- data/test/unit/view_model/active_record/alias_test.rb +15 -13
- data/test/unit/view_model/active_record/belongs_to_test.rb +40 -39
- data/test/unit/view_model/active_record/cache_test.rb +68 -31
- data/test/unit/view_model/active_record/cloner_test.rb +67 -63
- data/test/unit/view_model/active_record/controller_test.rb +113 -65
- data/test/unit/view_model/active_record/counter_test.rb +10 -9
- data/test/unit/view_model/active_record/customization_test.rb +59 -58
- data/test/unit/view_model/active_record/has_many_test.rb +112 -111
- data/test/unit/view_model/active_record/has_many_through_poly_test.rb +15 -14
- data/test/unit/view_model/active_record/has_many_through_test.rb +33 -38
- data/test/unit/view_model/active_record/has_one_test.rb +37 -36
- data/test/unit/view_model/active_record/migration_test.rb +161 -0
- data/test/unit/view_model/active_record/namespacing_test.rb +19 -17
- data/test/unit/view_model/active_record/poly_test.rb +44 -45
- data/test/unit/view_model/active_record/shared_test.rb +30 -28
- data/test/unit/view_model/active_record/version_test.rb +9 -7
- data/test/unit/view_model/active_record_test.rb +72 -72
- data/test/unit/view_model/callbacks_test.rb +19 -15
- data/test/unit/view_model/controller_test.rb +4 -2
- data/test/unit/view_model/record_test.rb +158 -145
- data/test/unit/view_model/registry_test.rb +38 -0
- data/test/unit/view_model/traversal_context_test.rb +4 -5
- data/test/unit/view_model_test.rb +18 -16
- metadata +38 -12
- data/.travis.yml +0 -31
- data/appveyor.yml +0 -22
- data/gemfiles/rails_6_0_beta.gemfile +0 -9
| @@ -0,0 +1,161 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require_relative '../../../helpers/arvm_test_utilities'
         | 
| 4 | 
            +
            require_relative '../../../helpers/arvm_test_models'
         | 
| 5 | 
            +
            require_relative '../../../helpers/viewmodel_spec_helpers'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            require 'minitest/autorun'
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            require 'view_model/active_record'
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            class ViewModel::ActiveRecord::Migration < ActiveSupport::TestCase
         | 
| 12 | 
            +
              include ARVMTestUtilities
         | 
| 13 | 
            +
              extend Minitest::Spec::DSL
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              include ViewModelSpecHelpers::ParentAndBelongsToChildWithMigration
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              def new_model
         | 
| 18 | 
            +
                model_class.new(name: 'm1', child: child_model_class.new(name: 'c1'))
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              let(:viewmodel) { create_viewmodel! }
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              let(:current_serialization) { ViewModel.serialize_to_hash(viewmodel) }
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              let(:v2_serialization) do
         | 
| 26 | 
            +
                {
         | 
| 27 | 
            +
                  ViewModel::TYPE_ATTRIBUTE => viewmodel_class.view_name,
         | 
| 28 | 
            +
                  ViewModel::VERSION_ATTRIBUTE => 2,
         | 
| 29 | 
            +
                  ViewModel::ID_ATTRIBUTE => viewmodel.id,
         | 
| 30 | 
            +
                  'name' => viewmodel.name,
         | 
| 31 | 
            +
                  'old_field' => 1,
         | 
| 32 | 
            +
                  'child' => {
         | 
| 33 | 
            +
                    ViewModel::TYPE_ATTRIBUTE => child_viewmodel_class.view_name,
         | 
| 34 | 
            +
                    ViewModel::VERSION_ATTRIBUTE => 2,
         | 
| 35 | 
            +
                    ViewModel::ID_ATTRIBUTE => viewmodel.child.id,
         | 
| 36 | 
            +
                    'name' => viewmodel.child.name,
         | 
| 37 | 
            +
                    'former_field' => 'former_value',
         | 
| 38 | 
            +
                  },
         | 
| 39 | 
            +
                }
         | 
| 40 | 
            +
              end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
              let(:migration_versions) { { viewmodel_class => 2, child_viewmodel_class => 2 } }
         | 
| 43 | 
            +
             | 
| 44 | 
            +
              let(:down_migrator) { ViewModel::DownMigrator.new(migration_versions) }
         | 
| 45 | 
            +
              let(:up_migrator) { ViewModel::UpMigrator.new(migration_versions) }
         | 
| 46 | 
            +
             | 
| 47 | 
            +
              def migrate!
         | 
| 48 | 
            +
                migrator.migrate!(subject, references: {})
         | 
| 49 | 
            +
              end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
              describe 'downwards' do
         | 
| 52 | 
            +
                let(:migrator) { down_migrator }
         | 
| 53 | 
            +
                let(:subject) { current_serialization.deep_dup }
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                let(:expected_result) do
         | 
| 56 | 
            +
                  v2_serialization.deep_merge(
         | 
| 57 | 
            +
                    {
         | 
| 58 | 
            +
                      ViewModel::MIGRATED_ATTRIBUTE => true,
         | 
| 59 | 
            +
                      'old_field' => -1,
         | 
| 60 | 
            +
                      'child' => {
         | 
| 61 | 
            +
                        ViewModel::MIGRATED_ATTRIBUTE => true,
         | 
| 62 | 
            +
                        'former_field' => 'reconstructed',
         | 
| 63 | 
            +
                      },
         | 
| 64 | 
            +
                    },
         | 
| 65 | 
            +
                  )
         | 
| 66 | 
            +
                end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                it 'migrates' do
         | 
| 69 | 
            +
                  migrate!
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                  assert_equal(expected_result, subject)
         | 
| 72 | 
            +
                end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                describe 'to an unreachable version' do
         | 
| 75 | 
            +
                  let(:migration_versions) { { viewmodel_class => 2, child_viewmodel_class => 1 } }
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                  it 'raises' do
         | 
| 78 | 
            +
                    assert_raises(ViewModel::Migration::NoPathError) do
         | 
| 79 | 
            +
                      migrate!
         | 
| 80 | 
            +
                    end
         | 
| 81 | 
            +
                  end
         | 
| 82 | 
            +
                end
         | 
| 83 | 
            +
              end
         | 
| 84 | 
            +
             | 
| 85 | 
            +
              describe 'upwards' do
         | 
| 86 | 
            +
                let(:migrator) { up_migrator }
         | 
| 87 | 
            +
                let(:subject) { v2_serialization.deep_dup }
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                let(:expected_result) do
         | 
| 90 | 
            +
                  current_serialization.deep_merge(
         | 
| 91 | 
            +
                    ViewModel::MIGRATED_ATTRIBUTE => true,
         | 
| 92 | 
            +
                    'new_field' => 3,
         | 
| 93 | 
            +
                    'child' => {
         | 
| 94 | 
            +
                      ViewModel::MIGRATED_ATTRIBUTE => true,
         | 
| 95 | 
            +
                    },
         | 
| 96 | 
            +
                  )
         | 
| 97 | 
            +
                end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                it 'migrates' do
         | 
| 100 | 
            +
                  migrate!
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                  assert_equal(expected_result, subject)
         | 
| 103 | 
            +
                end
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                describe 'with version unspecified' do
         | 
| 106 | 
            +
                  let(:subject) do
         | 
| 107 | 
            +
                    v2_serialization
         | 
| 108 | 
            +
                      .except(ViewModel::VERSION_ATTRIBUTE)
         | 
| 109 | 
            +
                  end
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                  it 'treats it as the requested version' do
         | 
| 112 | 
            +
                    migrate!
         | 
| 113 | 
            +
                    assert_equal(expected_result, subject)
         | 
| 114 | 
            +
                  end
         | 
| 115 | 
            +
                end
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                describe 'with a version not in the specification' do
         | 
| 118 | 
            +
                  let(:subject) do
         | 
| 119 | 
            +
                    v2_serialization
         | 
| 120 | 
            +
                      .except('old_field')
         | 
| 121 | 
            +
                      .deep_merge(ViewModel::VERSION_ATTRIBUTE => 3, 'mid_field' => 1)
         | 
| 122 | 
            +
                  end
         | 
| 123 | 
            +
             | 
| 124 | 
            +
                  it 'rejects it' do
         | 
| 125 | 
            +
                    assert_raises(ViewModel::Migration::UnspecifiedVersionError) do
         | 
| 126 | 
            +
                      migrate!
         | 
| 127 | 
            +
                    end
         | 
| 128 | 
            +
                  end
         | 
| 129 | 
            +
                end
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                describe 'from an unreachable version' do
         | 
| 132 | 
            +
                  let(:migration_versions) { { viewmodel_class => 2, child_viewmodel_class => 1 } }
         | 
| 133 | 
            +
             | 
| 134 | 
            +
                  let(:subject) do
         | 
| 135 | 
            +
                    v2_serialization.deep_merge(
         | 
| 136 | 
            +
                      'child' => { ViewModel::VERSION_ATTRIBUTE => 1 },
         | 
| 137 | 
            +
                    )
         | 
| 138 | 
            +
                  end
         | 
| 139 | 
            +
             | 
| 140 | 
            +
                  it 'raises' do
         | 
| 141 | 
            +
                    assert_raises(ViewModel::Migration::NoPathError) do
         | 
| 142 | 
            +
                      migrate!
         | 
| 143 | 
            +
                    end
         | 
| 144 | 
            +
                  end
         | 
| 145 | 
            +
                end
         | 
| 146 | 
            +
             | 
| 147 | 
            +
                describe 'in an undefined direction' do
         | 
| 148 | 
            +
                  let(:migration_versions) { { viewmodel_class => 1, child_viewmodel_class => 2 } }
         | 
| 149 | 
            +
             | 
| 150 | 
            +
                  let(:subject) do
         | 
| 151 | 
            +
                    v2_serialization.except('old_field').merge(ViewModel::VERSION_ATTRIBUTE => 1)
         | 
| 152 | 
            +
                  end
         | 
| 153 | 
            +
             | 
| 154 | 
            +
                  it 'raises' do
         | 
| 155 | 
            +
                    assert_raises(ViewModel::Migration::OneWayError) do
         | 
| 156 | 
            +
                      migrate!
         | 
| 157 | 
            +
                    end
         | 
| 158 | 
            +
                  end
         | 
| 159 | 
            +
                end
         | 
| 160 | 
            +
              end
         | 
| 161 | 
            +
            end
         | 
| @@ -1,13 +1,15 @@ | |
| 1 | 
            -
             | 
| 2 | 
            -
            require "minitest/unit"
         | 
| 3 | 
            -
            require "minitest/hooks"
         | 
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 4 2 |  | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 3 | 
            +
            require 'minitest/autorun'
         | 
| 4 | 
            +
            require 'minitest/unit'
         | 
| 5 | 
            +
            require 'minitest/hooks'
         | 
| 8 6 |  | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 7 | 
            +
            require_relative '../../../helpers/arvm_test_utilities'
         | 
| 8 | 
            +
            require_relative '../../../helpers/arvm_test_models'
         | 
| 9 | 
            +
            require_relative '../../../helpers/viewmodel_spec_helpers'
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            require 'view_model'
         | 
| 12 | 
            +
            require 'view_model/active_record'
         | 
| 11 13 |  | 
| 12 14 | 
             
            module NSTest
         | 
| 13 15 | 
             
            end
         | 
| @@ -27,23 +29,23 @@ class ViewModel::ActiveRecord::NamespacingTest < ActiveSupport::TestCase | |
| 27 29 | 
             
                  schema:    parent_attrs.schema,
         | 
| 28 30 | 
             
                  viewmodel: parent_attrs.viewmodel,
         | 
| 29 31 | 
             
                  model:     ->(_) {
         | 
| 30 | 
            -
                    has_one :child, inverse_of: :model, class_name:  | 
| 32 | 
            +
                    has_one :child, inverse_of: :model, class_name: 'NSTest::Child', dependent: :destroy
         | 
| 31 33 | 
             
                  })
         | 
| 32 34 | 
             
              end
         | 
| 33 35 |  | 
| 34 36 | 
             
              describe 'inference' do
         | 
| 35 | 
            -
                it  | 
| 36 | 
            -
                  assert_equal( | 
| 37 | 
            +
                it 'assigns a transformed view name from a namespaced class' do
         | 
| 38 | 
            +
                  assert_equal('NSTest.Model', viewmodel_class.view_name)
         | 
| 37 39 | 
             
                end
         | 
| 38 40 |  | 
| 39 | 
            -
                it  | 
| 41 | 
            +
                it 'can look up a viewmodel by inference from an association to a namespaced model' do
         | 
| 40 42 | 
             
                  child_viewmodel_class # test depends on child_viewmodel_class
         | 
| 41 43 |  | 
| 42 44 | 
             
                  assert_equal(viewmodel_class._association_data('child').viewmodel_class,
         | 
| 43 45 | 
             
                               child_viewmodel_class)
         | 
| 44 46 | 
             
                end
         | 
| 45 47 |  | 
| 46 | 
            -
                it  | 
| 48 | 
            +
                it 'can infer the model class from a namespaced view class name' do
         | 
| 47 49 | 
             
                  assert_equal(viewmodel_class.model_class, model_class)
         | 
| 48 50 | 
             
                end
         | 
| 49 51 | 
             
              end
         | 
| @@ -52,12 +54,12 @@ class ViewModel::ActiveRecord::NamespacingTest < ActiveSupport::TestCase | |
| 52 54 | 
             
                include ARVMTestUtilities
         | 
| 53 55 |  | 
| 54 56 | 
             
                it 'can apply access control policy for namespaced classes' do
         | 
| 55 | 
            -
                   | 
| 57 | 
            +
                  p_viewmodel_class = viewmodel_class
         | 
| 56 58 |  | 
| 57 59 | 
             
                  access_control_class =
         | 
| 58 60 | 
             
                    Class.new(ViewModel::AccessControl::Tree) do
         | 
| 59 | 
            -
                      view( | 
| 60 | 
            -
                        visible_unless!( | 
| 61 | 
            +
                      view(p_viewmodel_class.view_name) do
         | 
| 62 | 
            +
                        visible_unless!('VETO-ERROR-MESSAGE') { true }
         | 
| 61 63 | 
             
                      end
         | 
| 62 64 | 
             
                    end
         | 
| 63 65 |  | 
| @@ -68,7 +70,7 @@ class ViewModel::ActiveRecord::NamespacingTest < ActiveSupport::TestCase | |
| 68 70 |  | 
| 69 71 | 
             
                  refute_serializes(viewmodel_class,
         | 
| 70 72 | 
             
                                    model_class.create!,
         | 
| 71 | 
            -
                                     | 
| 73 | 
            +
                                    'VETO-ERROR-MESSAGE',
         | 
| 72 74 | 
             
                                    serialize_context: serialize_context)
         | 
| 73 75 | 
             
                end
         | 
| 74 76 | 
             
              end
         | 
| @@ -1,9 +1,11 @@ | |
| 1 | 
            -
             | 
| 2 | 
            -
            require_relative "../../../helpers/arvm_test_models.rb"
         | 
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 3 2 |  | 
| 4 | 
            -
             | 
| 3 | 
            +
            require_relative '../../../helpers/arvm_test_utilities'
         | 
| 4 | 
            +
            require_relative '../../../helpers/arvm_test_models'
         | 
| 5 5 |  | 
| 6 | 
            -
            require  | 
| 6 | 
            +
            require 'minitest/autorun'
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            require 'view_model/active_record'
         | 
| 7 9 |  | 
| 8 10 | 
             
            module ViewModel::ActiveRecord::PolyTest
         | 
| 9 11 | 
             
              ## Polymorphic pointer to parent in child (child may belong to different type parents)
         | 
| @@ -70,17 +72,17 @@ module ViewModel::ActiveRecord::PolyTest | |
| 70 72 |  | 
| 71 73 | 
             
                def setup
         | 
| 72 74 | 
             
                  super
         | 
| 73 | 
            -
                  @parent1 = PolyParentOne.create(text:  | 
| 74 | 
            -
                  @parent2 = PolyParentTwo.create(num: 2, children: [Child.new(text:  | 
| 75 | 
            +
                  @parent1 = PolyParentOne.create(text: 'p1', child: Child.new(text: 'c1'))
         | 
| 76 | 
            +
                  @parent2 = PolyParentTwo.create(num: 2, children: [Child.new(text: 'c2'), Child.new(text: 'c3')])
         | 
| 75 77 | 
             
                  @grandparent = Grandparent.create(poly_parent_one: @parent1, poly_parent_two: @parent2)
         | 
| 76 78 | 
             
                  enable_logging!
         | 
| 77 79 | 
             
                end
         | 
| 78 80 |  | 
| 79 81 | 
             
                def test_create_has_one_from_view
         | 
| 80 82 | 
             
                  p1_view = {
         | 
| 81 | 
            -
                     | 
| 82 | 
            -
                     | 
| 83 | 
            -
                     | 
| 83 | 
            +
                    '_type' => 'PolyParentOne',
         | 
| 84 | 
            +
                    'text'  => 'p',
         | 
| 85 | 
            +
                    'child' => { '_type' => 'Child', 'text' => 'c' },
         | 
| 84 86 | 
             
                  }
         | 
| 85 87 | 
             
                  p1v = PolyParentOneView.deserialize_from_view(p1_view)
         | 
| 86 88 | 
             
                  p1 = p1v.model
         | 
| @@ -92,9 +94,9 @@ module ViewModel::ActiveRecord::PolyTest | |
| 92 94 |  | 
| 93 95 | 
             
                def test_create_has_many_from_view
         | 
| 94 96 | 
             
                  p2_view = {
         | 
| 95 | 
            -
                     | 
| 96 | 
            -
                     | 
| 97 | 
            -
                     | 
| 97 | 
            +
                    '_type' => 'PolyParentTwo',
         | 
| 98 | 
            +
                    'num'   => '2',
         | 
| 99 | 
            +
                    'children' => [{ '_type' => 'Child', 'text' => 'c1' }, { '_type' => 'Child', 'text' => 'c2' }],
         | 
| 98 100 | 
             
                  }
         | 
| 99 101 | 
             
                  p2v = PolyParentTwoView.deserialize_from_view(p2_view)
         | 
| 100 102 | 
             
                  p2 = p2v.model
         | 
| @@ -108,15 +110,15 @@ module ViewModel::ActiveRecord::PolyTest | |
| 108 110 |  | 
| 109 111 | 
             
                def test_move
         | 
| 110 112 | 
             
                  # test that I can move a child from one type to another and the parent pointer/type is correctly updated.
         | 
| 111 | 
            -
                  alter_by_view!(GrandparentView, @grandparent) do |view,  | 
| 112 | 
            -
                    c1 = view[ | 
| 113 | 
            -
                    c2 = view[ | 
| 114 | 
            -
                    view[ | 
| 115 | 
            -
                    view[ | 
| 113 | 
            +
                  alter_by_view!(GrandparentView, @grandparent) do |view, _refs|
         | 
| 114 | 
            +
                    c1 = view['poly_parent_one']['child']
         | 
| 115 | 
            +
                    c2 = view['poly_parent_two']['children'].pop
         | 
| 116 | 
            +
                    view['poly_parent_one']['child'] = c2
         | 
| 117 | 
            +
                    view['poly_parent_two']['children'].push(c1)
         | 
| 116 118 | 
             
                  end
         | 
| 117 119 | 
             
                  @grandparent.reload
         | 
| 118 | 
            -
                  assert_equal( | 
| 119 | 
            -
                  assert_equal([ | 
| 120 | 
            +
                  assert_equal('c3', @grandparent.poly_parent_one.child.text)
         | 
| 121 | 
            +
                  assert_equal(['c1', 'c2'], @grandparent.poly_parent_two.children.map(&:text).sort)
         | 
| 120 122 | 
             
                end
         | 
| 121 123 | 
             
              end
         | 
| 122 124 |  | 
| @@ -166,13 +168,12 @@ module ViewModel::ActiveRecord::PolyTest | |
| 166 168 | 
             
                    end
         | 
| 167 169 |  | 
| 168 170 | 
             
                    define_viewmodel do
         | 
| 169 | 
            -
                      attributes | 
| 171 | 
            +
                      attributes :name
         | 
| 170 172 | 
             
                      association :poly, viewmodels: [PolyOneView, PolyTwoView]
         | 
| 171 173 | 
             
                    end
         | 
| 172 174 | 
             
                  end
         | 
| 173 175 | 
             
                end
         | 
| 174 176 |  | 
| 175 | 
            -
             | 
| 176 177 | 
             
                def before_all
         | 
| 177 178 | 
             
                  super
         | 
| 178 179 | 
             
                  self.class.build_poly_children(self)
         | 
| @@ -182,17 +183,17 @@ module ViewModel::ActiveRecord::PolyTest | |
| 182 183 | 
             
                def setup
         | 
| 183 184 | 
             
                  super
         | 
| 184 185 |  | 
| 185 | 
            -
                  @parent1 = Parent.create(name:  | 
| 186 | 
            +
                  @parent1 = Parent.create(name: 'p1',
         | 
| 186 187 | 
             
                                           poly: PolyOne.new(number: 1))
         | 
| 187 188 |  | 
| 188 | 
            -
                  @parent2 = Parent.create(name:  | 
| 189 | 
            +
                  @parent2 = Parent.create(name: 'p2')
         | 
| 189 190 |  | 
| 190 191 | 
             
                  enable_logging!
         | 
| 191 192 | 
             
                end
         | 
| 192 193 |  | 
| 193 194 | 
             
                def test_loading_batching
         | 
| 194 | 
            -
                  Parent.create(name:  | 
| 195 | 
            -
                  Parent.create(name:  | 
| 195 | 
            +
                  Parent.create(name: 'with PolyOne', poly: PolyOne.new)
         | 
| 196 | 
            +
                  Parent.create(name: 'with PolyTwo', poly: PolyTwo.new)
         | 
| 196 197 |  | 
| 197 198 | 
             
                  log_queries do
         | 
| 198 199 | 
             
                    serialize(ParentView.load)
         | 
| @@ -203,9 +204,9 @@ module ViewModel::ActiveRecord::PolyTest | |
| 203 204 |  | 
| 204 205 | 
             
                def test_create_from_view
         | 
| 205 206 | 
             
                  view = {
         | 
| 206 | 
            -
                     | 
| 207 | 
            -
                     | 
| 208 | 
            -
                     | 
| 207 | 
            +
                    '_type'    => 'Parent',
         | 
| 208 | 
            +
                    'name'     => 'p',
         | 
| 209 | 
            +
                    'poly'     => { '_type' => 'PolyTwo', 'text' => 'pol' },
         | 
| 209 210 | 
             
                  }
         | 
| 210 211 |  | 
| 211 212 | 
             
                  pv = ParentView.deserialize_from_view(view)
         | 
| @@ -214,25 +215,24 @@ module ViewModel::ActiveRecord::PolyTest | |
| 214 215 | 
             
                  assert(!p.changed?)
         | 
| 215 216 | 
             
                  assert(!p.new_record?)
         | 
| 216 217 |  | 
| 217 | 
            -
                  assert_equal( | 
| 218 | 
            +
                  assert_equal('p', p.name)
         | 
| 218 219 |  | 
| 219 220 | 
             
                  assert(p.poly.present?)
         | 
| 220 221 | 
             
                  assert(p.poly.is_a?(PolyTwo))
         | 
| 221 | 
            -
                  assert_equal( | 
| 222 | 
            +
                  assert_equal('pol', p.poly.text)
         | 
| 222 223 | 
             
                end
         | 
| 223 224 |  | 
| 224 | 
            -
             | 
| 225 225 | 
             
                def test_serialize_view
         | 
| 226 226 | 
             
                  view, _refs = serialize_with_references(ParentView.new(@parent1))
         | 
| 227 227 |  | 
| 228 | 
            -
                  assert_equal({  | 
| 229 | 
            -
                                  | 
| 230 | 
            -
                                  | 
| 231 | 
            -
                                  | 
| 232 | 
            -
                                  | 
| 233 | 
            -
                                                  | 
| 234 | 
            -
                                                  | 
| 235 | 
            -
                                                  | 
| 228 | 
            +
                  assert_equal({ '_type'    => 'Parent',
         | 
| 229 | 
            +
                                 '_version' => 1,
         | 
| 230 | 
            +
                                 'id'       => @parent1.id,
         | 
| 231 | 
            +
                                 'name'     => @parent1.name,
         | 
| 232 | 
            +
                                 'poly'     => { '_type'    => @parent1.poly_type,
         | 
| 233 | 
            +
                                                 '_version' => 1,
         | 
| 234 | 
            +
                                                 'id'       => @parent1.poly.id,
         | 
| 235 | 
            +
                                                 'number'   => @parent1.poly.number },
         | 
| 236 236 | 
             
                               },
         | 
| 237 237 | 
             
                               view)
         | 
| 238 238 | 
             
                end
         | 
| @@ -247,14 +247,14 @@ module ViewModel::ActiveRecord::PolyTest | |
| 247 247 | 
             
                          '_type'    => 'SomethingThatsNotActuallyAType',
         | 
| 248 248 | 
             
                          '_version' => 1,
         | 
| 249 249 | 
             
                        } })
         | 
| 250 | 
            -
             | 
| 251 | 
            -
             | 
| 250 | 
            +
                  end
         | 
| 251 | 
            +
                  assert_match(/\binvalid\b.+\bviewmodel type\b/i, ex.message)
         | 
| 252 252 | 
             
                end
         | 
| 253 253 |  | 
| 254 254 | 
             
                def test_change_polymorphic_type
         | 
| 255 255 | 
             
                  old_poly = @parent1.poly
         | 
| 256 256 |  | 
| 257 | 
            -
                  alter_by_view!(ParentView, @parent1) do |view,  | 
| 257 | 
            +
                  alter_by_view!(ParentView, @parent1) do |view, _refs|
         | 
| 258 258 | 
             
                    view['poly'] = { '_type' => 'PolyTwo', 'text' => 'hi' }
         | 
| 259 259 | 
             
                  end
         | 
| 260 260 |  | 
| @@ -302,18 +302,17 @@ module ViewModel::ActiveRecord::PolyTest | |
| 302 302 | 
             
                  end
         | 
| 303 303 |  | 
| 304 304 | 
             
                  def test_renamed_roundtrip
         | 
| 305 | 
            -
                    alter_by_view!(ParentView, @parent) do |view,  | 
| 305 | 
            +
                    alter_by_view!(ParentView, @parent) do |view, _refs|
         | 
| 306 306 | 
             
                      assert_equal({ 'id'       => @parent.id,
         | 
| 307 307 | 
             
                                     '_type'    => 'PolyOne',
         | 
| 308 308 | 
             
                                     '_version' => 1,
         | 
| 309 309 | 
             
                                     'number'   => 42 },
         | 
| 310 310 | 
             
                                   view['something_else'])
         | 
| 311 | 
            -
                      view['something_else'] = {'_type' => 'PolyTwo', 'text' => 'hi'}
         | 
| 311 | 
            +
                      view['something_else'] = { '_type' => 'PolyTwo', 'text' => 'hi' }
         | 
| 312 312 | 
             
                    end
         | 
| 313 313 |  | 
| 314 314 | 
             
                    assert_equal('hi', @parent.poly.text)
         | 
| 315 315 | 
             
                  end
         | 
| 316 316 | 
             
                end
         | 
| 317 | 
            -
             | 
| 318 317 | 
             
              end
         | 
| 319 318 | 
             
            end
         | 
| @@ -1,9 +1,11 @@ | |
| 1 | 
            -
             | 
| 2 | 
            -
            require_relative "../../../helpers/arvm_test_models.rb"
         | 
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 3 2 |  | 
| 4 | 
            -
             | 
| 3 | 
            +
            require_relative '../../../helpers/arvm_test_utilities'
         | 
| 4 | 
            +
            require_relative '../../../helpers/arvm_test_models'
         | 
| 5 5 |  | 
| 6 | 
            -
            require  | 
| 6 | 
            +
            require 'minitest/autorun'
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            require 'view_model/active_record'
         | 
| 7 9 |  | 
| 8 10 | 
             
            class ViewModel::ActiveRecord::SharedTest < ActiveSupport::TestCase
         | 
| 9 11 | 
             
              include ARVMTestUtilities
         | 
| @@ -58,12 +60,12 @@ class ViewModel::ActiveRecord::SharedTest < ActiveSupport::TestCase | |
| 58 60 | 
             
              def setup
         | 
| 59 61 | 
             
                super
         | 
| 60 62 |  | 
| 61 | 
            -
                @parent1 = Parent.create(name:  | 
| 62 | 
            -
                                         category: Category.new(name:  | 
| 63 | 
            +
                @parent1 = Parent.create(name: 'p1',
         | 
| 64 | 
            +
                                         category: Category.new(name: 'p1cat'))
         | 
| 63 65 |  | 
| 64 | 
            -
                @parent2 = Parent.create(name:  | 
| 66 | 
            +
                @parent2 = Parent.create(name: 'p2')
         | 
| 65 67 |  | 
| 66 | 
            -
                @category1 = Category.create(name:  | 
| 68 | 
            +
                @category1 = Category.create(name: 'Cat1')
         | 
| 67 69 |  | 
| 68 70 | 
             
                enable_logging!
         | 
| 69 71 | 
             
              end
         | 
| @@ -72,7 +74,7 @@ class ViewModel::ActiveRecord::SharedTest < ActiveSupport::TestCase | |
| 72 74 | 
             
                Parent.create(category: Category.new)
         | 
| 73 75 |  | 
| 74 76 | 
             
                log_queries do
         | 
| 75 | 
            -
                  serialize(ParentView.load | 
| 77 | 
            +
                  serialize(ParentView.load)
         | 
| 76 78 | 
             
                end
         | 
| 77 79 | 
             
                assert_equal(['Parent Load', 'Category Load'],
         | 
| 78 80 | 
             
                             logged_load_queries)
         | 
| @@ -80,12 +82,12 @@ class ViewModel::ActiveRecord::SharedTest < ActiveSupport::TestCase | |
| 80 82 |  | 
| 81 83 | 
             
              def test_create_from_view
         | 
| 82 84 | 
             
                view = {
         | 
| 83 | 
            -
                   | 
| 84 | 
            -
                   | 
| 85 | 
            -
                   | 
| 85 | 
            +
                  '_type'    => 'Parent',
         | 
| 86 | 
            +
                  'name'     => 'p',
         | 
| 87 | 
            +
                  'category' => { '_ref' => 'r1' },
         | 
| 86 88 | 
             
                }
         | 
| 87 89 | 
             
                refs = {
         | 
| 88 | 
            -
                   | 
| 90 | 
            +
                  'r1' => { '_type' => 'Category', 'name' => 'newcat' },
         | 
| 89 91 | 
             
                }
         | 
| 90 92 |  | 
| 91 93 | 
             
                pv = ParentView.deserialize_from_view(view, references: refs)
         | 
| @@ -94,27 +96,27 @@ class ViewModel::ActiveRecord::SharedTest < ActiveSupport::TestCase | |
| 94 96 | 
             
                assert(!p.changed?)
         | 
| 95 97 | 
             
                assert(!p.new_record?)
         | 
| 96 98 |  | 
| 97 | 
            -
                assert_equal( | 
| 99 | 
            +
                assert_equal('p', p.name)
         | 
| 98 100 |  | 
| 99 101 | 
             
                assert(p.category.present?)
         | 
| 100 | 
            -
                assert_equal( | 
| 102 | 
            +
                assert_equal('newcat', p.category.name)
         | 
| 101 103 | 
             
              end
         | 
| 102 104 |  | 
| 103 105 | 
             
              def test_serialize_view
         | 
| 104 106 | 
             
                view, refs = serialize_with_references(ParentView.new(@parent1))
         | 
| 105 107 | 
             
                cat1_ref = refs.detect { |_, v| v['_type'] == 'Category' }.first
         | 
| 106 108 |  | 
| 107 | 
            -
                assert_equal({cat1_ref => { '_type' | 
| 108 | 
            -
                                             | 
| 109 | 
            +
                assert_equal({ cat1_ref => { '_type' => 'Category',
         | 
| 110 | 
            +
                                            '_version' => 1,
         | 
| 109 111 | 
             
                                            'id'       => @parent1.category.id,
         | 
| 110 | 
            -
                                            'name'     => @parent1.category.name }},
         | 
| 112 | 
            +
                                            'name'     => @parent1.category.name } },
         | 
| 111 113 | 
             
                             refs)
         | 
| 112 114 |  | 
| 113 | 
            -
                assert_equal({  | 
| 114 | 
            -
                                | 
| 115 | 
            -
                                | 
| 116 | 
            -
                                | 
| 117 | 
            -
                                | 
| 115 | 
            +
                assert_equal({ '_type'    => 'Parent',
         | 
| 116 | 
            +
                               '_version' => 1,
         | 
| 117 | 
            +
                               'id'       => @parent1.id,
         | 
| 118 | 
            +
                               'name'     => @parent1.name,
         | 
| 119 | 
            +
                               'category' => { '_ref' => cat1_ref } },
         | 
| 118 120 | 
             
                             view)
         | 
| 119 121 | 
             
              end
         | 
| 120 122 |  | 
| @@ -126,7 +128,7 @@ class ViewModel::ActiveRecord::SharedTest < ActiveSupport::TestCase | |
| 126 128 | 
             
              def test_shared_serialize_interning
         | 
| 127 129 | 
             
                @parent2.update(category: @parent1.category)
         | 
| 128 130 | 
             
                view, refs = serialize_with_references([ParentView.new(@parent1),
         | 
| 129 | 
            -
                                                        ParentView.new(@parent2)])
         | 
| 131 | 
            +
                                                        ParentView.new(@parent2),])
         | 
| 130 132 |  | 
| 131 133 | 
             
                category_ref = view.first['category']['_ref']
         | 
| 132 134 |  | 
| @@ -158,7 +160,7 @@ class ViewModel::ActiveRecord::SharedTest < ActiveSupport::TestCase | |
| 158 160 |  | 
| 159 161 | 
             
              def test_shared_requires_all_references
         | 
| 160 162 | 
             
                ex = assert_raises(ViewModel::DeserializationError::InvalidStructure) do
         | 
| 161 | 
            -
                  alter_by_view!(ParentView, @parent2) do | | 
| 163 | 
            +
                  alter_by_view!(ParentView, @parent2) do |_p2view, refs|
         | 
| 162 164 | 
             
                    refs['spurious_ref'] = { '_type' => 'Parent', 'id' => @parent1.id }
         | 
| 163 165 | 
             
                  end
         | 
| 164 166 | 
             
                end
         | 
| @@ -167,7 +169,7 @@ class ViewModel::ActiveRecord::SharedTest < ActiveSupport::TestCase | |
| 167 169 |  | 
| 168 170 | 
             
              def test_shared_requires_valid_references
         | 
| 169 171 | 
             
                assert_raises(ViewModel::DeserializationError::InvalidSharedReference) do
         | 
| 170 | 
            -
                  alter_by_view!(ParentView, @parent1) do | | 
| 172 | 
            +
                  alter_by_view!(ParentView, @parent1) do |_p1view, refs|
         | 
| 171 173 | 
             
                    refs.clear # remove the expected serialized refs
         | 
| 172 174 | 
             
                  end
         | 
| 173 175 | 
             
                end
         | 
| @@ -180,7 +182,7 @@ class ViewModel::ActiveRecord::SharedTest < ActiveSupport::TestCase | |
| 180 182 | 
             
                    refs['p2'] = update_hash_for(ParentView, @parent2)
         | 
| 181 183 | 
             
                  end
         | 
| 182 184 | 
             
                end
         | 
| 183 | 
            -
                assert_equal( | 
| 185 | 
            +
                assert_equal('category', ex.association)
         | 
| 184 186 | 
             
              end
         | 
| 185 187 |  | 
| 186 188 | 
             
              def test_shared_requires_unique_references
         | 
| @@ -217,7 +219,7 @@ class ViewModel::ActiveRecord::SharedTest < ActiveSupport::TestCase | |
| 217 219 | 
             
                d_context = ParentView.new_deserialize_context
         | 
| 218 220 |  | 
| 219 221 | 
             
                alter_by_view!(ParentView, @parent1, deserialize_context: d_context) do |view, refs|
         | 
| 220 | 
            -
                  refs[view['category'][ | 
| 222 | 
            +
                  refs[view['category']['_ref']]['name'] = 'changed'
         | 
| 221 223 | 
             
                end
         | 
| 222 224 |  | 
| 223 225 | 
             
                assert(d_context.valid_edit_refs.include?(ViewModel::Reference.new(CategoryView, @parent1.category.id)))
         |