iknow_view_models 2.10.1 → 3.0.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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +119 -0
  3. data/.travis.yml +31 -0
  4. data/Appraisals +6 -16
  5. data/gemfiles/{rails_7_0.gemfile → rails_6_0_beta.gemfile} +2 -2
  6. data/iknow_view_models.gemspec +3 -5
  7. data/lib/iknow_view_models/version.rb +1 -1
  8. data/lib/view_model/active_record/association_data.rb +206 -92
  9. data/lib/view_model/active_record/association_manipulation.rb +22 -12
  10. data/lib/view_model/active_record/cache/cacheable_view.rb +3 -13
  11. data/lib/view_model/active_record/cache.rb +2 -2
  12. data/lib/view_model/active_record/cloner.rb +11 -11
  13. data/lib/view_model/active_record/controller.rb +0 -2
  14. data/lib/view_model/active_record/update_context.rb +21 -3
  15. data/lib/view_model/active_record/update_data.rb +43 -45
  16. data/lib/view_model/active_record/update_operation.rb +265 -153
  17. data/lib/view_model/active_record/visitor.rb +9 -6
  18. data/lib/view_model/active_record.rb +94 -74
  19. data/lib/view_model/after_transaction_runner.rb +3 -18
  20. data/lib/view_model/callbacks.rb +2 -2
  21. data/lib/view_model/changes.rb +24 -16
  22. data/lib/view_model/config.rb +6 -2
  23. data/lib/view_model/deserialization_error.rb +31 -0
  24. data/lib/view_model/deserialize_context.rb +2 -6
  25. data/lib/view_model/error_view.rb +6 -5
  26. data/lib/view_model/record/attribute_data.rb +11 -6
  27. data/lib/view_model/record.rb +44 -24
  28. data/lib/view_model/serialize_context.rb +2 -63
  29. data/lib/view_model/test_helpers/arvm_builder.rb +2 -4
  30. data/lib/view_model/traversal_context.rb +2 -2
  31. data/lib/view_model.rb +21 -13
  32. data/shell.nix +1 -1
  33. data/test/helpers/arvm_test_models.rb +4 -12
  34. data/test/helpers/arvm_test_utilities.rb +6 -0
  35. data/test/helpers/controller_test_helpers.rb +6 -6
  36. data/test/helpers/viewmodel_spec_helpers.rb +63 -52
  37. data/test/unit/view_model/access_control_test.rb +88 -37
  38. data/test/unit/view_model/active_record/belongs_to_test.rb +110 -178
  39. data/test/unit/view_model/active_record/cache_test.rb +11 -5
  40. data/test/unit/view_model/active_record/cloner_test.rb +1 -1
  41. data/test/unit/view_model/active_record/controller_test.rb +12 -20
  42. data/test/unit/view_model/active_record/has_many_test.rb +540 -316
  43. data/test/unit/view_model/active_record/has_many_through_poly_test.rb +12 -15
  44. data/test/unit/view_model/active_record/has_many_through_test.rb +15 -58
  45. data/test/unit/view_model/active_record/has_one_test.rb +288 -135
  46. data/test/unit/view_model/active_record/poly_test.rb +0 -1
  47. data/test/unit/view_model/active_record/shared_test.rb +21 -39
  48. data/test/unit/view_model/active_record/version_test.rb +3 -2
  49. data/test/unit/view_model/active_record_test.rb +5 -63
  50. data/test/unit/view_model/callbacks_test.rb +1 -0
  51. data/test/unit/view_model/record_test.rb +0 -32
  52. data/test/unit/view_model/traversal_context_test.rb +13 -12
  53. metadata +15 -25
  54. data/.github/workflows/gem-push.yml +0 -31
  55. data/.github/workflows/test.yml +0 -65
  56. data/gemfiles/rails_6_0.gemfile +0 -9
  57. data/gemfiles/rails_6_1.gemfile +0 -9
  58. data/test/unit/view_model/active_record/optional_attribute_view_test.rb +0 -58
