iknow_view_models 3.7.0 → 3.7.1
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/migrator.rb +23 -3
- data/lib/view_model/reference.rb +8 -0
- data/lib/view_model/references.rb +4 -3
- data/test/helpers/viewmodel_spec_helpers.rb +8 -0
- data/test/unit/view_model/active_record/migration_test.rb +98 -4
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1fb4421931099dc325d159573afcd9ea3529f6e29b4ac80f60d3628c9812df4c
|
4
|
+
data.tar.gz: 97d730c4d0a28ec9ce257906f69a1dd79e1b99c5fe025067ad57ba4ca9774931
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 53aff699c92efd1c334333b2f417444498c504b2f91ea57a00741e3e6e1e259c988723b23e68a7f2c16fba1a6906786471748f5adf5dc2797ca2a4d0924f10df
|
7
|
+
data.tar.gz: b739f19369e3282f6e897a000f04bb56b432796acbe78ca70777e349eef8f39a4058488032f4b42eeda0c4c7c4f60e9b4dba1fba1f2cf253a3c2bd960ff753e3
|
data/lib/view_model/migrator.rb
CHANGED
@@ -39,7 +39,26 @@ class ViewModel
|
|
39
39
|
def migrate!(serialization)
|
40
40
|
references = (serialization['references'] ||= {})
|
41
41
|
|
42
|
-
|
42
|
+
# First visit everything except references; there's no issue with adding
|
43
|
+
# new references during this.
|
44
|
+
migrate_tree!(serialization.except('references'), references: references)
|
45
|
+
|
46
|
+
# While visiting references itself, we need to take care that we can
|
47
|
+
# concurrently modify them (e.g. by adding new referenced views).
|
48
|
+
# Moreover, such added references must themselves be visited, as they'll
|
49
|
+
# be synthesized at the current version and so may need to be migrated
|
50
|
+
# down to the client's requested version.
|
51
|
+
visited_refs = []
|
52
|
+
loop do
|
53
|
+
unvisited_refs = references.keys - visited_refs
|
54
|
+
break if unvisited_refs.empty?
|
55
|
+
|
56
|
+
unvisited_refs.each do |ref|
|
57
|
+
migrate_tree!(references[ref], references: references)
|
58
|
+
end
|
59
|
+
|
60
|
+
visited_refs.concat(unvisited_refs)
|
61
|
+
end
|
43
62
|
|
44
63
|
GarbageCollection.garbage_collect_references!(serialization)
|
45
64
|
|
@@ -112,10 +131,11 @@ class ViewModel
|
|
112
131
|
path = @paths[view_name]
|
113
132
|
return false unless path
|
114
133
|
|
115
|
-
# We assume that an unspecified source version is the same as the required
|
116
|
-
# version.
|
117
134
|
required_version, current_version = @versions[view_name]
|
135
|
+
return false if source_version == current_version
|
118
136
|
|
137
|
+
# We assume that an unspecified source version is the same as the required
|
138
|
+
# version (i.e. the version demanded by the client request).
|
119
139
|
unless source_version.nil? || source_version == required_version
|
120
140
|
raise ViewModel::Migration::UnspecifiedVersionError.new(view_name, source_version)
|
121
141
|
end
|
data/lib/view_model/reference.rb
CHANGED
@@ -29,5 +29,13 @@ class ViewModel
|
|
29
29
|
def hash
|
30
30
|
[viewmodel_class, model_id].hash
|
31
31
|
end
|
32
|
+
|
33
|
+
# Generate a stable reference key for this viewmodel using type name and id
|
34
|
+
def stable_reference
|
35
|
+
raise RuntimeError.new('Model id required to generate a stable reference') unless model_id
|
36
|
+
|
37
|
+
hash = Digest::SHA256.base64digest("#{viewmodel_class.name}.#{model_id}")
|
38
|
+
"ref:h:#{hash}"
|
39
|
+
end
|
32
40
|
end
|
33
41
|
end
|
@@ -37,12 +37,13 @@ class ViewModel
|
|
37
37
|
|
38
38
|
private
|
39
39
|
|
40
|
-
# Ensure stable reference
|
40
|
+
# Ensure stable reference keys for the same (persisted) viewmodels. For
|
41
|
+
# unpersisted viewmodels, use a counter to generate a reference key unique
|
42
|
+
# to this serialization.
|
41
43
|
def new_ref!(viewmodel)
|
42
44
|
vm_ref = viewmodel.to_reference
|
43
45
|
if vm_ref.model_id
|
44
|
-
|
45
|
-
"ref:h:#{hash}"
|
46
|
+
vm_ref.stable_reference
|
46
47
|
else
|
47
48
|
format('ref:i:%06<count>d', count: (@last_ref += 1))
|
48
49
|
end
|
@@ -295,6 +295,14 @@ module ViewModelSpecHelpers
|
|
295
295
|
end
|
296
296
|
end
|
297
297
|
|
298
|
+
module ReferencedList
|
299
|
+
extend ActiveSupport::Concern
|
300
|
+
include ViewModelSpecHelpers::List
|
301
|
+
def model_attributes
|
302
|
+
super.merge(viewmodel: ->(_v) { root! })
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
298
306
|
module ParentAndHasOneChild
|
299
307
|
extend ActiveSupport::Concern
|
300
308
|
include ViewModelSpecHelpers::Base
|
@@ -436,16 +436,17 @@ class ViewModel::ActiveRecord::Migration < ActiveSupport::TestCase
|
|
436
436
|
let(:migrator) { down_migrator }
|
437
437
|
let(:subject) do
|
438
438
|
ser = current_serialization.deep_dup
|
439
|
-
raise ArgumentError.new(
|
439
|
+
raise ArgumentError.new('Expected no references') if ser.has_key?('references')
|
440
|
+
|
440
441
|
ser
|
441
442
|
end
|
442
443
|
|
443
444
|
let(:expected_result) do
|
444
445
|
{
|
445
446
|
'data' => v1_serialization_data.deep_dup.deep_merge(
|
446
|
-
{ ViewModel::MIGRATED_ATTRIBUTE => true }
|
447
|
+
{ ViewModel::MIGRATED_ATTRIBUTE => true },
|
447
448
|
),
|
448
|
-
'references' => v1_serialization_references
|
449
|
+
'references' => v1_serialization_references,
|
449
450
|
}
|
450
451
|
end
|
451
452
|
|
@@ -460,7 +461,8 @@ class ViewModel::ActiveRecord::Migration < ActiveSupport::TestCase
|
|
460
461
|
let(:migrator) { up_migrator }
|
461
462
|
let(:subject) do
|
462
463
|
ser = v1_serialization.deep_dup
|
463
|
-
raise ArgumentError.new(
|
464
|
+
raise ArgumentError.new('Expected references') unless ser.has_key?('references')
|
465
|
+
|
464
466
|
ser
|
465
467
|
end
|
466
468
|
|
@@ -480,4 +482,96 @@ class ViewModel::ActiveRecord::Migration < ActiveSupport::TestCase
|
|
480
482
|
end
|
481
483
|
end
|
482
484
|
end
|
485
|
+
|
486
|
+
describe 'concurrently inserting a reference' do
|
487
|
+
include ViewModelSpecHelpers::ReferencedList
|
488
|
+
let(:migration_versions) { { viewmodel_class => 1 } }
|
489
|
+
|
490
|
+
# Use a list with two members
|
491
|
+
def new_model
|
492
|
+
model_class.new(name: 'root',
|
493
|
+
next: model_class.new(name: 'old-tail'))
|
494
|
+
end
|
495
|
+
|
496
|
+
# Define a down migration that matches the old tail to insert a new tail
|
497
|
+
# after it, and the new tail to change its name.
|
498
|
+
def model_attributes
|
499
|
+
super.merge(
|
500
|
+
viewmodel: ->(v) {
|
501
|
+
self.schema_version = 2
|
502
|
+
|
503
|
+
migrates from: 1, to: 2 do
|
504
|
+
down do |view, refs|
|
505
|
+
case view['name']
|
506
|
+
when 'old-tail'
|
507
|
+
view['next'] = { ViewModel::REFERENCE_ATTRIBUTE => 'ref:s:new_tail' }
|
508
|
+
refs['ref:s:new_tail'] = {
|
509
|
+
ViewModel::TYPE_ATTRIBUTE => v.view_name,
|
510
|
+
ViewModel::VERSION_ATTRIBUTE => v.schema_version,
|
511
|
+
'id' => 100, # entirely fake
|
512
|
+
'name' => 'new-tail',
|
513
|
+
'next' => nil,
|
514
|
+
}
|
515
|
+
|
516
|
+
when 'new-tail'
|
517
|
+
view['name'] = 'newer-tail'
|
518
|
+
end
|
519
|
+
end
|
520
|
+
end
|
521
|
+
},
|
522
|
+
)
|
523
|
+
end
|
524
|
+
|
525
|
+
let(:v1_serialization_data) do
|
526
|
+
{
|
527
|
+
ViewModel::TYPE_ATTRIBUTE => viewmodel_class.view_name,
|
528
|
+
ViewModel::VERSION_ATTRIBUTE => 1,
|
529
|
+
ViewModel::ID_ATTRIBUTE => viewmodel.id,
|
530
|
+
'name' => viewmodel.name,
|
531
|
+
'next' => { ViewModel::REFERENCE_ATTRIBUTE => viewmodel.next.to_reference.stable_reference },
|
532
|
+
ViewModel::MIGRATED_ATTRIBUTE => true,
|
533
|
+
}
|
534
|
+
end
|
535
|
+
|
536
|
+
let(:v1_serialization_references) do
|
537
|
+
old_tail = viewmodel.next
|
538
|
+
old_tail_ref = old_tail.to_reference.stable_reference
|
539
|
+
{
|
540
|
+
old_tail_ref => {
|
541
|
+
ViewModel::TYPE_ATTRIBUTE => viewmodel_class.view_name,
|
542
|
+
ViewModel::VERSION_ATTRIBUTE => 1,
|
543
|
+
ViewModel::ID_ATTRIBUTE => old_tail.id,
|
544
|
+
'name' => 'old-tail',
|
545
|
+
'next' => { ViewModel::REFERENCE_ATTRIBUTE => 'ref:s:new_tail' },
|
546
|
+
ViewModel::MIGRATED_ATTRIBUTE => true,
|
547
|
+
},
|
548
|
+
'ref:s:new_tail' => {
|
549
|
+
ViewModel::TYPE_ATTRIBUTE => viewmodel_class.view_name,
|
550
|
+
ViewModel::VERSION_ATTRIBUTE => 1,
|
551
|
+
ViewModel::ID_ATTRIBUTE => 100,
|
552
|
+
'name' => 'newer-tail',
|
553
|
+
'next' => nil,
|
554
|
+
ViewModel::MIGRATED_ATTRIBUTE => true,
|
555
|
+
},
|
556
|
+
}
|
557
|
+
end
|
558
|
+
|
559
|
+
let(:v1_serialization) do
|
560
|
+
{
|
561
|
+
'data' => v1_serialization_data,
|
562
|
+
'references' => v1_serialization_references,
|
563
|
+
}
|
564
|
+
end
|
565
|
+
|
566
|
+
describe 'downwards' do
|
567
|
+
let(:migrator) { down_migrator }
|
568
|
+
let(:subject) { current_serialization.deep_dup }
|
569
|
+
|
570
|
+
it 'migrates' do
|
571
|
+
migrate!
|
572
|
+
|
573
|
+
assert_equal(v1_serialization, subject)
|
574
|
+
end
|
575
|
+
end
|
576
|
+
end
|
483
577
|
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.7.
|
4
|
+
version: 3.7.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- iKnow Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-11-
|
11
|
+
date: 2022-11-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actionpack
|