# frozen_string_literal: true
require "delegate"
class AdminAction
class NoOp
def to_s
"NoOp"
end
end
module Direction
class InvalidDirection < StandardError; end
def self.for(direction)
{
forward: Forward,
reverse: Reverse,
reforward: Reforward
}.fetch(direction.to_sym) { raise InvalidDirection }
end
class Forward < SimpleDelegator
def with(**kwargs)
self.class.new(__getobj__.with(**kwargs))
end
def perform
check_forward.then { forward }.then { |x| self.class.new(x) }
end
def to_h
super.merge(direction: :forward)
end
def undo
Reverse.new(__getobj__.with(parent_id: id))
end
end
class Reverse < SimpleDelegator
def with(**kwargs)
self.class.new(__getobj__.with(**kwargs))
end
def perform
check_reverse.then { reverse }.then { |x| self.class.new(x) }
end
def to_s
"UNDO(#{parent_id}) #{super}"
end
def to_h
super.merge(direction: :reverse)
end
def undo
Reforward.new(__getobj__)
end
end
class Reforward < Forward
def with(**kwargs)
self.class.new(__getobj__.with(**kwargs))
end
def to_s
"REDO(#{parent_id}) #{super}"
end
def to_h
super.merge(direction: :reforward)
end
def undo
Reverse.new(__getobj__)
end
end
end
def self.for(**kwargs)
Direction::Forward.new(new(**kwargs))
end
def initialize(**kwargs)
@attributes = kwargs
end
def with(**kwargs)
self.class.new(@attributes.merge(kwargs))
end
def id
@attributes[:id]
end
def parent_id
@attributes[:parent_id]
end
def actor_id
@attributes[:actor_id]
end
def check_forward
EMPromise.resolve(nil)
end
def forward
EMPromise.resolve(self)
end
def check_reverse
EMPromise.resolve(nil)
end
def reverse
EMPromise.resolve(self)
end
def to_h
@attributes.merge({
class: self.class.to_s.delete_prefix("AdminAction::")
}.compact)
end
module Isomorphic
def check_reverse
to_reverse.check_forward
end
def reverse
# We don't want it to return the reversed one
# We want it to return itself but with the reverse state
to_reverse.forward.then { self }
end
end
end