@@ -190,6 +190,7 @@ class ViewModel::AccessControlTest < ActiveSupport::TestCase
190
190
  end
191
191
 
192
192
  define_viewmodel do
193
+ root!
193
194
  attribute :val
194
195
  association :tree2
195
196
 
@@ -215,7 +216,7 @@ class ViewModel::AccessControlTest < ActiveSupport::TestCase
215
216
 
216
217
  define_viewmodel do
217
218
  attribute :val
218
- association :tree1, shared: true, optional: false
219
+ association :tree1
219
220
  end
220
221
  end
221
222
  end
@@ -447,15 +448,16 @@ class ViewModel::AccessControlTest < ActiveSupport::TestCase
447
448
  include ViewModelSpecHelpers::List
448
449
  extend Minitest::Spec::DSL
449
450
 
450
- def assert_changes_match(changes, new, deleted, children, attributes, associations)
451
+ def assert_changes_match(changes, n: false, d: false, nstc: false, refc: false, att: [], ass: [])
451
452
  assert_equal(
452
453
  changes,
453
454
  ViewModel::Changes.new(
454
- new: new,
455
- deleted: deleted,
456
- changed_children: children,
457
- changed_attributes: attributes,
458
- changed_associations: associations))
455
+ new: n,
456
+ deleted: d,
457
+ changed_nested_children: nstc,
458
+ changed_referenced_children: refc,
459
+ changed_attributes: att,
460
+ changed_associations: ass))
459
461
  end
460
462
 
461
463
  describe 'with parent and points-to child test models' do
@@ -479,7 +481,7 @@ class ViewModel::AccessControlTest < ActiveSupport::TestCase
479
481
  vm = viewmodel_class.deserialize_from_view(view, deserialize_context: ctx)
480
482
 
481
483
  vm_changes = ctx.valid_edit_changes(vm.to_reference)
482
- assert_changes_match(vm_changes, true, false, false, ['name'], [])
484
+ assert_changes_match(vm_changes, n: true, att: ['name'])
483
485
  end
484
486
 
485
487
  it 'records a destroyed model' do
@@ -489,7 +491,7 @@ class ViewModel::AccessControlTest < ActiveSupport::TestCase
489
491
  vm.destroy!(deserialize_context: ctx)
490
492
 
491
493
  vm_changes = ctx.valid_edit_changes(vm.to_reference)
492
- assert_changes_match(vm_changes, false, true, false, [], [])
494
+ assert_changes_match(vm_changes, d: true)
493
495
  end
494
496
 
495
497
  it 'records a change to an attribute' do
@@ -498,7 +500,7 @@ class ViewModel::AccessControlTest < ActiveSupport::TestCase
498
500
  end
499
501
 
500
502
  vm_changes = ctx.valid_edit_changes(vm.to_reference)
501
- assert_changes_match(vm_changes, false, false, false, ['name'], [])
503
+ assert_changes_match(vm_changes, att: ['name'])
502
504
  end
503
505
 
504
506
  it 'records a new child' do
@@ -507,10 +509,10 @@ class ViewModel::AccessControlTest < ActiveSupport::TestCase
507
509
  end
508
510
 
509
511
  vm_changes = ctx.valid_edit_changes(vm.to_reference)
510
- assert_changes_match(vm_changes, false, false, true, [], ['child'])
512
+ assert_changes_match(vm_changes, nstc: true, ass: ['child'])
511
513
 
512
514
  c_changes = ctx.valid_edit_changes(vm.child.to_reference)
513
- assert_changes_match(c_changes, true, false, false, ['name'], [])
515
+ assert_changes_match(c_changes, n: true, att: ['name'])
514
516
  end
515
517
 
516
518
  it 'records a replaced child' do
@@ -522,14 +524,14 @@ class ViewModel::AccessControlTest < ActiveSupport::TestCase
522
524
  end
523
525
 
524
526
  vm_changes = ctx.valid_edit_changes(vm.to_reference)
525
- assert_changes_match(vm_changes, false, false, true, [], ['child'])
527
+ assert_changes_match(vm_changes, nstc: true, ass: ['child'])
526
528
 
