iknow_view_models 3.1.6 → 3.2.2
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|