iknow_view_models 3.2.10 → 3.2.11
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 +1 -0
- data/lib/view_model/active_record/cache.rb +8 -9
- data/lib/view_model/active_record/controller.rb +2 -2
- data/lib/view_model/garbage_collection.rb +43 -0
- data/lib/view_model/migrator.rb +17 -5
- data/test/helpers/viewmodel_spec_helpers.rb +9 -3
- data/test/unit/view_model/active_record/cache_test.rb +1 -1
- data/test/unit/view_model/active_record/migration_test.rb +124 -35
- data/test/unit/view_model/garbage_collection_test.rb +80 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2a75096a1b8ac47eee4ff5b2a303a0d447cfe8e93668f579bb697b863947eaa5
|
4
|
+
data.tar.gz: ca0edc9b15a0b436d36d7b12dbd8f4255008ad4a6cd6d1ed23a352a989013fa1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 683a95fe51734a420f87f4709942314ec03ee32a8a95a63487bb4495eaad7a61c0f6ba4216d67ee31f33acf9f593607833eebcd3fd9e1dfd8a4f3440a337f249
|
7
|
+
data.tar.gz: e889492e1e0b76a3f8b3ed8775c16fa6f67f6a45eb9ed14e09f53f41b3dc6a1675d093eec75ba2b94d79567238d22d4996236a5388dafb5ee078fb9760d0c97e
|
data/lib/view_model.rb
CHANGED
@@ -177,28 +177,27 @@ class ViewModel::ActiveRecord::Cache
|
|
177
177
|
ViewModel.serialize(viewmodel, json, serialize_context: serialize_context)
|
178
178
|
end
|
179
179
|
|
180
|
+
# viewmodels referenced from roots
|
180
181
|
referenced_viewmodels = serialize_context.extract_referenced_views!
|
181
182
|
|
182
183
|
if migration_versions.present?
|
183
184
|
migrator = ViewModel::DownMigrator.new(migration_versions)
|
184
185
|
|
185
|
-
# This migration isn't
|
186
|
-
#
|
187
|
-
#
|
188
|
-
#
|
189
|
-
#
|
190
|
-
# must introduce children or alter the contents of its referenced
|
191
|
-
# children, we may have to avoid caching while the migration is in
|
192
|
-
# use.
|
186
|
+
# This migration isn't able to affect the contents of referenced
|
187
|
+
# views, only their presence. The references will be themselves
|
188
|
+
# rendered (and migrated) independently later. We mark the dummy
|
189
|
+
# references provided to exclude their partial contents from being
|
190
|
+
# themselves migrated.
|
193
191
|
dummy_references = referenced_viewmodels.transform_values do |ref_vm|
|
194
192
|
{
|
195
193
|
ViewModel::TYPE_ATTRIBUTE => ref_vm.class.view_name,
|
196
194
|
ViewModel::VERSION_ATTRIBUTE => ref_vm.class.schema_version,
|
197
195
|
ViewModel::ID_ATTRIBUTE => ref_vm.id,
|
196
|
+
ViewModel::Migrator::EXCLUDE_FROM_MIGRATION => true,
|
198
197
|
}.freeze
|
199
198
|
end
|
200
199
|
|
201
|
-
migrator.migrate!(builder.attributes!, references
|
200
|
+
migrator.migrate!({ 'data' => builder.attributes!, 'references' => dummy_references })
|
202
201
|
|
203
202
|
# Removed dummy references can be removed from referenced_viewmodels.
|
204
203
|
referenced_viewmodels.keep_if { |k, _| dummy_references.has_key?(k) }
|
@@ -71,7 +71,7 @@ module ViewModel::ActiveRecord::Controller
|
|
71
71
|
super.tap do |update_hash, refs|
|
72
72
|
if migration_versions.present?
|
73
73
|
migrator = ViewModel::UpMigrator.new(migration_versions)
|
74
|
-
migrator.migrate!(
|
74
|
+
migrator.migrate!({ 'data' => update_hash, 'references' => refs })
|
75
75
|
end
|
76
76
|
end
|
77
77
|
end
|
@@ -84,7 +84,7 @@ module ViewModel::ActiveRecord::Controller
|
|
84
84
|
if migration_versions.present?
|
85
85
|
tree = jbuilder.attributes!
|
86
86
|
migrator = ViewModel::DownMigrator.new(migration_versions)
|
87
|
-
migrator.migrate!(tree
|
87
|
+
migrator.migrate!(tree)
|
88
88
|
end
|
89
89
|
end
|
90
90
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ViewModel::GarbageCollection
|
4
|
+
class << self
|
5
|
+
def garbage_collect_references!(serialization)
|
6
|
+
return unless serialization.has_key?('references')
|
7
|
+
|
8
|
+
roots = serialization.except('references')
|
9
|
+
references = serialization['references']
|
10
|
+
|
11
|
+
worklist = Set.new(collect_references(roots))
|
12
|
+
visited = Set.new
|
13
|
+
|
14
|
+
while (live = worklist.first)
|
15
|
+
worklist.delete(live)
|
16
|
+
visited << live
|
17
|
+
collect_references(references[live]) do |ref|
|
18
|
+
worklist << ref unless visited.include?(ref)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
references.keep_if { |ref, _val| visited.include?(ref) }
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
## yield each reference encountered in tree
|
28
|
+
def collect_references(tree, &block)
|
29
|
+
return enum_for(__method__, tree) unless block_given?
|
30
|
+
|
31
|
+
case tree
|
32
|
+
when Hash
|
33
|
+
if tree.size == 1 && (ref = tree[ViewModel::REFERENCE_ATTRIBUTE])
|
34
|
+
block.(ref)
|
35
|
+
else
|
36
|
+
tree.each_value { |t| collect_references(t, &block) }
|
37
|
+
end
|
38
|
+
when Array
|
39
|
+
tree.each { |t| collect_references(t, &block) }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/view_model/migrator.rb
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
class ViewModel
|
4
4
|
class Migrator
|
5
|
+
EXCLUDE_FROM_MIGRATION = '_exclude_from_migration'
|
6
|
+
|
5
7
|
class << self
|
6
8
|
def migrated_deep_schema_version(viewmodel_class, required_versions, include_referenced: true)
|
7
9
|
deep_schema_version = viewmodel_class.deep_schema_version(include_referenced: include_referenced)
|
@@ -34,27 +36,37 @@ class ViewModel
|
|
34
36
|
end
|
35
37
|
end
|
36
38
|
|
37
|
-
def migrate!(
|
39
|
+
def migrate!(serialization)
|
40
|
+
migrate_tree!(serialization, references: serialization['references'] || {})
|
41
|
+
GarbageCollection.garbage_collect_references!(serialization)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def migrate_tree!(node, references:)
|
38
47
|
case node
|
39
48
|
when Hash
|
40
49
|
if (type = node[ViewModel::TYPE_ATTRIBUTE])
|
41
50
|
version = node[ViewModel::VERSION_ATTRIBUTE]
|
42
51
|
|
52
|
+
# We allow subtrees to be excluded from migration. This is used
|
53
|
+
# internally to permit stub references that are not a full
|
54
|
+
# serialization of the referenced type: see ViewModel::Cache.
|
55
|
+
return if node[EXCLUDE_FROM_MIGRATION]
|
56
|
+
|
43
57
|
if migrate_viewmodel!(type, version, node, references)
|
44
58
|
node[ViewModel::MIGRATED_ATTRIBUTE] = true
|
45
59
|
end
|
46
60
|
end
|
47
61
|
|
48
62
|
node.each_value do |child|
|
49
|
-
|
63
|
+
migrate_tree!(child, references: references)
|
50
64
|
end
|
51
65
|
when Array
|
52
|
-
node.each { |child|
|
66
|
+
node.each { |child| migrate_tree!(child, references: references) }
|
53
67
|
end
|
54
68
|
end
|
55
69
|
|
56
|
-
private
|
57
|
-
|
58
70
|
def migrate_viewmodel!(_view_name, _version, _view_hash, _references)
|
59
71
|
raise RuntimeError.new('abstract method')
|
60
72
|
end
|
@@ -141,10 +141,10 @@ module ViewModelSpecHelpers
|
|
141
141
|
end
|
142
142
|
end
|
143
143
|
|
144
|
-
module
|
144
|
+
module ParentAndChildMigrations
|
145
145
|
extend ActiveSupport::Concern
|
146
|
-
|
147
|
-
|
146
|
+
|
147
|
+
def model_attributes
|
148
148
|
super.merge(
|
149
149
|
schema: ->(t) { t.integer :new_field, default: 1, null: false },
|
150
150
|
viewmodel: ->(_v) {
|
@@ -206,6 +206,12 @@ module ViewModelSpecHelpers
|
|
206
206
|
end
|
207
207
|
end
|
208
208
|
|
209
|
+
module ParentAndBelongsToChildWithMigration
|
210
|
+
extend ActiveSupport::Concern
|
211
|
+
include ViewModelSpecHelpers::ParentAndBelongsToChild
|
212
|
+
include ViewModelSpecHelpers::ParentAndChildMigrations
|
213
|
+
end
|
214
|
+
|
209
215
|
module ParentAndSharedBelongsToChild
|
210
216
|
extend ActiveSupport::Concern
|
211
217
|
include ViewModelSpecHelpers::ParentAndBelongsToChild
|
@@ -122,7 +122,7 @@ class ViewModel::ActiveRecord
|
|
122
122
|
|
123
123
|
if migration_versions.present?
|
124
124
|
migrator = ViewModel::DownMigrator.new(migration_versions)
|
125
|
-
migrator.migrate!(
|
125
|
+
migrator.migrate!({ 'data' => data, 'references' => refs })
|
126
126
|
end
|
127
127
|
|
128
128
|
[data, refs]
|
@@ -24,25 +24,39 @@ class ViewModel::ActiveRecord::Migration < ActiveSupport::TestCase
|
|
24
24
|
let(:up_migrator) { ViewModel::UpMigrator.new(migration_versions) }
|
25
25
|
|
26
26
|
def migrate!
|
27
|
-
migrator.migrate!(subject
|
27
|
+
migrator.migrate!(subject)
|
28
28
|
end
|
29
29
|
|
30
|
-
let(:current_serialization)
|
30
|
+
let(:current_serialization) do
|
31
|
+
ctx = viewmodel_class.new_serialize_context
|
32
|
+
view = ViewModel.serialize_to_hash(viewmodel, serialize_context: ctx)
|
33
|
+
refs = ctx.serialize_references_to_hash
|
34
|
+
{ 'data' => view, 'references' => refs }
|
35
|
+
end
|
31
36
|
|
32
|
-
let(:
|
37
|
+
let(:v2_serialization_data) do
|
33
38
|
{
|
34
|
-
|
35
|
-
ViewModel::VERSION_ATTRIBUTE => 2,
|
36
|
-
ViewModel::ID_ATTRIBUTE => viewmodel.id,
|
37
|
-
'name' => viewmodel.name,
|
38
|
-
'old_field' => 1,
|
39
|
-
'child' => {
|
40
|
-
ViewModel::TYPE_ATTRIBUTE => child_viewmodel_class.view_name,
|
39
|
+
ViewModel::TYPE_ATTRIBUTE => viewmodel_class.view_name,
|
41
40
|
ViewModel::VERSION_ATTRIBUTE => 2,
|
42
|
-
ViewModel::ID_ATTRIBUTE => viewmodel.
|
43
|
-
'name' => viewmodel.
|
44
|
-
'
|
45
|
-
|
41
|
+
ViewModel::ID_ATTRIBUTE => viewmodel.id,
|
42
|
+
'name' => viewmodel.name,
|
43
|
+
'old_field' => 1,
|
44
|
+
'child' => {
|
45
|
+
ViewModel::TYPE_ATTRIBUTE => child_viewmodel_class.view_name,
|
46
|
+
ViewModel::VERSION_ATTRIBUTE => 2,
|
47
|
+
ViewModel::ID_ATTRIBUTE => viewmodel.child.id,
|
48
|
+
'name' => viewmodel.child.name,
|
49
|
+
'former_field' => 'former_value',
|
50
|
+
},
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
let(:v2_serialization_references) { {} }
|
55
|
+
|
56
|
+
let(:v2_serialization) do
|
57
|
+
{
|
58
|
+
'data' => v2_serialization_data,
|
59
|
+
'references' => v2_serialization_references,
|
46
60
|
}
|
47
61
|
end
|
48
62
|
|
@@ -56,14 +70,15 @@ class ViewModel::ActiveRecord::Migration < ActiveSupport::TestCase
|
|
56
70
|
let(:expected_result) do
|
57
71
|
v2_serialization.deep_merge(
|
58
72
|
{
|
59
|
-
|
60
|
-
'old_field' => -1,
|
61
|
-
'child' => {
|
73
|
+
'data' => {
|
62
74
|
ViewModel::MIGRATED_ATTRIBUTE => true,
|
63
|
-
'
|
75
|
+
'old_field' => -1,
|
76
|
+
'child' => {
|
77
|
+
ViewModel::MIGRATED_ATTRIBUTE => true,
|
78
|
+
'former_field' => 'reconstructed',
|
79
|
+
},
|
64
80
|
},
|
65
|
-
}
|
66
|
-
)
|
81
|
+
})
|
67
82
|
end
|
68
83
|
|
69
84
|
it 'migrates' do
|
@@ -85,15 +100,21 @@ class ViewModel::ActiveRecord::Migration < ActiveSupport::TestCase
|
|
85
100
|
|
86
101
|
describe 'upwards' do
|
87
102
|
let(:migrator) { up_migrator }
|
88
|
-
let(:
|
103
|
+
let(:subject_data) { v2_serialization_data.deep_dup }
|
104
|
+
let(:subject_references) { v2_serialization_references.deep_dup }
|
105
|
+
let(:subject) { { 'data' => subject_data, 'references' => subject_references } }
|
89
106
|
|
90
107
|
let(:expected_result) do
|
91
108
|
current_serialization.deep_merge(
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
109
|
+
{
|
110
|
+
'data' => {
|
111
|
+
ViewModel::MIGRATED_ATTRIBUTE => true,
|
112
|
+
'new_field' => 3,
|
113
|
+
'child' => {
|
114
|
+
ViewModel::MIGRATED_ATTRIBUTE => true,
|
115
|
+
},
|
116
|
+
},
|
117
|
+
}
|
97
118
|
)
|
98
119
|
end
|
99
120
|
|
@@ -104,9 +125,8 @@ class ViewModel::ActiveRecord::Migration < ActiveSupport::TestCase
|
|
104
125
|
end
|
105
126
|
|
106
127
|
describe 'with version unspecified' do
|
107
|
-
let(:
|
108
|
-
|
109
|
-
.except(ViewModel::VERSION_ATTRIBUTE)
|
128
|
+
let(:subject_data) do
|
129
|
+
v2_serialization_data.except(ViewModel::VERSION_ATTRIBUTE)
|
110
130
|
end
|
111
131
|
|
112
132
|
it 'treats it as the requested version' do
|
@@ -116,8 +136,8 @@ class ViewModel::ActiveRecord::Migration < ActiveSupport::TestCase
|
|
116
136
|
end
|
117
137
|
|
118
138
|
describe 'with a version not in the specification' do
|
119
|
-
let(:
|
120
|
-
|
139
|
+
let(:subject_data) do
|
140
|
+
v2_serialization_data
|
121
141
|
.except('old_field')
|
122
142
|
.deep_merge(ViewModel::VERSION_ATTRIBUTE => 3, 'mid_field' => 1)
|
123
143
|
end
|
@@ -132,8 +152,8 @@ class ViewModel::ActiveRecord::Migration < ActiveSupport::TestCase
|
|
132
152
|
describe 'from an unreachable version' do
|
133
153
|
let(:migration_versions) { { viewmodel_class => 2, child_viewmodel_class => 1 } }
|
134
154
|
|
135
|
-
let(:
|
136
|
-
|
155
|
+
let(:subject_data) do
|
156
|
+
v2_serialization_data.deep_merge(
|
137
157
|
'child' => { ViewModel::VERSION_ATTRIBUTE => 1 },
|
138
158
|
)
|
139
159
|
end
|
@@ -148,8 +168,8 @@ class ViewModel::ActiveRecord::Migration < ActiveSupport::TestCase
|
|
148
168
|
describe 'in an undefined direction' do
|
149
169
|
let(:migration_versions) { { viewmodel_class => 1, child_viewmodel_class => 2 } }
|
150
170
|
|
151
|
-
let(:
|
152
|
-
|
171
|
+
let(:subject_data) do
|
172
|
+
v2_serialization_data.except('old_field').merge(ViewModel::VERSION_ATTRIBUTE => 1)
|
153
173
|
end
|
154
174
|
|
155
175
|
it 'raises' do
|
@@ -161,6 +181,75 @@ class ViewModel::ActiveRecord::Migration < ActiveSupport::TestCase
|
|
161
181
|
end
|
162
182
|
end
|
163
183
|
|
184
|
+
describe 'garbage collection' do
|
185
|
+
include ViewModelSpecHelpers::ParentAndSharedBelongsToChild
|
186
|
+
|
187
|
+
# current (v2) features the shared child, v1 did not
|
188
|
+
def model_attributes
|
189
|
+
super.merge(
|
190
|
+
viewmodel: ->(_v) {
|
191
|
+
self.schema_version = 2
|
192
|
+
migrates from: 1, to: 2 do
|
193
|
+
down do |view, refs|
|
194
|
+
view.delete('child')
|
195
|
+
end
|
196
|
+
end
|
197
|
+
})
|
198
|
+
end
|
199
|
+
|
200
|
+
# current (v2) refers to another child, v1 did not
|
201
|
+
def child_attributes
|
202
|
+
super.merge(
|
203
|
+
schema: ->(t) { t.references :child, foreign_key: true },
|
204
|
+
model: ->(m) {
|
205
|
+
belongs_to :child, inverse_of: :parent, dependent: :destroy
|
206
|
+
has_one :parent, inverse_of: :child, class_name: self.name
|
207
|
+
},
|
208
|
+
viewmodel: ->(_v) {
|
209
|
+
self.schema_version = 2
|
210
|
+
association :child
|
211
|
+
migrates from: 1, to: 2 do
|
212
|
+
down do |view, refs|
|
213
|
+
view.delete('child')
|
214
|
+
end
|
215
|
+
end
|
216
|
+
})
|
217
|
+
end
|
218
|
+
|
219
|
+
def new_model
|
220
|
+
model_class.new(name: 'm1',
|
221
|
+
child: child_model_class.new(
|
222
|
+
name: 'c1',
|
223
|
+
child: child_model_class.new(
|
224
|
+
name: 'c2')))
|
225
|
+
end
|
226
|
+
|
227
|
+
|
228
|
+
let(:migrator) { down_migrator }
|
229
|
+
let(:migration_versions) { { viewmodel_class => 1, child_viewmodel_class => 1 } }
|
230
|
+
|
231
|
+
let(:subject) { current_serialization.deep_dup }
|
232
|
+
|
233
|
+
let(:expected_result) do
|
234
|
+
{
|
235
|
+
'data' => {
|
236
|
+
ViewModel::TYPE_ATTRIBUTE => viewmodel_class.view_name,
|
237
|
+
ViewModel::VERSION_ATTRIBUTE => 1,
|
238
|
+
ViewModel::ID_ATTRIBUTE => viewmodel.id,
|
239
|
+
ViewModel::MIGRATED_ATTRIBUTE => true,
|
240
|
+
'name' => viewmodel.name,
|
241
|
+
},
|
242
|
+
'references' => {},
|
243
|
+
}
|
244
|
+
end
|
245
|
+
|
246
|
+
it 'migrates' do
|
247
|
+
migrate!
|
248
|
+
|
249
|
+
assert_equal(expected_result, subject)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
164
253
|
describe 'without migrations' do
|
165
254
|
describe 'to an unreachable version' do
|
166
255
|
include ViewModelSpecHelpers::ParentAndBelongsToChild
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'minitest/unit'
|
5
|
+
|
6
|
+
require 'view_model'
|
7
|
+
require 'view_model/garbage_collection'
|
8
|
+
|
9
|
+
class ViewModel::GarbageCollectionTest < ActiveSupport::TestCase
|
10
|
+
extend Minitest::Spec::DSL
|
11
|
+
|
12
|
+
# Generate a viewmodel-serialization alike from a minimal structure
|
13
|
+
# @param [Hash<Symbol, Array<Symbol>] structure mapping from id to referenced ids
|
14
|
+
# @param [Hash<Symbol, Array<Symbol>] data_ids list of ids of data elements
|
15
|
+
def mock_serialization(data_skeleton, refs_skeleton)
|
16
|
+
data = []
|
17
|
+
references = {}
|
18
|
+
|
19
|
+
generate(data_skeleton) do |id, body|
|
20
|
+
data << body
|
21
|
+
end
|
22
|
+
|
23
|
+
generate(refs_skeleton) do |id, body|
|
24
|
+
references[id] = body
|
25
|
+
end
|
26
|
+
|
27
|
+
{
|
28
|
+
"data" => data,
|
29
|
+
"references" => references,
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
def generate(skeleton)
|
34
|
+
skeleton.each do |id, referred|
|
35
|
+
yield id, ({
|
36
|
+
ViewModel::ID_ATTRIBUTE => id,
|
37
|
+
:children => referred.map do |referred_id|
|
38
|
+
{ ViewModel::REFERENCE_ATTRIBUTE => referred_id }
|
39
|
+
end
|
40
|
+
})
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def retained_ids(data_skeleton, refs_skeleton)
|
45
|
+
serialization = mock_serialization(data_skeleton, refs_skeleton)
|
46
|
+
ViewModel::GarbageCollection.garbage_collect_references!(serialization)
|
47
|
+
Set.new(
|
48
|
+
(serialization['data'].map { |x| x[ViewModel::ID_ATTRIBUTE] }) +
|
49
|
+
(serialization['references'].keys),
|
50
|
+
)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'keeps all roots' do
|
54
|
+
assert_equal(
|
55
|
+
Set.new([:a, :b, :c]),
|
56
|
+
retained_ids({ a: [], b: [], c: [] }, {})
|
57
|
+
)
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'keeps a list' do
|
61
|
+
assert_equal(
|
62
|
+
Set.new([:a, :b, :c, :d]),
|
63
|
+
retained_ids({ a: [:b], }, { b: [:c], c: [:d], d: [] }),
|
64
|
+
)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'keeps a child with a removed reference' do
|
68
|
+
assert_equal(
|
69
|
+
Set.new([:a, :z]),
|
70
|
+
retained_ids({ a: [:z], }, { b: [:z], z: [] }),
|
71
|
+
)
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'prunes a list at the head' do
|
75
|
+
assert_equal(
|
76
|
+
Set.new([:a]),
|
77
|
+
retained_ids({ a: [], }, { b: [:c], c: [:d], d: [] }),
|
78
|
+
)
|
79
|
+
end
|
80
|
+
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.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- iKnow Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-01-
|
11
|
+
date: 2021-01-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -414,6 +414,7 @@ files:
|
|
414
414
|
- lib/view_model/deserialize_context.rb
|
415
415
|
- lib/view_model/error.rb
|
416
416
|
- lib/view_model/error_view.rb
|
417
|
+
- lib/view_model/garbage_collection.rb
|
417
418
|
- lib/view_model/migratable_view.rb
|
418
419
|
- lib/view_model/migration.rb
|
419
420
|
- lib/view_model/migration/no_path_error.rb
|
@@ -467,6 +468,7 @@ files:
|
|
467
468
|
- test/unit/view_model/callbacks_test.rb
|
468
469
|
- test/unit/view_model/controller_test.rb
|
469
470
|
- test/unit/view_model/deserialization_error/unique_violation_test.rb
|
471
|
+
- test/unit/view_model/garbage_collection_test.rb
|
470
472
|
- test/unit/view_model/record_test.rb
|
471
473
|
- test/unit/view_model/registry_test.rb
|
472
474
|
- test/unit/view_model/traversal_context_test.rb
|
@@ -527,6 +529,7 @@ test_files:
|
|
527
529
|
- test/unit/view_model/callbacks_test.rb
|
528
530
|
- test/unit/view_model/controller_test.rb
|
529
531
|
- test/unit/view_model/deserialization_error/unique_violation_test.rb
|
532
|
+
- test/unit/view_model/garbage_collection_test.rb
|
530
533
|
- test/unit/view_model/record_test.rb
|
531
534
|
- test/unit/view_model/registry_test.rb
|
532
535
|
- test/unit/view_model/traversal_context_test.rb
|