527
529
  c_changes = ctx.valid_edit_changes(vm.child.to_reference)
528
- assert_changes_match(c_changes, true, false, false, ['name'], [])
530
+ assert_changes_match(c_changes, n: true, att: ['name'])
529
531
 
530
532
  oc_changes = ctx.valid_edit_changes(
531
533
  ViewModel::Reference.new(child_viewmodel_class, old_child.id))
532
- assert_changes_match(oc_changes, false, true, false, [], [])
534
+ assert_changes_match(oc_changes, d: true)
533
535
  end
534
536
 
535
537
  it 'records an edited child' do
@@ -542,10 +544,10 @@ class ViewModel::AccessControlTest < ActiveSupport::TestCase
542
544
  # The parent node itself wasn't changed, so must not have been
543
545
  # valid_edit checked
544
546
  refute(ctx.was_edited?(vm.to_reference))
545
- assert_changes_match(vm.previous_changes, false, false, true, [], [])
547
+ assert_changes_match(vm.previous_changes, nstc: true)
546
548
 
547
549
  c_changes = ctx.valid_edit_changes(vm.child.to_reference)
548
- assert_changes_match(c_changes, false, false, false, ['name'], [])
550
+ assert_changes_match(c_changes, att: ['name'])
549
551
  end
550
552
 
551
553
  it 'records a deleted child' do
@@ -557,11 +559,11 @@ class ViewModel::AccessControlTest < ActiveSupport::TestCase
557
559
  end
558
560
 
559
561
  vm_changes = ctx.valid_edit_changes(vm.to_reference)
560
- assert_changes_match(vm_changes, false, false, true, [], ['child'])
562
+ assert_changes_match(vm_changes, nstc: true, ass: ['child'])
561
563
 
562
564
  oc_changes = ctx.valid_edit_changes(
563
565
  ViewModel::Reference.new(child_viewmodel_class, old_child.id))
564
- assert_changes_match(oc_changes, false, true, false, [], [])
566
+ assert_changes_match(oc_changes, d: true)
565
567
  end
566
568
  end
567
569
 
@@ -585,7 +587,7 @@ class ViewModel::AccessControlTest < ActiveSupport::TestCase
585
587
  end
586
588
 
587
589
  vm_changes = ctx.valid_edit_changes(vm.to_reference)
588
- assert_changes_match(vm_changes, false, false, true, [], ['children'])
590
+ assert_changes_match(vm_changes, nstc: true, ass: ['children'])
589
591
 
590
592
  new_children, existing_children = vm.children.partition do |c|
591
593
  c.name < 'm'
@@ -593,7 +595,7 @@ class ViewModel::AccessControlTest < ActiveSupport::TestCase
593
595
 
594
596
  new_children.each do |c|
595
597
  c_changes = ctx.valid_edit_changes(c.to_reference)
596
- assert_changes_match(c_changes, true, false, false, ['name'], [])
598
+ assert_changes_match(c_changes, n: true, att: ['name'])
597
599
  end
598
600
 
599
601
  existing_children.each do |c|
@@ -613,15 +615,15 @@ class ViewModel::AccessControlTest < ActiveSupport::TestCase
613
615
  refute(vm.children.include?(replaced_child))
614
616
 
615
617
  vm_changes = ctx.valid_edit_changes(vm.to_reference)
616
- assert_changes_match(vm_changes, false, false, true, [], ['children'])
618
+ assert_changes_match(vm_changes, nstc: true, ass: ['children'])
617
619
 
618
620
  new_child = vm.children.detect { |c| c.name == 'b' }
619
621
  c_changes = ctx.valid_edit_changes(new_child.to_reference)
620
- assert_changes_match(c_changes, true, false, false, ['name'], [])
622
+ assert_changes_match(c_changes, n:true, att: ['name'])
621
623
 
622
624
  oc_changes = ctx.valid_edit_changes(
623
625
  ViewModel::Reference.new(child_viewmodel_class, replaced_child.id))
