admin_action.rb

  1# frozen_string_literal: true
  2
  3require "delegate"
  4
  5class AdminAction
  6	class NoOp
  7		def to_s
  8			"NoOp"
  9		end
 10	end
 11
 12	module Direction
 13		class InvalidDirection < StandardError; end
 14
 15		def self.for(direction)
 16			{
 17				forward: Forward,
 18				reverse: Reverse,
 19				reforward: Reforward
 20			}.fetch(direction.to_sym) { raise InvalidDirection }
 21		end
 22
 23		class Forward < SimpleDelegator
 24			def with(**kwargs)
 25				self.class.new(__getobj__.with(**kwargs))
 26			end
 27
 28			def perform
 29				check_forward.then { forward }.then { |x| self.class.new(x) }
 30			end
 31
 32			def to_h
 33				super.merge(direction: :forward)
 34			end
 35
 36			def undo
 37				Reverse.new(__getobj__.with(parent_id: id))
 38			end
 39		end
 40
 41		class Reverse < SimpleDelegator
 42			def with(**kwargs)
 43				self.class.new(__getobj__.with(**kwargs))
 44			end
 45
 46			def perform
 47				check_reverse.then { reverse }.then { |x| self.class.new(x) }
 48			end
 49
 50			def to_s
 51				"UNDO(#{parent_id}) #{super}"
 52			end
 53
 54			def to_h
 55				super.merge(direction: :reverse)
 56			end
 57
 58			def undo
 59				Reforward.new(__getobj__)
 60			end
 61		end
 62
 63		class Reforward < Forward
 64			def with(**kwargs)
 65				self.class.new(__getobj__.with(**kwargs))
 66			end
 67
 68			def to_s
 69				"REDO(#{parent_id}) #{super}"
 70			end
 71
 72			def to_h
 73				super.merge(direction: :reforward)
 74			end
 75
 76			def undo
 77				Reverse.new(__getobj__)
 78			end
 79		end
 80	end
 81
 82	def self.for(**kwargs)
 83		Direction::Forward.new(new(**kwargs))
 84	end
 85
 86	def initialize(**kwargs)
 87		@attributes = kwargs
 88	end
 89
 90	def with(**kwargs)
 91		self.class.new(@attributes.merge(kwargs))
 92	end
 93
 94	def id
 95		@attributes[:id]
 96	end
 97
 98	def parent_id
 99		@attributes[:parent_id]
100	end
101
102	def actor_id
103		@attributes[:actor_id]
104	end
105
106	def check_forward
107		EMPromise.resolve(nil)
108	end
109
110	def forward
111		EMPromise.resolve(self)
112	end
113
114	def check_reverse
115		EMPromise.resolve(nil)
116	end
117
118	def reverse
119		EMPromise.resolve(self)
120	end
121
122	def to_h
123		@attributes.merge({
124			class: self.class.to_s.delete_prefix("AdminAction::")
125		}.compact)
126	end
127
128	module Isomorphic
129		def check_reverse
130			to_reverse.check_forward
131		end
132
133		def reverse
134			# We don't want it to return the reversed one
135			# We want it to return itself but with the reverse state
136			to_reverse.forward.then { self }
137		end
138	end
139end