Skip to content

Commit

Permalink
Add support for batch deletion
Browse files Browse the repository at this point in the history
The VM::AR controller destroy action now optionally parses multiple ids for
deletion, and the action is aliased as a collection route as well as a member
route.

Deletion is performed one at a time within the same transaction.
  • Loading branch information
chrisandreae committed Jul 19, 2024
1 parent e5ff6fc commit e83af52
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 4 deletions.
2 changes: 1 addition & 1 deletion lib/iknow_view_models/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# frozen_string_literal: true

module IknowViewModels
VERSION = '3.10.1'
VERSION = '3.11.0'
end
31 changes: 28 additions & 3 deletions lib/view_model/active_record/controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,14 @@ def create(serialize_context: new_serialize_context, deserialize_context: new_de
end

def destroy(serialize_context: new_serialize_context, deserialize_context: new_deserialize_context)
viewmodel_ids = parse_param(
:id, with: IknowParams::Serializer::ArrayOf.new(ViewmodelIdSerializer, allow_singleton: true))

viewmodel_class.transaction do
view = viewmodel_class.find(viewmodel_id, eager_include: false)
view.destroy!(deserialize_context: deserialize_context)
views = viewmodel_class.find(viewmodel_ids, eager_include: false)
views.each do |view|
view.destroy!(deserialize_context: deserialize_context)
end
end
render_viewmodel(nil)
end
Expand Down Expand Up @@ -91,8 +96,28 @@ def prerender_viewmodel(...)

private

# Viewmodel ids are permitted to be either integers or strings
class ViewmodelIdSerializer < IknowParams::Serializer
def initialize
super(::Object)
end

def load(val)
case val
when ::Integer, ::String
val
else
raise IknowParams::Serializer::LoadError.new(
"Incorrect type for #{self.class.name}: #{val.inspect}:#{val.class.name}")
end
end

set_singleton!
json_value!
end

def viewmodel_id
parse_param(:id)
parse_param(:id, with: ViewmodelIdSerializer)
end

def migrated_deep_schema_version
Expand Down
2 changes: 2 additions & 0 deletions lib/view_model/active_record/controller_base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,13 @@ def arvm_resources(resource_name, options = {}, &block)
name_route = { as: '' } # Only one route may take the name
post('', action: :create, **name_route.extract!(:as)) unless except.include?(:create) || !add_shallow_routes
get('', action: :index, **name_route.extract!(:as)) unless except.include?(:index) || !add_shallow_routes
delete('', action: :destroy, as: :bulk_delete) unless except.include?(:destroy) || !add_shallow_routes
end
end
else
collection do
get('', action: :index, as: '') unless except.include?(:index)
delete('', action: :destroy, as: :bulk_delete) unless except.include?(:destroy)
end
end
end
Expand Down
16 changes: 16 additions & 0 deletions test/unit/view_model/active_record/controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,22 @@ def test_update
end

def test_destroy
other_parent = make_parent
parentcontroller = ParentController.new(params: { id: [@parent.id, other_parent.id] })
parentcontroller.invoke(:destroy)

assert_equal(200, parentcontroller.status)

assert(Parent.where(id: @parent.id).blank?, "record doesn't exist after delete")
assert(Parent.where(id: other_parent.id).blank?, "record doesn't exist after delete")

assert_equal({ 'data' => nil },
parentcontroller.hash_response)

assert_all_hooks_nested_inside_parent_hook(parentcontroller.hook_trace)
end

def test_batch_destroy
parentcontroller = ParentController.new(params: { id: @parent.id })
parentcontroller.invoke(:destroy)

Expand Down

0 comments on commit e83af52

Please sign in to comment.