iknow_view_models 3.1.6 → 3.2.2
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 +13 -12
- data/lib/view_model/active_record/association_data.rb +3 -2
- 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 +2 -2
- 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 +1 -1
- 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 +92 -97
- data/test/unit/view_model/traversal_context_test.rb +4 -5
- data/test/unit/view_model_test.rb +18 -16
- metadata +36 -12
- data/.travis.yml +0 -31
- data/appveyor.yml +0 -22
- data/gemfiles/rails_6_0_beta.gemfile +0 -9
@@ -1,14 +1,16 @@
|
|
1
|
-
|
2
|
-
require "minitest/unit"
|
3
|
-
require "minitest/hooks"
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
|
-
|
6
|
-
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'minitest/unit'
|
5
|
+
require 'minitest/hooks'
|
6
|
+
|
7
|
+
require_relative '../../../helpers/arvm_test_models'
|
8
|
+
require_relative '../../../helpers/viewmodel_spec_helpers'
|
7
9
|
|
8
10
|
# MiniTest::Spec.register_spec_type(/./, Minitest::HooksSpec)
|
9
11
|
|
10
|
-
require
|
11
|
-
require
|
12
|
+
require 'view_model'
|
13
|
+
require 'view_model/active_record'
|
12
14
|
|
13
15
|
class ViewModel::ActiveRecord
|
14
16
|
class ClonerTest < ActiveSupport::TestCase
|
@@ -18,7 +20,7 @@ class ViewModel::ActiveRecord
|
|
18
20
|
let(:viewmodel) { create_viewmodel! }
|
19
21
|
let(:model) { viewmodel.model }
|
20
22
|
|
21
|
-
describe
|
23
|
+
describe 'with single model' do
|
22
24
|
include ViewModelSpecHelpers::Single
|
23
25
|
|
24
26
|
def model_attributes
|
@@ -26,15 +28,15 @@ class ViewModel::ActiveRecord
|
|
26
28
|
end
|
27
29
|
|
28
30
|
def new_model
|
29
|
-
model_class.new(name:
|
31
|
+
model_class.new(name: 'a', nonview: 'b')
|
30
32
|
end
|
31
33
|
|
32
|
-
it
|
34
|
+
it 'persists the test setup' do
|
33
35
|
assert(viewmodel.model.persisted?)
|
34
36
|
refute(viewmodel.model.new_record?)
|
35
37
|
end
|
36
38
|
|
37
|
-
it
|
39
|
+
it 'can clone the model' do
|
38
40
|
clone_model = Cloner.new.clone(viewmodel)
|
39
41
|
assert(clone_model.new_record?)
|
40
42
|
assert_nil(clone_model.id)
|
@@ -45,75 +47,75 @@ class ViewModel::ActiveRecord
|
|
45
47
|
end
|
46
48
|
|
47
49
|
class IgnoreParentCloner < Cloner
|
48
|
-
def visit_model_view(
|
50
|
+
def visit_model_view(_node, _model)
|
49
51
|
ignore!
|
50
52
|
end
|
51
53
|
end
|
52
54
|
|
53
|
-
it
|
55
|
+
it 'can ignore a model' do
|
54
56
|
clone_model = IgnoreParentCloner.new.clone(viewmodel)
|
55
57
|
assert_nil(clone_model)
|
56
58
|
end
|
57
59
|
|
58
60
|
class IgnoreAllCloner < Cloner
|
59
|
-
def pre_visit(
|
61
|
+
def pre_visit(_node, _model)
|
60
62
|
ignore!
|
61
63
|
end
|
62
64
|
end
|
63
65
|
|
64
|
-
it
|
66
|
+
it 'can ignore a model in pre-visit' do
|
65
67
|
clone_model = IgnoreAllCloner.new.clone(viewmodel)
|
66
68
|
assert_nil(clone_model)
|
67
69
|
end
|
68
70
|
|
69
71
|
class AlterAttributeCloner < Cloner
|
70
|
-
def visit_model_view(
|
71
|
-
model.name =
|
72
|
+
def visit_model_view(_node, model)
|
73
|
+
model.name = 'changed'
|
72
74
|
end
|
73
75
|
end
|
74
76
|
|
75
|
-
it
|
77
|
+
it 'can alter a model attribute' do
|
76
78
|
clone_model = AlterAttributeCloner.new.clone(viewmodel)
|
77
79
|
assert(clone_model.new_record?)
|
78
80
|
assert_nil(clone_model.id)
|
79
|
-
assert_equal(
|
80
|
-
refute_equal(
|
81
|
+
assert_equal('changed', clone_model.name)
|
82
|
+
refute_equal('changed', model.name)
|
81
83
|
assert_equal(model.nonview, clone_model.nonview)
|
82
84
|
clone_model.save!
|
83
85
|
refute_equal(model, clone_model)
|
84
86
|
end
|
85
87
|
|
86
88
|
class PostAlterAttributeCloner < Cloner
|
87
|
-
def end_visit_model_view(
|
88
|
-
model.name =
|
89
|
+
def end_visit_model_view(_node, model)
|
90
|
+
model.name = 'changed'
|
89
91
|
end
|
90
92
|
end
|
91
93
|
|
92
|
-
it
|
94
|
+
it 'can alter a model attribute post-visit' do
|
93
95
|
clone_model = PostAlterAttributeCloner.new.clone(viewmodel)
|
94
96
|
assert(clone_model.new_record?)
|
95
97
|
assert_nil(clone_model.id)
|
96
|
-
assert_equal(
|
97
|
-
refute_equal(
|
98
|
+
assert_equal('changed', clone_model.name)
|
99
|
+
refute_equal('changed', model.name)
|
98
100
|
assert_equal(model.nonview, clone_model.nonview)
|
99
101
|
clone_model.save!
|
100
102
|
refute_equal(model, clone_model)
|
101
103
|
end
|
102
104
|
end
|
103
105
|
|
104
|
-
describe
|
106
|
+
describe 'with a child' do
|
105
107
|
def new_child_model
|
106
|
-
child_model_class.new(name:
|
108
|
+
child_model_class.new(name: 'b')
|
107
109
|
end
|
108
110
|
|
109
111
|
def new_model
|
110
|
-
model_class.new(name:
|
112
|
+
model_class.new(name: 'a', child: new_child_model)
|
111
113
|
end
|
112
114
|
|
113
115
|
module BehavesLikeConstructingAChild
|
114
116
|
extend ActiveSupport::Concern
|
115
117
|
included do
|
116
|
-
it
|
118
|
+
it 'persists the test setup' do
|
117
119
|
assert(viewmodel.model.persisted?)
|
118
120
|
refute(viewmodel.model.new_record?)
|
119
121
|
assert(viewmodel.model.child.persisted?)
|
@@ -123,7 +125,7 @@ class ViewModel::ActiveRecord
|
|
123
125
|
end
|
124
126
|
|
125
127
|
class IgnoreChildAssociationCloner < Cloner
|
126
|
-
def visit_model_view(
|
128
|
+
def visit_model_view(_node, _model)
|
127
129
|
ignore_association!(:child)
|
128
130
|
end
|
129
131
|
end
|
@@ -131,7 +133,7 @@ class ViewModel::ActiveRecord
|
|
131
133
|
module BehavesLikeCloningAChild
|
132
134
|
extend ActiveSupport::Concern
|
133
135
|
included do
|
134
|
-
it
|
136
|
+
it 'can clone the model and child' do
|
135
137
|
clone_model = Cloner.new.clone(viewmodel)
|
136
138
|
|
137
139
|
assert(clone_model.new_record?)
|
@@ -148,7 +150,7 @@ class ViewModel::ActiveRecord
|
|
148
150
|
refute_equal(model.child, clone_model.child)
|
149
151
|
end
|
150
152
|
|
151
|
-
it
|
153
|
+
it 'can ignore the child association' do
|
152
154
|
clone_model = IgnoreChildAssociationCloner.new.clone(viewmodel)
|
153
155
|
|
154
156
|
assert(clone_model.new_record?)
|
@@ -160,66 +162,67 @@ class ViewModel::ActiveRecord
|
|
160
162
|
end
|
161
163
|
end
|
162
164
|
|
163
|
-
describe
|
165
|
+
describe 'as belongs_to' do
|
164
166
|
include ViewModelSpecHelpers::ParentAndBelongsToChild
|
165
167
|
include BehavesLikeConstructingAChild
|
166
168
|
include BehavesLikeCloningAChild
|
167
169
|
end
|
168
170
|
|
169
|
-
describe
|
171
|
+
describe 'as has_one' do
|
170
172
|
include ViewModelSpecHelpers::ParentAndHasOneChild
|
171
173
|
include BehavesLikeConstructingAChild
|
172
174
|
include BehavesLikeCloningAChild
|
173
175
|
end
|
174
176
|
|
175
|
-
describe
|
177
|
+
describe 'as belongs_to shared child' do
|
176
178
|
include ViewModelSpecHelpers::ParentAndSharedBelongsToChild
|
177
179
|
include BehavesLikeConstructingAChild
|
178
|
-
it "can clone the model but not the child" do
|
179
|
-
clone_model = Cloner.new.clone(viewmodel)
|
180
180
|
|
181
|
-
|
182
|
-
|
183
|
-
assert_equal(model.name, clone_model.name)
|
181
|
+
it 'can clone the model but not the child' do
|
182
|
+
clone_model = Cloner.new.clone(viewmodel)
|
184
183
|
|
185
|
-
|
186
|
-
|
187
|
-
|
184
|
+
assert(clone_model.new_record?)
|
185
|
+
assert_nil(clone_model.id)
|
186
|
+
assert_equal(model.name, clone_model.name)
|
188
187
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
188
|
+
clone_child = clone_model.child
|
189
|
+
refute(clone_child.new_record?)
|
190
|
+
assert_equal(model.child, clone_child)
|
191
|
+
|
192
|
+
clone_model.save!
|
193
|
+
refute_equal(model, clone_model)
|
194
|
+
assert_equal(model.child, clone_model.child)
|
195
|
+
end
|
193
196
|
end
|
194
197
|
end
|
195
198
|
|
196
199
|
class IgnoreChildrenAssociationCloner < Cloner
|
197
|
-
def visit_model_view(
|
200
|
+
def visit_model_view(_node, _model)
|
198
201
|
ignore_association!(:children)
|
199
202
|
end
|
200
203
|
end
|
201
204
|
|
202
|
-
describe
|
205
|
+
describe 'with has_many children' do
|
203
206
|
include ViewModelSpecHelpers::ParentAndHasManyChildren
|
204
207
|
def new_child_models
|
205
|
-
[
|
208
|
+
['b', 'c'].map { |n| child_model_class.new(name: n) }
|
206
209
|
end
|
207
210
|
|
208
211
|
def new_model
|
209
|
-
model_class.new(name:
|
212
|
+
model_class.new(name: 'a', children: new_child_models)
|
210
213
|
end
|
211
214
|
|
212
|
-
it
|
215
|
+
it 'persists the test setup' do
|
213
216
|
assert(viewmodel.model.persisted?)
|
214
217
|
refute(viewmodel.model.new_record?)
|
215
218
|
assert_equal(2, viewmodel.model.children.size)
|
216
|
-
viewmodel.model.children.each do |
|
219
|
+
viewmodel.model.children.each do |child|
|
217
220
|
assert(child.persisted?)
|
218
221
|
refute(child.new_record?)
|
219
222
|
end
|
220
223
|
end
|
221
224
|
|
222
|
-
it
|
225
|
+
it 'can clone the model' do
|
223
226
|
clone_model = Cloner.new.clone(viewmodel)
|
224
227
|
|
225
228
|
assert(clone_model.new_record?)
|
@@ -244,9 +247,10 @@ class ViewModel::ActiveRecord
|
|
244
247
|
class IgnoreFirstChildCloner < Cloner
|
245
248
|
def initialize
|
246
249
|
@ignored_first = false
|
250
|
+
super
|
247
251
|
end
|
248
252
|
|
249
|
-
def visit_child_view(
|
253
|
+
def visit_child_view(_node, _model)
|
250
254
|
unless @ignored_first
|
251
255
|
@ignored_first = true
|
252
256
|
ignore!
|
@@ -254,7 +258,7 @@ class ViewModel::ActiveRecord
|
|
254
258
|
end
|
255
259
|
end
|
256
260
|
|
257
|
-
it
|
261
|
+
it 'can ignore subset of children' do
|
258
262
|
clone_model = IgnoreFirstChildCloner.new.clone(viewmodel)
|
259
263
|
|
260
264
|
assert(clone_model.new_record?)
|
@@ -265,7 +269,7 @@ class ViewModel::ActiveRecord
|
|
265
269
|
assert_equal(model.children[1].name, clone_model.children[0].name)
|
266
270
|
end
|
267
271
|
|
268
|
-
it
|
272
|
+
it 'can ignore the children association' do
|
269
273
|
clone_model = IgnoreChildrenAssociationCloner.new.clone(viewmodel)
|
270
274
|
|
271
275
|
assert(clone_model.new_record?)
|
@@ -276,19 +280,19 @@ class ViewModel::ActiveRecord
|
|
276
280
|
end
|
277
281
|
end
|
278
282
|
|
279
|
-
describe
|
283
|
+
describe 'with has_many_through shared children' do
|
280
284
|
include ViewModelSpecHelpers::ParentAndHasManyThroughChildren
|
281
285
|
def new_model_children
|
282
|
-
[
|
286
|
+
['b', 'c'].map.with_index do |n, i|
|
283
287
|
join_model_class.new(child: child_model_class.new(name: n), position: i)
|
284
288
|
end
|
285
289
|
end
|
286
290
|
|
287
291
|
def new_model
|
288
|
-
model_class.new(
|
292
|
+
model_class.new(name: 'a', model_children: new_model_children)
|
289
293
|
end
|
290
294
|
|
291
|
-
it
|
295
|
+
it 'persists the test setup' do
|
292
296
|
assert(viewmodel.model.persisted?)
|
293
297
|
refute(viewmodel.model.new_record?)
|
294
298
|
assert_equal(2, viewmodel.model.model_children.size)
|
@@ -301,7 +305,7 @@ class ViewModel::ActiveRecord
|
|
301
305
|
end
|
302
306
|
end
|
303
307
|
|
304
|
-
it
|
308
|
+
it 'can clone the model and join model but not the child' do
|
305
309
|
clone_model = Cloner.new.clone(viewmodel)
|
306
310
|
|
307
311
|
assert(clone_model.new_record?)
|
@@ -325,7 +329,7 @@ class ViewModel::ActiveRecord
|
|
325
329
|
end
|
326
330
|
end
|
327
331
|
|
328
|
-
it
|
332
|
+
it 'can ignore the children association' do
|
329
333
|
clone_model = IgnoreChildrenAssociationCloner.new.clone(viewmodel)
|
330
334
|
|
331
335
|
assert(clone_model.new_record?)
|
@@ -1,14 +1,14 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require 'minitest/autorun'
|
4
4
|
require 'minitest/unit'
|
5
5
|
require 'minitest/hooks'
|
6
6
|
|
7
|
-
require
|
8
|
-
require
|
7
|
+
require 'view_model'
|
8
|
+
require 'view_model/active_record'
|
9
9
|
|
10
|
-
require_relative
|
11
|
-
require_relative
|
10
|
+
require_relative '../../../helpers/controller_test_helpers'
|
11
|
+
require_relative '../../../helpers/callback_tracer'
|
12
12
|
|
13
13
|
class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
14
14
|
include ARVMTestUtilities
|
@@ -88,7 +88,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
88
88
|
super
|
89
89
|
@parent = Parent.create(name: 'p',
|
90
90
|
children: [Child.new(name: 'c1', position: 1.0),
|
91
|
-
Child.new(name: 'c2', position: 2.0)],
|
91
|
+
Child.new(name: 'c2', position: 2.0),],
|
92
92
|
label: Label.new,
|
93
93
|
target: Target.new)
|
94
94
|
|
@@ -98,7 +98,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
98
98
|
end
|
99
99
|
|
100
100
|
def test_show
|
101
|
-
parentcontroller = ParentController.new(id: @parent.id)
|
101
|
+
parentcontroller = ParentController.new(params: { id: @parent.id })
|
102
102
|
parentcontroller.invoke(:show)
|
103
103
|
|
104
104
|
assert_equal({ 'data' => @parent_view.to_hash },
|
@@ -109,8 +109,41 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
109
109
|
assert_all_hooks_nested_inside_parent_hook(parentcontroller.hook_trace)
|
110
110
|
end
|
111
111
|
|
112
|
+
def test_migrated_show
|
113
|
+
parentcontroller = ParentController.new(
|
114
|
+
params: { id: @parent.id },
|
115
|
+
headers: { 'X-ViewModel-Versions' => { ParentView.view_name => 1 }.to_json })
|
116
|
+
|
117
|
+
parentcontroller.invoke(:show)
|
118
|
+
|
119
|
+
expected_view = @parent_view.to_hash
|
120
|
+
.except('name')
|
121
|
+
.merge('old_name' => @parent.name,
|
122
|
+
ViewModel::VERSION_ATTRIBUTE => 1,
|
123
|
+
ViewModel::MIGRATED_ATTRIBUTE => true)
|
124
|
+
|
125
|
+
assert_equal({ 'data' => expected_view },
|
126
|
+
parentcontroller.hash_response)
|
127
|
+
|
128
|
+
assert_equal(200, parentcontroller.status)
|
129
|
+
|
130
|
+
assert_all_hooks_nested_inside_parent_hook(parentcontroller.hook_trace)
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_invalid_migration_header
|
134
|
+
parentcontroller = ParentController.new(
|
135
|
+
params: { id: @parent.id },
|
136
|
+
headers: { 'X-ViewModel-Versions' => 'not a json' })
|
137
|
+
|
138
|
+
parentcontroller.invoke(:show)
|
139
|
+
assert_equal(400, parentcontroller.status)
|
140
|
+
assert_match(/Invalid JSON/i,
|
141
|
+
parentcontroller.hash_response['error']['detail'],
|
142
|
+
'json error propagated')
|
143
|
+
end
|
144
|
+
|
112
145
|
def test_index
|
113
|
-
p2 = Parent.create(name:
|
146
|
+
p2 = Parent.create(name: 'p2')
|
114
147
|
p2_view = ParentView.new(p2)
|
115
148
|
|
116
149
|
parentcontroller = ParentController.new
|
@@ -119,7 +152,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
119
152
|
assert_equal(200, parentcontroller.status)
|
120
153
|
|
121
154
|
assert_equal(parentcontroller.hash_response,
|
122
|
-
{
|
155
|
+
{ 'data' => [@parent_view.to_hash, p2_view.to_hash] })
|
123
156
|
|
124
157
|
assert_all_hooks_nested_inside_parent_hook(parentcontroller.hook_trace)
|
125
158
|
end
|
@@ -131,10 +164,10 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
131
164
|
'label' => { '_type' => 'Label', 'text' => 'l' },
|
132
165
|
'target' => { '_type' => 'Target', 'text' => 't' },
|
133
166
|
'children' => [{ '_type' => 'Child', 'name' => 'c1' },
|
134
|
-
{ '_type' => 'Child', 'name' => 'c2' }]
|
167
|
+
{ '_type' => 'Child', 'name' => 'c2' },],
|
135
168
|
}
|
136
169
|
|
137
|
-
parentcontroller = ParentController.new(data: data)
|
170
|
+
parentcontroller = ParentController.new(params: { data: data })
|
138
171
|
parentcontroller.invoke(:create)
|
139
172
|
|
140
173
|
assert_equal(200, parentcontroller.status)
|
@@ -148,15 +181,31 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
148
181
|
assert_all_hooks_nested_inside_parent_hook(parentcontroller.hook_trace)
|
149
182
|
end
|
150
183
|
|
184
|
+
def test_migrated_create
|
185
|
+
data = {
|
186
|
+
'_type' => 'Parent',
|
187
|
+
'_version' => 1,
|
188
|
+
'old_name' => 'p2',
|
189
|
+
}
|
190
|
+
|
191
|
+
parentcontroller = ParentController.new(params: { data: data, versions: { ParentView.view_name => 1 } })
|
192
|
+
parentcontroller.invoke(:create)
|
193
|
+
|
194
|
+
assert_equal(200, parentcontroller.status)
|
195
|
+
|
196
|
+
p2 = Parent.where(name: 'p2').first
|
197
|
+
assert(p2.present?, 'p2 created')
|
198
|
+
end
|
199
|
+
|
151
200
|
def test_create_empty
|
152
|
-
parentcontroller = ParentController.new(data: [])
|
201
|
+
parentcontroller = ParentController.new(params: { data: [] })
|
153
202
|
parentcontroller.invoke(:create)
|
154
203
|
|
155
204
|
assert_equal(400, parentcontroller.status)
|
156
205
|
end
|
157
206
|
|
158
207
|
def test_create_invalid
|
159
|
-
parentcontroller = ParentController.new(data: 42)
|
208
|
+
parentcontroller = ParentController.new(params: { data: 42 })
|
160
209
|
parentcontroller.invoke(:create)
|
161
210
|
|
162
211
|
assert_equal(400, parentcontroller.status)
|
@@ -167,7 +216,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
167
216
|
'_type' => 'Parent',
|
168
217
|
'name' => 'new' }
|
169
218
|
|
170
|
-
parentcontroller = ParentController.new(id: @parent.id, data: data)
|
219
|
+
parentcontroller = ParentController.new(params: { id: @parent.id, data: data })
|
171
220
|
parentcontroller.invoke(:create)
|
172
221
|
|
173
222
|
assert_equal(200, parentcontroller.status)
|
@@ -182,7 +231,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
182
231
|
end
|
183
232
|
|
184
233
|
def test_destroy
|
185
|
-
parentcontroller = ParentController.new(id: @parent.id)
|
234
|
+
parentcontroller = ParentController.new(params: { id: @parent.id })
|
186
235
|
parentcontroller.invoke(:destroy)
|
187
236
|
|
188
237
|
assert_equal(200, parentcontroller.status)
|
@@ -196,7 +245,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
196
245
|
end
|
197
246
|
|
198
247
|
def test_show_missing
|
199
|
-
parentcontroller = ParentController.new(id: 9999)
|
248
|
+
parentcontroller = ParentController.new(params: { id: 9999 })
|
200
249
|
parentcontroller.invoke(:show)
|
201
250
|
|
202
251
|
assert_equal(404, parentcontroller.status)
|
@@ -206,10 +255,10 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
206
255
|
'status' => 404,
|
207
256
|
'detail' => "Couldn't find Parent(s) with id(s)=[9999]",
|
208
257
|
'title' => nil,
|
209
|
-
'code'
|
210
|
-
'meta' => { 'nodes' => [{ '_type' =>
|
258
|
+
'code' => 'DeserializationError.NotFound',
|
259
|
+
'meta' => { 'nodes' => [{ '_type' => 'Parent', 'id' => 9999 }] },
|
211
260
|
'exception' => nil,
|
212
|
-
'causes' => nil }},
|
261
|
+
'causes' => nil } },
|
213
262
|
parentcontroller.hash_response)
|
214
263
|
end
|
215
264
|
|
@@ -218,7 +267,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
218
267
|
'children' => [{ '_type' => 'Child',
|
219
268
|
'age' => 42 }] }
|
220
269
|
|
221
|
-
parentcontroller = ParentController.new(data: data)
|
270
|
+
parentcontroller = ParentController.new(params: { data: data })
|
222
271
|
parentcontroller.invoke(:create)
|
223
272
|
|
224
273
|
assert_equal({ 'error' => {
|
@@ -227,13 +276,13 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
227
276
|
'status' => 400,
|
228
277
|
'detail' => 'Validation failed: \'age\' must be less than 42',
|
229
278
|
'title' => nil,
|
230
|
-
'code'
|
231
|
-
'meta' => { 'nodes' => [{ '_type' =>
|
279
|
+
'code' => 'DeserializationError.Validation',
|
280
|
+
'meta' => { 'nodes' => [{ '_type' => 'Child', 'id' => nil }],
|
232
281
|
'attribute' => 'age',
|
233
282
|
'message' => 'must be less than 42',
|
234
|
-
'details' => { 'error' => 'less_than', 'value' => 42, 'count' => 42 }},
|
283
|
+
'details' => { 'error' => 'less_than', 'value' => 42, 'count' => 42 } },
|
235
284
|
'exception' => nil,
|
236
|
-
'causes' => nil }},
|
285
|
+
'causes' => nil } },
|
237
286
|
parentcontroller.hash_response)
|
238
287
|
end
|
239
288
|
|
@@ -241,17 +290,17 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
241
290
|
data = { '_type' => 'Parent',
|
242
291
|
'children' => [{ '_type' => 'Child',
|
243
292
|
'age' => 1 }] }
|
244
|
-
parentcontroller = ParentController.new(data: data)
|
293
|
+
parentcontroller = ParentController.new(params: { data: data })
|
245
294
|
parentcontroller.invoke(:create)
|
246
295
|
|
247
296
|
assert_equal(400, parentcontroller.status)
|
248
|
-
assert_match(
|
249
|
-
parentcontroller.hash_response[
|
250
|
-
|
297
|
+
assert_match(/check constraint/i,
|
298
|
+
parentcontroller.hash_response['error']['detail'],
|
299
|
+
'Database error propagated')
|
251
300
|
end
|
252
301
|
|
253
302
|
def test_destroy_missing
|
254
|
-
parentcontroller = ParentController.new(id: 9999)
|
303
|
+
parentcontroller = ParentController.new(params: { id: 9999 })
|
255
304
|
parentcontroller.invoke(:destroy)
|
256
305
|
|
257
306
|
assert_equal({ 'error' => {
|
@@ -260,8 +309,8 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
260
309
|
'status' => 404,
|
261
310
|
'detail' => "Couldn't find Parent(s) with id(s)=[9999]",
|
262
311
|
'title' => nil,
|
263
|
-
'code'
|
264
|
-
'meta' => {
|
312
|
+
'code' => 'DeserializationError.NotFound',
|
313
|
+
'meta' => { 'nodes' => [{ '_type' => 'Parent', 'id' => 9999 }] },
|
265
314
|
'exception' => nil,
|
266
315
|
'causes' => nil } },
|
267
316
|
parentcontroller.hash_response)
|
@@ -273,7 +322,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
273
322
|
def test_nested_collection_index_associated
|
274
323
|
_distractor = Parent.create(name: 'p2', children: [Child.new(name: 'c3', position: 1)])
|
275
324
|
|
276
|
-
childcontroller = ChildController.new(parent_id: @parent.id)
|
325
|
+
childcontroller = ChildController.new(params: { parent_id: @parent.id })
|
277
326
|
childcontroller.invoke(:index_associated)
|
278
327
|
|
279
328
|
assert_equal(200, childcontroller.status)
|
@@ -300,7 +349,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
300
349
|
|
301
350
|
def test_nested_collection_append_one
|
302
351
|
data = { '_type' => 'Child', 'name' => 'c3' }
|
303
|
-
childcontroller = ChildController.new(parent_id: @parent.id, data: data)
|
352
|
+
childcontroller = ChildController.new(params: { parent_id: @parent.id, data: data })
|
304
353
|
|
305
354
|
childcontroller.invoke(:append)
|
306
355
|
|
@@ -308,7 +357,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
308
357
|
|
309
358
|
@parent.reload
|
310
359
|
|
311
|
-
assert_equal(%w
|
360
|
+
assert_equal(%w[c1 c2 c3], @parent.children.order(:position).pluck(:name))
|
312
361
|
assert_equal({ 'data' => ChildView.new(@parent.children.last).to_hash },
|
313
362
|
childcontroller.hash_response)
|
314
363
|
|
@@ -317,17 +366,17 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
317
366
|
|
318
367
|
def test_nested_collection_append_many
|
319
368
|
data = [{ '_type' => 'Child', 'name' => 'c3' },
|
320
|
-
{ '_type' => 'Child', 'name' => 'c4' }]
|
369
|
+
{ '_type' => 'Child', 'name' => 'c4' },]
|
321
370
|
|
322
|
-
childcontroller = ChildController.new(parent_id: @parent.id, data: data)
|
371
|
+
childcontroller = ChildController.new(params: { parent_id: @parent.id, data: data })
|
323
372
|
childcontroller.invoke(:append)
|
324
373
|
|
325
374
|
assert_equal(200, childcontroller.status, childcontroller.hash_response)
|
326
375
|
|
327
376
|
@parent.reload
|
328
377
|
|
329
|
-
assert_equal(%w
|
330
|
-
new_children_hashes = @parent.children.last(2).map{ |c| ChildView.new(c).to_hash }
|
378
|
+
assert_equal(%w[c1 c2 c3 c4], @parent.children.order(:position).pluck(:name))
|
379
|
+
new_children_hashes = @parent.children.last(2).map { |c| ChildView.new(c).to_hash }
|
331
380
|
assert_equal({ 'data' => new_children_hashes },
|
332
381
|
childcontroller.hash_response)
|
333
382
|
|
@@ -339,25 +388,25 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
339
388
|
# Parent.children
|
340
389
|
old_children = @parent.children
|
341
390
|
|
342
|
-
data = [{'_type' => 'Child', 'name' => 'newc1'},
|
343
|
-
{'_type' => 'Child', 'name' => 'newc2'}]
|
391
|
+
data = [{ '_type' => 'Child', 'name' => 'newc1' },
|
392
|
+
{ '_type' => 'Child', 'name' => 'newc2' },]
|
344
393
|
|
345
|
-
childcontroller = ChildController.new(parent_id: @parent.id, data: data)
|
394
|
+
childcontroller = ChildController.new(params: { parent_id: @parent.id, data: data })
|
346
395
|
childcontroller.invoke(:replace)
|
347
396
|
|
348
397
|
assert_equal(200, childcontroller.status, childcontroller.hash_response)
|
349
398
|
|
350
399
|
@parent.reload
|
351
400
|
|
352
|
-
assert_equal(%w
|
401
|
+
assert_equal(%w[newc1 newc2], @parent.children.order(:position).pluck(:name))
|
353
402
|
assert_predicate(Child.where(id: old_children.map(&:id)), :empty?)
|
354
403
|
|
355
404
|
assert_all_hooks_nested_inside_parent_hook(childcontroller.hook_trace)
|
356
405
|
end
|
357
406
|
|
358
407
|
def test_nested_collection_replace_bad_data
|
359
|
-
data = [{
|
360
|
-
childcontroller = ChildController.new(parent_id: @parent.id, data: data)
|
408
|
+
data = [{ 'name' => 'nc' }]
|
409
|
+
childcontroller = ChildController.new(params: { parent_id: @parent.id, data: data })
|
361
410
|
|
362
411
|
childcontroller.invoke(:replace)
|
363
412
|
|
@@ -368,14 +417,14 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
368
417
|
|
369
418
|
def test_nested_collection_disassociate_one
|
370
419
|
old_child = @parent.children.first
|
371
|
-
childcontroller = ChildController.new(parent_id: @parent.id, id: old_child.id)
|
420
|
+
childcontroller = ChildController.new(params: { parent_id: @parent.id, id: old_child.id })
|
372
421
|
childcontroller.invoke(:disassociate)
|
373
422
|
|
374
423
|
assert_equal(200, childcontroller.status, childcontroller.hash_response)
|
375
424
|
|
376
425
|
@parent.reload
|
377
426
|
|
378
|
-
assert_equal(%w
|
427
|
+
assert_equal(%w[c2], @parent.children.order(:position).pluck(:name))
|
379
428
|
assert_predicate(Child.where(id: old_child.id), :empty?)
|
380
429
|
|
381
430
|
assert_all_hooks_nested_inside_parent_hook(childcontroller.hook_trace)
|
@@ -384,7 +433,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
384
433
|
def test_nested_collection_disassociate_many
|
385
434
|
old_children = @parent.children
|
386
435
|
|
387
|
-
childcontroller = ChildController.new(parent_id: @parent.id)
|
436
|
+
childcontroller = ChildController.new(params: { parent_id: @parent.id })
|
388
437
|
childcontroller.invoke(:disassociate_all)
|
389
438
|
|
390
439
|
assert_equal(200, childcontroller.status, childcontroller.hash_response)
|
@@ -400,14 +449,14 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
400
449
|
# direct methods on nested controller
|
401
450
|
def test_nested_collection_destroy
|
402
451
|
old_child = @parent.children.first
|
403
|
-
childcontroller = ChildController.new(id: old_child.id)
|
452
|
+
childcontroller = ChildController.new(params: { id: old_child.id })
|
404
453
|
childcontroller.invoke(:destroy)
|
405
454
|
|
406
455
|
assert_equal(200, childcontroller.status, childcontroller.hash_response)
|
407
456
|
|
408
457
|
@parent.reload
|
409
458
|
|
410
|
-
assert_equal(%w
|
459
|
+
assert_equal(%w[c2], @parent.children.order(:position).pluck(:name))
|
411
460
|
assert_predicate(Child.where(id: old_child.id), :empty?)
|
412
461
|
end
|
413
462
|
|
@@ -418,7 +467,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
418
467
|
'_type' => 'Child',
|
419
468
|
'name' => 'new_name' }
|
420
469
|
|
421
|
-
childcontroller = ChildController.new(data: data)
|
470
|
+
childcontroller = ChildController.new(params: { data: data })
|
422
471
|
childcontroller.invoke(:create)
|
423
472
|
|
424
473
|
assert_equal(200, childcontroller.status, childcontroller.hash_response)
|
@@ -430,26 +479,25 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
430
479
|
childcontroller.hash_response)
|
431
480
|
end
|
432
481
|
|
433
|
-
|
482
|
+
def test_nested_collection_show
|
434
483
|
old_child = @parent.children.first
|
435
484
|
|
436
|
-
childcontroller = ChildController.new(id: old_child.id)
|
485
|
+
childcontroller = ChildController.new(params: { id: old_child.id })
|
437
486
|
childcontroller.invoke(:show)
|
438
487
|
|
439
488
|
assert_equal({ 'data' => ChildView.new(old_child).to_hash },
|
440
489
|
childcontroller.hash_response)
|
441
490
|
|
442
491
|
assert_equal(200, childcontroller.status)
|
443
|
-
|
444
|
-
|
492
|
+
end
|
445
493
|
|
446
494
|
## Single association
|
447
495
|
|
448
496
|
def test_nested_singular_replace_from_parent
|
449
497
|
old_label = @parent.label
|
450
498
|
|
451
|
-
data = {'_type' => 'Label', 'text' => 'new label'}
|
452
|
-
labelcontroller = LabelController.new(parent_id: @parent.id, data: data)
|
499
|
+
data = { '_type' => 'Label', 'text' => 'new label' }
|
500
|
+
labelcontroller = LabelController.new(params: { parent_id: @parent.id, data: data })
|
453
501
|
labelcontroller.invoke(:create_associated)
|
454
502
|
|
455
503
|
assert_equal(200, labelcontroller.status, labelcontroller.hash_response)
|
@@ -471,7 +519,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
471
519
|
def test_nested_singular_show_from_parent
|
472
520
|
old_label = @parent.label
|
473
521
|
|
474
|
-
labelcontroller = LabelController.new(parent_id: @parent.id)
|
522
|
+
labelcontroller = LabelController.new(params: { parent_id: @parent.id })
|
475
523
|
labelcontroller.invoke(:show_associated)
|
476
524
|
|
477
525
|
assert_equal(200, labelcontroller.status, labelcontroller.hash_response)
|
@@ -485,7 +533,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
485
533
|
def test_nested_singular_destroy_from_parent
|
486
534
|
old_label = @parent.label
|
487
535
|
|
488
|
-
labelcontroller = LabelController.new(parent_id: @parent.id)
|
536
|
+
labelcontroller = LabelController.new(params: { parent_id: @parent.id })
|
489
537
|
labelcontroller.invoke(:destroy_associated)
|
490
538
|
|
491
539
|
@parent.reload
|
@@ -502,8 +550,8 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
502
550
|
def test_nested_singular_update_from_parent
|
503
551
|
old_label = @parent.label
|
504
552
|
|
505
|
-
data = {'_type' => 'Label', 'id' => old_label.id, 'text' => 'new label'}
|
506
|
-
labelcontroller = LabelController.new(parent_id: @parent.id, data: data)
|
553
|
+
data = { '_type' => 'Label', 'id' => old_label.id, 'text' => 'new label' }
|
554
|
+
labelcontroller = LabelController.new(params: { parent_id: @parent.id, data: data })
|
507
555
|
labelcontroller.invoke(:create_associated)
|
508
556
|
|
509
557
|
assert_equal(200, labelcontroller.status, labelcontroller.hash_response)
|
@@ -520,7 +568,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
520
568
|
def test_nested_singular_show_from_id
|
521
569
|
old_label = @parent.label
|
522
570
|
|
523
|
-
labelcontroller = LabelController.new(id: old_label.id)
|
571
|
+
labelcontroller = LabelController.new(params: { id: old_label.id })
|
524
572
|
labelcontroller.invoke(:show)
|
525
573
|
|
526
574
|
assert_equal(200, labelcontroller.status, labelcontroller.hash_response)
|
@@ -534,7 +582,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
534
582
|
# foreign key violation. Destroy target instead.
|
535
583
|
old_target = @parent.target
|
536
584
|
|
537
|
-
targetcontroller = TargetController.new(id: old_target.id)
|
585
|
+
targetcontroller = TargetController.new(params: { id: old_target.id })
|
538
586
|
targetcontroller.invoke(:destroy)
|
539
587
|
|
540
588
|
@parent.reload
|
@@ -549,8 +597,8 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
549
597
|
def test_nested_singular_update
|
550
598
|
old_label = @parent.label
|
551
599
|
|
552
|
-
data = {'_type' => 'Label', 'id' => old_label.id, 'text' => 'new label'}
|
553
|
-
labelcontroller = LabelController.new(data: data)
|
600
|
+
data = { '_type' => 'Label', 'id' => old_label.id, 'text' => 'new label' }
|
601
|
+
labelcontroller = LabelController.new(params: { data: data })
|
554
602
|
labelcontroller.invoke(:create)
|
555
603
|
|
556
604
|
assert_equal(200, labelcontroller.status, labelcontroller.hash_response)
|