1212use Innmind \Immutable \{
1313 Attempt ,
1414 Sequence ,
15+ Map ,
16+ Set ,
1517 SideEffect ,
1618 Predicate \Instance ,
1719};
2224final class Transaction implements TransactionInterface
2325{
2426 private Adapter $ committed ;
25- /** @var Sequence<callable(Adapter): Attempt<SideEffect>> */
27+ private Adapter $ notCommitted ;
28+ /** @var Sequence<Directory> */
2629 private Sequence $ mutations ;
30+ /** @var Map<non-empty-string, Set<Name>> */
31+ private Map $ removals ;
2732
2833 private function __construct (Adapter $ committed )
2934 {
3035 $ this ->committed = $ committed ;
36+ $ this ->notCommitted = Adapter::inMemory ();
3137 $ this ->mutations = Sequence::of ();
38+ $ this ->removals = Map::of ();
3239 }
3340
3441 /**
@@ -42,7 +49,7 @@ public static function of(Adapter $committed): self
4249 #[\Override]
4350 public function start (): Attempt
4451 {
45- $ this ->mutations = $ this -> mutations -> clear ();
52+ $ this ->reset ();
4653
4754 return Attempt::result (SideEffect::identity ());
4855 }
@@ -59,7 +66,7 @@ public function commit(mixed $value): Attempt
5966 {
6067 return $ this
6168 ->apply ($ this ->committed )
62- ->map (fn () => $ this ->mutations = $ this -> mutations -> clear ( ))
69+ ->map ($ this ->reset (... ))
6370 ->map (static fn () => $ value );
6471 }
6572
@@ -73,49 +80,66 @@ public function commit(mixed $value): Attempt
7380 #[\Override]
7481 public function rollback (mixed $ value ): Attempt
7582 {
76- $ this ->mutations = $ this -> mutations -> clear ();
83+ $ this ->reset ();
7784
7885 return Attempt::result ($ value );
7986 }
8087
8188 /**
82- * @param callable(Adapter): Attempt<SideEffect> $mutate
83- *
8489 * @return Attempt<SideEffect>
8590 */
86- public function mutate (callable $ mutate ): Attempt
91+ public function mutate (Directory $ directory ): Attempt
8792 {
88- $ this ->mutations = ($ this ->mutations )($ mutate );
89-
90- return Attempt::result (SideEffect::identity);
93+ $ this ->mutations = ($ this ->mutations )($ directory );
94+ /** @psalm-suppress InternalMethod */
95+ $ this ->removals = ($ this ->removals )(
96+ $ directory ->name ()->toString (),
97+ $ this
98+ ->removals
99+ ->get ($ directory ->name ()->toString ())
100+ ->match (
101+ static fn ($ removed ) => $ removed ->merge ($ directory ->removed ()),
102+ static fn () => $ directory ->removed (),
103+ ),
104+ );
105+
106+ return $ this ->notCommitted ->add ($ directory );
91107 }
92108
93109 public function get (Name $ directory ): Directory
94110 {
95- $ committed = $ this
96- ->committed
111+ $ notCommitted = $ this
112+ ->notCommitted
97113 ->get ($ directory )
98114 ->keep (Instance::of (Directory::class))
99115 ->match (
100116 static fn ($ directory ) => $ directory ,
101117 static fn () => Directory::of ($ directory ),
102118 );
103- $ notCommitted = Adapter::inMemory ();
104- $ _ = $ notCommitted
105- ->add ($ committed )
106- ->unwrap ();
107-
108- $ _ = $ this
109- ->apply ($ notCommitted )
110- ->unwrap ();
111-
112- return $ notCommitted
119+ $ committed = $ this
120+ ->committed
113121 ->get ($ directory )
114122 ->keep (Instance::of (Directory::class))
115123 ->match (
116124 static fn ($ directory ) => $ directory ,
117125 static fn () => Directory::of ($ directory ),
118126 );
127+
128+ $ merged = $ this
129+ ->removals
130+ ->get ($ directory ->toString ())
131+ ->match (
132+ static fn ($ removed ) => $ removed ->reduce (
133+ $ committed ,
134+ static fn (Directory $ committed , $ name ) => $ committed ->remove ($ name ),
135+ ),
136+ static fn () => $ committed ,
137+ );
138+
139+ return $ notCommitted ->all ()->reduce (
140+ $ merged ,
141+ static fn (Directory $ merged , $ file ) => $ merged ->add ($ file ),
142+ );
119143 }
120144
121145 /**
@@ -126,6 +150,13 @@ private function apply(Adapter $adapter): Attempt
126150 return $ this
127151 ->mutations
128152 ->sink (SideEffect::identity)
129- ->attempt (static fn ($ _ , $ mutate ) => $ mutate ($ adapter ));
153+ ->attempt (static fn ($ _ , $ mutation ) => $ adapter ->add ($ mutation ));
154+ }
155+
156+ private function reset (): void
157+ {
158+ $ this ->notCommitted = Adapter::inMemory ();
159+ $ this ->mutations = $ this ->mutations ->clear ();
160+ $ this ->removals = $ this ->removals ->clear ();
130161 }
131162}
0 commit comments