624
- assert_changes_match(oc_changes, false, true, false, [], [])
626
+ assert_changes_match(oc_changes, d: true)
625
627
  end
626
628
 
627
629
  it 'records reordered children' do
@@ -630,7 +632,7 @@ class ViewModel::AccessControlTest < ActiveSupport::TestCase
630
632
  end
631
633
 
632
634
  vm_changes = ctx.valid_edit_changes(vm.to_reference)
633
- assert_changes_match(vm_changes, false, false, false, [], ['children'])
635
+ assert_changes_match(vm_changes, ass: ['children'])
634
636
 
635
637
  vm.children.each do |c|
636
638
  refute(ctx.was_edited?(c.to_reference))
@@ -639,23 +641,23 @@ class ViewModel::AccessControlTest < ActiveSupport::TestCase
639
641
  end
640
642
 
641
643
  describe 'with parent and shared child test models' do
642
- include ViewModelSpecHelpers::ParentAndSharedChild
644
+ include ViewModelSpecHelpers::ParentAndSharedBelongsToChild
643
645
 
644
646
  def new_model
645
647
  model_class.new(name: 'a', child: child_model_class.new(name: 'z'))
646
648
  end
647
649
 
648
- it 'records an change to child without a tree change' do
650
+ it 'records a change to child without a tree change' do
649
651
  vm, ctx = alter_by_view!(viewmodel_class, create_model!) do |view, refs|
650
652
  view['child'] = { '_ref' => 'cref' }
651
653
  refs.clear['cref'] = { '_type' => child_view_name, 'name' => 'b' }
652
654
  end
653
655
 
654
656
  vm_changes = ctx.valid_edit_changes(vm.to_reference)
655
- assert_changes_match(vm_changes, false, false, false, [], ['child'])
657
+ assert_changes_match(vm_changes, ass: ['child'])
656
658
 
657
659
  c_changes = ctx.valid_edit_changes(vm.child.to_reference)
658
- assert_changes_match(c_changes, true, false, false, ['name'], [])
660
+ assert_changes_match(c_changes, n: true, att: ['name'])
659
661
  end
660
662
 
661
663
  it 'records an edited child without a tree change' do
@@ -664,10 +666,10 @@ class ViewModel::AccessControlTest < ActiveSupport::TestCase
664
666
  end
665
667
 
666
668
  refute(ctx.was_edited?(vm.to_reference))
667
- assert_changes_match(vm.previous_changes, false, false, false, [], [])
669
+ assert_changes_match(vm.previous_changes)
668
670
 
669
671
  c_changes = ctx.valid_edit_changes(vm.child.to_reference)
670
- assert_changes_match(c_changes, false, false, false, ['name'], [])
672
+ assert_changes_match(c_changes, att: ['name'])
671
673
  end
672
674
 
673
675
  it 'records a deleted child' do
@@ -680,12 +682,61 @@ class ViewModel::AccessControlTest < ActiveSupport::TestCase
680
682
  end
681
683
 
682
684
  vm_changes = ctx.valid_edit_changes(vm.to_reference)
683
- assert_changes_match(vm_changes, false, false, false, [], ['child'])
685
+ assert_changes_match(vm_changes, ass: ['child'])
684
686
 
685
687
  refute(ctx.was_edited?(old_child.to_reference))
686
688
  end
687
689
  end
688
690
 
