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