iknow_view_models 3.2.2 → 3.2.7
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/lib/iknow_view_models/version.rb +1 -1
- data/lib/view_model.rb +3 -1
- data/lib/view_model/active_record.rb +5 -4
- data/lib/view_model/registry.rb +13 -1
- data/test/unit/view_model/record_test.rb +102 -84
- data/test/unit/view_model/registry_test.rb +38 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4873d88f99bcdf0d63c3db8cbf36af0990bd9dd88bca0e170159b873b8aa7212
|
4
|
+
data.tar.gz: b190cb5ec7806dfe4f8decbf4acf8f54b7fcc0857f271d1417b4d680a87c0622
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 57c4fad3880aa1ce8f3434827df3dd6a789561a0f3bd8210b774c86258b8a0d4be777cbb827760f6c405b7caa61875efb8a780b3a2a9d7eff203315490d5f450
|
7
|
+
data.tar.gz: ffe26b3f24098c1ce7bd07453ce5a4f9a0bfd9611e57a53ccb7394b98fc2b8af724dc598bca85e0d2713c457d3fb5cc8575006ed947ade06aa7efd11f4436c16
|
data/lib/view_model.rb
CHANGED
@@ -245,7 +245,9 @@ class ViewModel
|
|
245
245
|
|
246
246
|
def schema_hash(schema_versions)
|
247
247
|
version_string = schema_versions.to_a.sort.join(',')
|
248
|
-
|
248
|
+
# We want a short hash value, as this will be used in cache keys
|
249
|
+
hash = Digest::SHA256.digest(version_string).byteslice(0, 16)
|
250
|
+
Base64.urlsafe_encode64(hash, padding: false)
|
249
251
|
end
|
250
252
|
|
251
253
|
def preload_for_serialization(viewmodels, serialize_context: new_serialize_context, include_referenced: true, lock: nil)
|
@@ -224,7 +224,7 @@ class ViewModel::ActiveRecord < ViewModel::Record
|
|
224
224
|
DeepPreloader::Spec.new(association_specs)
|
225
225
|
end
|
226
226
|
|
227
|
-
def dependent_viewmodels(seen = Set.new, include_referenced: true)
|
227
|
+
def dependent_viewmodels(seen = Set.new, include_referenced: true, include_external: true)
|
228
228
|
return if seen.include?(self)
|
229
229
|
|
230
230
|
seen << self
|
@@ -232,19 +232,20 @@ class ViewModel::ActiveRecord < ViewModel::Record
|
|
232
232
|
_members.each_value do |data|
|
233
233
|
next unless data.is_a?(AssociationData)
|
234
234
|
next unless include_referenced || !data.referenced?
|
235
|
+
next unless include_external || !data.external?
|
235
236
|
|
236
237
|
data.viewmodel_classes.each do |vm|
|
237
|
-
vm.dependent_viewmodels(seen, include_referenced: include_referenced)
|
238
|
+
vm.dependent_viewmodels(seen, include_referenced: include_referenced, include_external: include_external)
|
238
239
|
end
|
239
240
|
end
|
240
241
|
|
241
242
|
seen
|
242
243
|
end
|
243
244
|
|
244
|
-
def deep_schema_version(include_referenced: true)
|
245
|
+
def deep_schema_version(include_referenced: true, include_external: true)
|
245
246
|
(@deep_schema_version ||= {})[include_referenced] ||=
|
246
247
|
begin
|
247
|
-
dependent_viewmodels(include_referenced: include_referenced).each_with_object({}) do |view, h|
|
248
|
+
dependent_viewmodels(include_referenced: include_referenced, include_external: include_external).each_with_object({}) do |view, h|
|
248
249
|
h[view.view_name] = view.schema_version
|
249
250
|
end.freeze
|
250
251
|
end
|
data/lib/view_model/registry.rb
CHANGED
@@ -6,7 +6,8 @@ class ViewModel::Registry
|
|
6
6
|
DEFERRED_NAME = Object.new
|
7
7
|
|
8
8
|
class << self
|
9
|
-
delegate :for_view_name, :register, :default_view_name, :infer_model_class_name,
|
9
|
+
delegate :for_view_name, :register, :default_view_name, :infer_model_class_name,
|
10
|
+
:clear_removed_classes!, :all, :roots,
|
10
11
|
to: :instance
|
11
12
|
end
|
12
13
|
|
@@ -33,6 +34,17 @@ class ViewModel::Registry
|
|
33
34
|
end
|
34
35
|
end
|
35
36
|
|
37
|
+
def all
|
38
|
+
@lock.synchronize do
|
39
|
+
resolve_deferred_classes
|
40
|
+
@viewmodel_classes_by_name.values
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def roots
|
45
|
+
all.select { |c| c.root? }
|
46
|
+
end
|
47
|
+
|
36
48
|
def register(viewmodel, as: DEFERRED_NAME)
|
37
49
|
@lock.synchronize do
|
38
50
|
@deferred_viewmodel_classes << [viewmodel, as]
|
@@ -365,122 +365,140 @@ class ViewModel::RecordTest < ActiveSupport::TestCase
|
|
365
365
|
end
|
366
366
|
end
|
367
367
|
|
368
|
-
|
368
|
+
describe 'nesting' do
|
369
|
+
let(:nested_model_class) do
|
370
|
+
klass = Struct.new(:member)
|
371
|
+
Object.const_set(:Nested, klass)
|
372
|
+
klass
|
373
|
+
end
|
369
374
|
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
+
let(:nested_viewmodel_class) do
|
376
|
+
mc = nested_model_class
|
377
|
+
klass = Class.new(TestViewModel) do
|
378
|
+
self.view_name = 'Nested'
|
379
|
+
self.model_class = mc
|
380
|
+
attribute :member
|
381
|
+
end
|
382
|
+
Object.const_set(:NestedView, klass)
|
383
|
+
klass
|
384
|
+
end
|
375
385
|
|
376
|
-
|
377
|
-
|
378
|
-
|
386
|
+
def teardown
|
387
|
+
Object.send(:remove_const, :Nested)
|
388
|
+
Object.send(:remove_const, :NestedView)
|
389
|
+
ActiveSupport::Dependencies::Reference.clear!
|
390
|
+
super
|
391
|
+
end
|
379
392
|
|
380
|
-
|
393
|
+
describe 'with nested viewmodel' do
|
394
|
+
let(:default_nested_model) { nested_model_class.new('member') }
|
395
|
+
let(:default_nested_view) { view_base.merge('_type' => 'Nested', 'member' => 'member') }
|
381
396
|
|
382
|
-
|
383
|
-
let(:default_model_values) { { nested: default_nested_model } }
|
397
|
+
let(:attributes) { { simple: {}, nested: { using: nested_viewmodel_class } } }
|
384
398
|
|
385
|
-
|
386
|
-
|
387
|
-
access_control: access_control)
|
388
|
-
end
|
399
|
+
let(:default_view_values) { { nested: default_nested_view } }
|
400
|
+
let(:default_model_values) { { nested: default_nested_model } }
|
389
401
|
|
390
|
-
|
391
|
-
|
392
|
-
|
402
|
+
let(:update_context) do
|
403
|
+
TestDeserializeContext.new(targets: [default_model, default_nested_model],
|
404
|
+
access_control: access_control)
|
405
|
+
end
|
393
406
|
|
394
|
-
|
395
|
-
|
407
|
+
include CanSerialize
|
408
|
+
include CanDeserializeToNew
|
409
|
+
include CanDeserializeToExisting
|
396
410
|
|
397
|
-
|
411
|
+
it 'can update the nested value' do
|
412
|
+
new_view = default_view.merge('nested' => default_nested_view.merge('member' => 'changed'))
|
398
413
|
|
399
|
-
|
400
|
-
assert(default_nested_model.equal?(vm.model.nested), 'returned nested model was not the same')
|
414
|
+
vm = viewmodel_class.deserialize_from_view(new_view, deserialize_context: update_context)
|
401
415
|
|
402
|
-
|
416
|
+
assert(default_model.equal?(vm.model), 'returned model was not the same')
|
417
|
+
assert(default_nested_model.equal?(vm.model.nested), 'returned nested model was not the same')
|
403
418
|
|
404
|
-
|
405
|
-
assert_edited(vm.nested, changed_attributes: [:member])
|
406
|
-
end
|
419
|
+
assert_equal('changed', default_model.nested.member)
|
407
420
|
|
408
|
-
|
409
|
-
|
410
|
-
|
421
|
+
assert_unchanged(vm)
|
422
|
+
assert_edited(vm.nested, changed_attributes: [:member])
|
423
|
+
end
|
411
424
|
|
412
|
-
|
413
|
-
|
425
|
+
it 'can replace the nested value' do
|
426
|
+
# The value will be unified if it is different after deserialization
|
427
|
+
new_view = default_view.merge('nested' => default_nested_view.merge('member' => 'changed'))
|
414
428
|
|
415
|
-
|
429
|
+
partial_update_context = TestDeserializeContext.new(targets: [default_model],
|
430
|
+
access_control: access_control)
|
416
431
|
|
417
|
-
|
418
|
-
refute(default_nested_model.equal?(vm.model.nested), 'returned nested model was the same')
|
432
|
+
vm = viewmodel_class.deserialize_from_view(new_view, deserialize_context: partial_update_context)
|
419
433
|
|
420
|
-
|
421
|
-
|
434
|
+
assert(default_model.equal?(vm.model), 'returned model was not the same')
|
435
|
+
refute(default_nested_model.equal?(vm.model.nested), 'returned nested model was the same')
|
436
|
+
|
437
|
+
assert_edited(vm, new: false, changed_attributes: [:nested])
|
438
|
+
assert_edited(vm.nested, new: true, changed_attributes: [:member])
|
439
|
+
end
|
422
440
|
end
|
423
|
-
end
|
424
441
|
|
425
|
-
|
426
|
-
|
427
|
-
|
442
|
+
describe 'with array of nested viewmodel' do
|
443
|
+
let(:default_nested_model_1) { nested_model_class.new('member1') }
|
444
|
+
let(:default_nested_view_1) { view_base.merge('_type' => 'Nested', 'member' => 'member1') }
|
428
445
|
|
429
|
-
|
430
|
-
|
446
|
+
let(:default_nested_model_2) { nested_model_class.new('member2') }
|
447
|
+
let(:default_nested_view_2) { view_base.merge('_type' => 'Nested', 'member' => 'member2') }
|
431
448
|
|
432
|
-
|
449
|
+
let(:attributes) { { simple: {}, nested: { using: nested_viewmodel_class, array: true } } }
|
433
450
|
|
434
|
-
|
435
|
-
|
451
|
+
let(:default_view_values) { { nested: [default_nested_view_1, default_nested_view_2] } }
|
452
|
+
let(:default_model_values) { { nested: [default_nested_model_1, default_nested_model_2] } }
|
436
453
|
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
454
|
+
let(:update_context) {
|
455
|
+
TestDeserializeContext.new(targets: [default_model, default_nested_model_1, default_nested_model_2],
|
456
|
+
access_control: access_control)
|
457
|
+
}
|
441
458
|
|
442
|
-
|
443
|
-
|
444
|
-
|
459
|
+
include CanSerialize
|
460
|
+
include CanDeserializeToNew
|
461
|
+
include CanDeserializeToExisting
|
445
462
|
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
463
|
+
it 'rejects change to attribute' do
|
464
|
+
new_view = default_view.merge('nested' => 'terrible')
|
465
|
+
ex = assert_raises(ViewModel::DeserializationError::InvalidAttributeType) do
|
466
|
+
viewmodel_class.deserialize_from_view(new_view, deserialize_context: update_context)
|
467
|
+
end
|
468
|
+
assert_equal('nested', ex.attribute)
|
469
|
+
assert_equal('Array', ex.expected_type)
|
470
|
+
assert_equal('String', ex.provided_type)
|
450
471
|
end
|
451
|
-
assert_equal('nested', ex.attribute)
|
452
|
-
assert_equal('Array', ex.expected_type)
|
453
|
-
assert_equal('String', ex.provided_type)
|
454
|
-
end
|
455
472
|
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
473
|
+
it 'can edit a nested value' do
|
474
|
+
default_view['nested'][0]['member'] = 'changed'
|
475
|
+
vm = viewmodel_class.deserialize_from_view(default_view, deserialize_context: update_context)
|
476
|
+
assert(default_model.equal?(vm.model), 'returned model was not the same')
|
477
|
+
assert_equal(2, vm.model.nested.size)
|
478
|
+
assert(default_nested_model_1.equal?(vm.model.nested[0]))
|
479
|
+
assert(default_nested_model_2.equal?(vm.model.nested[1]))
|
463
480
|
|
464
|
-
|
465
|
-
|
466
|
-
|
481
|
+
assert_unchanged(vm)
|
482
|
+
assert_edited(vm.nested[0], changed_attributes: [:member])
|
483
|
+
end
|
467
484
|
|
468
|
-
|
469
|
-
|
485
|
+
it 'can append a nested value' do
|
486
|
+
default_view['nested'] << view_base.merge('_type' => 'Nested', 'member' => 'member3')
|
470
487
|
|
471
|
-
|
488
|
+
vm = viewmodel_class.deserialize_from_view(default_view, deserialize_context: update_context)
|
472
489
|
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
490
|
+
assert(default_model.equal?(vm.model), 'returned model was not the same')
|
491
|
+
assert_equal(3, vm.model.nested.size)
|
492
|
+
assert(default_nested_model_1.equal?(vm.model.nested[0]))
|
493
|
+
assert(default_nested_model_2.equal?(vm.model.nested[1]))
|
477
494
|
|
478
|
-
|
479
|
-
|
480
|
-
|
495
|
+
vm.model.nested.each_with_index do |nvm, i|
|
496
|
+
assert_equal("member#{i + 1}", nvm.member)
|
497
|
+
end
|
481
498
|
|
482
|
-
|
483
|
-
|
499
|
+
assert_edited(vm, changed_attributes: [:nested])
|
500
|
+
assert_edited(vm.nested[2], new: true, changed_attributes: [:member])
|
501
|
+
end
|
484
502
|
end
|
485
503
|
end
|
486
504
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'minitest/unit'
|
5
|
+
require 'minitest/hooks'
|
6
|
+
|
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'
|
13
|
+
|
14
|
+
class ViewModel
|
15
|
+
class RegistryTest < ActiveSupport::TestCase
|
16
|
+
using ViewModel::Utils::Collections
|
17
|
+
include ARVMTestUtilities
|
18
|
+
extend Minitest::Spec::DSL
|
19
|
+
include ViewModelSpecHelpers::ParentAndBelongsToChild
|
20
|
+
|
21
|
+
before(:each) do
|
22
|
+
ViewModel::Registry.clear_removed_classes!
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'registers the views' do
|
26
|
+
assert_equal(ViewModel::Registry.for_view_name(view_name), viewmodel_class)
|
27
|
+
assert_equal(ViewModel::Registry.for_view_name(child_view_name), child_viewmodel_class)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'enumerates the views' do
|
31
|
+
assert_contains_exactly([ViewModel::ErrorView, viewmodel_class, child_viewmodel_class], ViewModel::Registry.all)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'enumerates the root views' do
|
35
|
+
assert_contains_exactly([viewmodel_class], ViewModel::Registry.roots)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: iknow_view_models
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.2.
|
4
|
+
version: 3.2.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- iKnow Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-10-
|
11
|
+
date: 2020-10-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -468,6 +468,7 @@ files:
|
|
468
468
|
- test/unit/view_model/controller_test.rb
|
469
469
|
- test/unit/view_model/deserialization_error/unique_violation_test.rb
|
470
470
|
- test/unit/view_model/record_test.rb
|
471
|
+
- test/unit/view_model/registry_test.rb
|
471
472
|
- test/unit/view_model/traversal_context_test.rb
|
472
473
|
- test/unit/view_model_test.rb
|
473
474
|
homepage: https://github.com/iknow/cerego_view_models
|
@@ -527,5 +528,6 @@ test_files:
|
|
527
528
|
- test/unit/view_model/controller_test.rb
|
528
529
|
- test/unit/view_model/deserialization_error/unique_violation_test.rb
|
529
530
|
- test/unit/view_model/record_test.rb
|
531
|
+
- test/unit/view_model/registry_test.rb
|
530
532
|
- test/unit/view_model/traversal_context_test.rb
|
531
533
|
- test/unit/view_model_test.rb
|