iknow_view_models 3.10.1 → 3.12.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 417eb3615156fa48cf438ead03e2ea33e323c5baa7d411b1e0fafcea5050acb1
4
- data.tar.gz: cdede3ad865389a0d006725819595aec6da1ea417e9d061452ef3198a39af3d8
3
+ metadata.gz: 07b80f46184b9f84a29e63b4f26c65b9cf7e7b7fa0a6390365e66c92cbac0325
4
+ data.tar.gz: 240963485ad8192d341ad3ce40a5d360052a69055036bf3ca64fb76d2f176c36
5
5
  SHA512:
6
- metadata.gz: ada26778b54ffb60a825d408fe40f05c8a4aa93cbac7b5519b2338b5afb4cadfda0d1eb7b359b65584f88fbb9cadea4a35a7d2ba0aad9fb8e4d8ec9d5f894e03
7
- data.tar.gz: b70d2b42d4a599c3d284dbb96c4506c8ff7b6104108ebcb7126c554fcd671eb0bad04dc4df5a1006f76af272a71c5ca46f54736bf4961821dd7f22160d46fada
6
+ metadata.gz: 0ddaba32ebd18303eba6f2e91db5ca44368c538bba771c6572afa4a3b4d7e17efd69ef6bfb274218b2f1fcf73812a8bb62704aa60065c3e45900428eff91e231
7
+ data.tar.gz: 7b482657ab857da0848f7880caf8a67a08ecbf132b3495d2117ea89642270525db95bf92fe26160ff0bc9450d3b514e94ca2ef77252f47a0ae6f04934a49efd0
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module IknowViewModels
4
- VERSION = '3.10.1'
4
+ VERSION = '3.12.0'
5
5
  end
@@ -56,9 +56,14 @@ module ViewModel::ActiveRecord::Controller
56
56
  end
57
57
 
58
58
  def destroy(serialize_context: new_serialize_context, deserialize_context: new_deserialize_context)
59
+ viewmodel_ids = parse_param(
60
+ :id, with: IknowParams::Serializer::ArrayOf.new(ViewmodelIdSerializer, allow_singleton: true))
61
+
59
62
  viewmodel_class.transaction do
60
- view = viewmodel_class.find(viewmodel_id, eager_include: false)
61
- view.destroy!(deserialize_context: deserialize_context)
63
+ views = viewmodel_class.find(viewmodel_ids, eager_include: false)
64
+ views.each do |view|
65
+ view.destroy!(deserialize_context: deserialize_context)
66
+ end
62
67
  end
63
68
  render_viewmodel(nil)
64
69
  end
@@ -91,8 +96,28 @@ module ViewModel::ActiveRecord::Controller
91
96
 
92
97
  private
93
98
 
99
+ # Viewmodel ids are permitted to be either integers or strings
100
+ class ViewmodelIdSerializer < IknowParams::Serializer
101
+ def initialize
102
+ super(::Object)
103
+ end
104
+
105
+ def load(val)
106
+ case val
107
+ when ::Integer, ::String
108
+ val
109
+ else
110
+ raise IknowParams::Serializer::LoadError.new(
111
+ "Incorrect type for #{self.class.name}: #{val.inspect}:#{val.class.name}")
112
+ end
113
+ end
114
+
115
+ set_singleton!
116
+ json_value!
117
+ end
118
+
94
119
  def viewmodel_id
95
- parse_param(:id)
120
+ parse_param(:id, with: ViewmodelIdSerializer)
96
121
  end
97
122
 
98
123
  def migrated_deep_schema_version
@@ -156,11 +156,13 @@ module ActionDispatch
156
156
  name_route = { as: '' } # Only one route may take the name
157
157
  post('', action: :create, **name_route.extract!(:as)) unless except.include?(:create) || !add_shallow_routes
158
158
  get('', action: :index, **name_route.extract!(:as)) unless except.include?(:index) || !add_shallow_routes
159
+ delete('', action: :destroy, as: :bulk_delete) unless except.include?(:destroy) || !add_shallow_routes
159
160
  end
160
161
  end
161
162
  else
162
163
  collection do
163
164
  get('', action: :index, as: '') unless except.include?(:index)