691
+ describe 'with parent and owned referenced child test models' do
692
+ include ViewModelSpecHelpers::ParentAndReferencedHasOneChild
693
+
694
+ def new_model
695
+ model_class.new(name: 'a', child: child_model_class.new(name: 'z'))
696
+ end
697
+
698
+ it 'records a change to child with referenced tree change' do
699
+ vm, ctx = alter_by_view!(viewmodel_class, create_model!) do |view, refs|
700
+ view['child'] = { '_ref' => 'cref' }
701
+ refs.clear['cref'] = { '_type' => child_view_name, 'name' => 'b' }
702
+ end
703
+
704
+ vm_changes = ctx.valid_edit_changes(vm.to_reference)
705
+ assert_changes_match(vm_changes, refc: true, ass: ['child'])
706
+
707
+ c_changes = ctx.valid_edit_changes(vm.child.to_reference)
708
+ assert_changes_match(c_changes, n: true, att: ['name'])
709
+ end
710
+
711
+ it 'records an edited child with referenced tree change' do
712
+ vm, ctx = alter_by_view!(viewmodel_class, create_model!) do |_view, refs|
713
+ refs.values.first.merge!('name' => 'b')
714
+ end
715
+
716
+ refute(ctx.was_edited?(vm.to_reference))
717
+ assert_changes_match(vm.previous_changes, refc: true)
718
+
719
+ c_changes = ctx.valid_edit_changes(vm.child.to_reference)
720
+ assert_changes_match(c_changes, att: ['name'])
721
+ end
722
+
723
+ it 'records a deleted child' do
724
+ vm = create_viewmodel!
725
+ old_child = vm.child
726
+
727
+ vm, ctx = alter_by_view!(viewmodel_class, vm.model) do |view, refs|
728
+ view['child'] = nil
729
+ refs.clear
730
+ end
731
+
732
+ vm_changes = ctx.valid_edit_changes(vm.to_reference)
733
+ assert_changes_match(vm_changes, refc: true, ass: ['child'])
734
+
735
+ c_changes = ctx.valid_edit_changes(old_child.to_reference)
736
+ assert_changes_match(c_changes, d: true)
737
+ end
738
+ end
739
+
689
740
  describe 'with has_many_through children test models' do
690
741
  include ViewModelSpecHelpers::ParentAndHasManyThroughChildren
691
742
 
@@ -706,7 +757,7 @@ class ViewModel::AccessControlTest < ActiveSupport::TestCase
706
757
  end
707
758
 
708
759
  vm_changes = ctx.valid_edit_changes(vm.to_reference)
709
- assert_changes_match(vm_changes, false, false, false, [], ['children'])
760
+ assert_changes_match(vm_changes, ass: ['children'])
710
761
 
711
762
  new_children, existing_children = vm.children.partition do |c|
712
763
  c.name < 'm'
@@ -714,7 +765,7 @@ class ViewModel::AccessControlTest < ActiveSupport::TestCase
714
765
 
715
766
  new_children.each do |c|
716
767
  c_changes = ctx.valid_edit_changes(c.to_reference)
717
- assert_changes_match(c_changes, true, false, false, ['name'], [])
768
+ assert_changes_match(c_changes, n: true, att: ['name'])
718
769
  end
719
770
 
720
771
  existing_children.each do |c|
@@ -734,7 +785,7 @@ class ViewModel::AccessControlTest < ActiveSupport::TestCase
734
785
  end
735
786
 
736
787
  vm_changes = ctx.valid_edit_changes(vm.to_reference)
737
- assert_changes_match(vm_changes, false, false, false, [], ['children'])
788
+ assert_changes_match(vm_changes, ass: ['children'])
738
789
 
739
790
  new_children, existing_children = vm.children.partition do |c|
740
791
  c.name < 'm'
@@ -742,7 +793,7 @@ class ViewModel::AccessControlTest < ActiveSupport::TestCase
742
793
 
743
794
  new_children.each do |c|
744
795
  c_changes = ctx.valid_edit_changes(c.to_reference)
745
- assert_changes_match(c_changes, true, false, false, ['name'], [])
796
+ assert_changes_match(c_changes, n: true, att: ['name'])
746
797
  end
747
798
 
748
799
  existing_children.each do |c|
@@ -758,7 +809,7 @@ class ViewModel::AccessControlTest < ActiveSupport::TestCase
758
809
  end
759
810
 
760
811
  vm_changes = ctx.valid_edit_changes(vm.to_reference)
761
- assert_changes_match(vm_changes, false, false, false, [], ['children'])
812
+ assert_changes_match(vm_changes, ass: ['children'])
762
813
 
763
814
  vm.children.each do |c|
764
815
  refute(ctx.was_edited?(c.to_reference))