165
+ delete('', action: :destroy, as: :bulk_delete) unless except.include?(:destroy)
164
166
  end
165
167
  end
166
168
  end
@@ -522,6 +522,10 @@ class ViewModel::ActiveRecord
522
522
 
523
523
  delegate :new?, :child_update?, :auto_child_update?, to: :metadata
524
524
 
525
+ def reference_only?
526
+ attributes.empty? && associations.empty? && referenced_associations.empty?
527
+ end
528
+
525
529
  def self.parse_hashes(root_subtree_hashes, referenced_subtree_hashes = {})
526
530
  valid_reference_keys = referenced_subtree_hashes.keys.to_set
527
531
 
@@ -44,6 +44,10 @@ class ViewModel::ActiveRecord
44
44
  @built
45
45
  end
46
46
 
47
+ def reference_only?
48
+ update_data.reference_only? && reparent_to.nil? && reposition_to.nil?
49
+ end
50
+
47
51
  # Evaluate a built update tree, applying and saving changes to the models.
48
52
  def run!(deserialize_context:)
49
53
  raise ViewModel::DeserializationError::Internal.new('Internal error: UpdateOperation run before build') unless built?
@@ -123,9 +127,14 @@ class ViewModel::ActiveRecord
123
127
  end
124
128
  end
125
129
 
126
- # validate
127
- deserialize_context.run_callback(ViewModel::Callbacks::Hook::BeforeValidate, viewmodel)
128
- viewmodel.validate!
130
+ # If a request makes no assertions about the model, we don't demand
131
+ # that the current state of the model is valid. This permits making
132
+ # edits to other models that refer to this model when this model is
133
+ # invalid.
134
+ unless reference_only? && !viewmodel.new_model?
135
+ deserialize_context.run_callback(ViewModel::Callbacks::Hook::BeforeValidate, viewmodel)
136
+ viewmodel.validate!
137
+ end
129
138
 
130
139
  # Save if the model has been altered. Covers not only models with
131
140
  # view changes but also lock version assertions.
@@ -5,8 +5,18 @@ class ViewModel::Migration
5
5
  require 'view_model/migration/one_way_error'
6
6
  require 'view_model/migration/unspecified_version_error'
7
7
 
8
+ REFERENCE_ONLY_KEYS = [
9
+ ViewModel::TYPE_ATTRIBUTE,
10
+ ViewModel::ID_ATTRIBUTE,
11
+ ViewModel::VERSION_ATTRIBUTE,
12
+ ].freeze
13
+
8
14
  def up(view, _references)
9
- raise ViewModel::Migration::OneWayError.new(view[ViewModel::TYPE_ATTRIBUTE], :up)
15
+ # Only a reference-only view may be (trivially) migrated up without an
16
+ # explicit migration.
17
+ if (view.keys - REFERENCE_ONLY_KEYS).present?
18
+ raise ViewModel::Migration::OneWayError.new(view[ViewModel::TYPE_ATTRIBUTE], :up)
19
+ end
10
20
  end
11
21
 
12
22
  def down(view, _references)
@@ -167,6 +167,22 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
167
167
  end
168
168
 
169
169
  def test_destroy
170
+ other_parent = make_parent
171
+ parentcontroller = ParentController.new(params: { id: [@parent.id, other_parent.id] })
172
+ parentcontroller.invoke(:destroy)
173
+
174
+ assert_equal(200, parentcontroller.status)
175
+
176
+ assert(Parent.where(id: @parent.id).blank?, "record doesn't exist after delete")
177
+ assert(Parent.where(id: other_parent.id).blank?, "record doesn't exist after delete")
178
+
179
+ assert_equal({ 'data' => nil },
180
+ parentcontroller.hash_response)
181
+
182
+ assert_all_hooks_nested_inside_parent_hook(parentcontroller.hook_trace)
183
+ end
184
+
185
+ def test_batch_destroy
170
186
  parentcontroller = ParentController.new(params: { id: @parent.id })
171
187
  parentcontroller.invoke(:destroy)
172
188
 
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.10.1
4
+ version: 3.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - iKnow Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-05-24 00:00:00.000000000 Z
11
+ date: 2024-10-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack