Skip to content

Commit 5d0036a

Browse files
authored
Add OnSuccess method to Result. (#8)
1 parent 6e60239 commit 5d0036a

File tree

7 files changed

+593
-17
lines changed

7 files changed

+593
-17
lines changed

src/Winton.DomainModelling.Abstractions/AsyncResultExtensions.cs

Lines changed: 170 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,177 @@
77
namespace Winton.DomainModelling
88
{
99
/// <summary>
10-
/// Extension methods for asynchronous results which make it possible to chain async results together
10+
/// Extension methods for asynchronous results which make it possible to chain asynchronous results together
1111
/// using a fluent API in the same way as synchronous results.
1212
/// </summary>
1313
public static class AsyncResultExtensions
1414
{
15+
/// <summary>
16+
/// Invokes the specified action if the result was successful and returns the original result.
17+
/// </summary>
18+
/// <remarks>
19+
/// If this result is a failure then this is a no-op and the original failure is retained.
20+
/// This is useful for publishing domain model notifications when an operation has been successful.
21+
/// </remarks>
22+
/// <typeparam name="TData">
23+
/// The type of data encapsulated by the result.
24+
/// </typeparam>
25+
/// <param name="resultTask">
26+
/// The asynchronous result that this extension method is invoked on.
27+
/// </param>
28+
/// <param name="onSuccess">
29+
/// The action that will be invoked if this result represents a success.
30+
/// </param>
31+
/// <returns>
32+
/// The original result.
33+
/// </returns>
34+
public static async Task<Result<TData>> OnSuccess<TData>(
35+
this Task<Result<TData>> resultTask,
36+
Action onSuccess)
37+
{
38+
return await resultTask.OnSuccess(data => onSuccess());
39+
}
40+
41+
/// <summary>
42+
/// Invokes the specified action if the result was successful and returns the original result.
43+
/// </summary>
44+
/// <remarks>
45+
/// If this result is a failure then this is a no-op and the original failure is retained.
46+
/// This is useful for publishing domain model notifications when an operation has been successful.
47+
/// </remarks>
48+
/// <typeparam name="TData">
49+
/// The type of data encapsulated by the result.
50+
/// </typeparam>
51+
/// <param name="resultTask">
52+
/// The asynchronous result that this extension method is invoked on.
53+
/// </param>
54+
/// <param name="onSuccess">
55+
/// The action that will be invoked if this result represents a success.
56+
/// </param>
57+
/// <returns>
58+
/// The original result.
59+
/// </returns>
60+
public static async Task<Result<TData>> OnSuccess<TData>(
61+
this Task<Result<TData>> resultTask,
62+
Action<TData> onSuccess)
63+
{
64+
Result<TData> result = await resultTask;
65+
return result.OnSuccess(onSuccess);
66+
}
67+
68+
/// <summary>
69+
/// Invokes the specified action if the result was successful and returns the original result.
70+
/// </summary>
71+
/// <remarks>
72+
/// If this result is a failure then this is a no-op and the original failure is retained.
73+
/// This is useful for publishing domain model notifications when an operation has been successful.
74+
/// </remarks>
75+
/// <typeparam name="TData">
76+
/// The type of data encapsulated by the result.
77+
/// </typeparam>
78+
/// <param name="resultTask">
79+
/// The asynchronous result that this extension method is invoked on.
80+
/// </param>
81+
/// <param name="onSuccess">
82+
/// The asynchronous action that will be invoked if this result represents a success.
83+
/// </param>
84+
/// <returns>
85+
/// The original result.
86+
/// </returns>
87+
public static async Task<Result<TData>> OnSuccess<TData>(
88+
this Task<Result<TData>> resultTask,
89+
Func<Task> onSuccess)
90+
{
91+
return await resultTask.OnSuccess(data => onSuccess());
92+
}
93+
94+
/// <summary>
95+
/// Invokes the specified action if the result was successful and returns the original result.
96+
/// </summary>
97+
/// <remarks>
98+
/// If this result is a failure then this is a no-op and the original failure is retained.
99+
/// This is useful for publishing domain model notifications when an operation has been successful.
100+
/// </remarks>
101+
/// <typeparam name="TData">
102+
/// The type of data encapsulated by the result.
103+
/// </typeparam>
104+
/// <param name="resultTask">
105+
/// The asynchronous result that this extension method is invoked on.
106+
/// </param>
107+
/// <param name="onSuccess">
108+
/// The asynchronous action that will be invoked if this result represents a success.
109+
/// </param>
110+
/// <returns>
111+
/// The original result.
112+
/// </returns>
113+
public static async Task<Result<TData>> OnSuccess<TData>(
114+
this Task<Result<TData>> resultTask,
115+
Func<TData, Task> onSuccess)
116+
{
117+
Result<TData> result = await resultTask;
118+
return await result.OnSuccess(onSuccess);
119+
}
120+
121+
/// <summary>
122+
/// Projects a successful result's data from one type to another.
123+
/// </summary>
124+
/// <remarks>
125+
/// If this result is a failure then this is a no-op.
126+
/// </remarks>
127+
/// <typeparam name="TData">
128+
/// The type of data encapsulated by the result.
129+
/// </typeparam>
130+
/// <typeparam name="TNewData">
131+
/// The type of data in the new result.
132+
/// </typeparam>
133+
/// <param name="resultTask">
134+
/// The asynchronous result that this extension method is invoked on.
135+
/// </param>
136+
/// <param name="selectData">
137+
/// The function that is invoked to select the data.
138+
/// </param>
139+
/// <returns>
140+
/// A new result containing either; the output of the <paramref>selectData</paramref> function
141+
/// if this result is a success, otherwise the original error.
142+
/// </returns>
143+
public static async Task<Result<TNewData>> Select<TData, TNewData>(
144+
this Task<Result<TData>> resultTask,
145+
Func<TData, TNewData> selectData)
146+
{
147+
Result<TData> result = await resultTask;
148+
return result.Select(selectData);
149+
}
150+
151+
/// <summary>
152+
/// Projects a successful result's data from one type to another.
153+
/// </summary>
154+
/// <remarks>
155+
/// If this result is a failure then this is a no-op.
156+
/// </remarks>
157+
/// <typeparam name="TData">
158+
/// The type of data encapsulated by the result.
159+
/// </typeparam>
160+
/// <typeparam name="TNewData">
161+
/// The type of data in the new result.
162+
/// </typeparam>
163+
/// <param name="resultTask">
164+
/// The asynchronous result that this extension method is invoked on.
165+
/// </param>
166+
/// <param name="selectData">
167+
/// The asynchronous function that is invoked to select the data.
168+
/// </param>
169+
/// <returns>
170+
/// A new result containing either; the output of the <paramref>selectData</paramref> function
171+
/// if this result is a success, otherwise the original error.
172+
/// </returns>
173+
public static async Task<Result<TNewData>> Select<TData, TNewData>(
174+
this Task<Result<TData>> resultTask,
175+
Func<TData, Task<TNewData>> selectData)
176+
{
177+
Result<TData> result = await resultTask;
178+
return await result.Select(selectData);
179+
}
180+
15181
/// <summary>
16182
/// Invokes another result generating function which takes as input the data of this result
17183
/// if it is successful after it has been awaited.
@@ -27,7 +193,7 @@ public static class AsyncResultExtensions
27193
/// The type of data in the new result.
28194
/// </typeparam>
29195
/// <param name="resultTask">
30-
/// The async result that this extension method is invoked on.
196+
/// The asynchronous result that this extension method is invoked on.
31197
/// </param>
32198
/// <param name="onSuccess">
33199
/// The function that is invoked if this result represents a success.
@@ -59,7 +225,7 @@ public static async Task<Result<TNewData>> Then<TData, TNewData>(
59225
/// The type of data in the new result.
60226
/// </typeparam>
61227
/// <param name="resultTask">
62-
/// The async result that this extension method is invoked on.
228+
/// The asynchronous result that this extension method is invoked on.
63229
/// </param>
64230
/// <param name="onSuccess">
65231
/// The asynchronous function that is invoked if this result represents a success.
@@ -76,4 +242,4 @@ public static async Task<Result<TNewData>> Then<TData, TNewData>(
76242
return await result.Then(onSuccess);
77243
}
78244
}
79-
}
245+
}

src/Winton.DomainModelling.Abstractions/Failure.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,30 @@ public override T Match<T>(Func<TData, T> onSuccess, Func<Error, T> onFailure)
4444
return onFailure(Error);
4545
}
4646

47+
/// <inheritdoc />
48+
public override Result<TData> OnSuccess(Action onSuccess)
49+
{
50+
return this;
51+
}
52+
53+
/// <inheritdoc />
54+
public override Result<TData> OnSuccess(Action<TData> onSuccess)
55+
{
56+
return this;
57+
}
58+
59+
/// <inheritdoc />
60+
public override Task<Result<TData>> OnSuccess(Func<Task> onSuccess)
61+
{
62+
return Task.FromResult<Result<TData>>(this);
63+
}
64+
65+
/// <inheritdoc />
66+
public override Task<Result<TData>> OnSuccess(Func<TData, Task> onSuccess)
67+
{
68+
return Task.FromResult<Result<TData>>(this);
69+
}
70+
4771
/// <inheritdoc />
4872
public override Result<TNewData> Select<TNewData>(Func<TData, TNewData> selectData)
4973
{

src/Winton.DomainModelling.Abstractions/Result.cs

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,66 @@ public abstract Result<TNewData> Combine<TOtherData, TNewData>(
6262
/// </returns>
6363
public abstract T Match<T>(Func<TData, T> onSuccess, Func<Error, T> onFailure);
6464

65+
/// <summary>
66+
/// Invokes the specified action if the result was successful and returns the original result.
67+
/// </summary>
68+
/// <remarks>
69+
/// If this result is a failure then this is a no-op and the original failure is retained.
70+
/// This is useful for publishing domain model notifications when an operation has been successful.
71+
/// </remarks>
72+
/// <param name="onSuccess">
73+
/// The action that will be invoked if this result represents a success.
74+
/// </param>
75+
/// <returns>
76+
/// The original result.
77+
/// </returns>
78+
public abstract Result<TData> OnSuccess(Action onSuccess);
79+
80+
/// <summary>
81+
/// Invokes the specified action if the result was successful and returns the original result.
82+
/// </summary>
83+
/// <remarks>
84+
/// If this result is a failure then this is a no-op and the original failure is retained.
85+
/// This is useful for publishing domain model notifications when an operation has been successful.
86+
/// </remarks>
87+
/// <param name="onSuccess">
88+
/// The action that will be invoked if this result represents a success.
89+
/// </param>
90+
/// <returns>
91+
/// The original result.
92+
/// </returns>
93+
public abstract Result<TData> OnSuccess(Action<TData> onSuccess);
94+
95+
/// <summary>
96+
/// Invokes the specified action if the result was successful and returns the original result.
97+
/// </summary>
98+
/// <remarks>
99+
/// If this result is a failure then this is a no-op and the original failure is retained.
100+
/// This is useful for publishing domain model notifications when an operation has been successful.
101+
/// </remarks>
102+
/// <param name="onSuccess">
103+
/// The asynchronous action that will be invoked if this result represents a success.
104+
/// </param>
105+
/// <returns>
106+
/// The original result.
107+
/// </returns>
108+
public abstract Task<Result<TData>> OnSuccess(Func<Task> onSuccess);
109+
110+
/// <summary>
111+
/// Invokes the specified action if the result was successful and returns the original result.
112+
/// </summary>
113+
/// <remarks>
114+
/// If this result is a failure then this is a no-op and the original failure is retained.
115+
/// This is useful for publishing domain model notifications when an operation has been successful.
116+
/// </remarks>
117+
/// <param name="onSuccess">
118+
/// The asynchronous action that will be invoked if this result represents a success.
119+
/// </param>
120+
/// <returns>
121+
/// The original result.
122+
/// </returns>
123+
public abstract Task<Result<TData>> OnSuccess(Func<TData, Task> onSuccess);
124+
65125
/// <summary>
66126
/// Projects a successful result's data from one type to another.
67127
/// </summary>
@@ -75,8 +135,8 @@ public abstract Result<TNewData> Combine<TOtherData, TNewData>(
75135
/// The function that is invoked to select the data.
76136
/// </param>
77137
/// <returns>
78-
/// If this result is a success, then the result of <paramref>selectData</paramref> function;
79-
/// otherwise the original error.
138+
/// A new result containing either; the output of the <paramref>selectData</paramref> function
139+
/// if this result is a success, otherwise the original error.
80140
/// </returns>
81141
public abstract Result<TNewData> Select<TNewData>(Func<TData, TNewData> selectData);
82142

@@ -93,8 +153,8 @@ public abstract Result<TNewData> Combine<TOtherData, TNewData>(
93153
/// The asynchronous function that is invoked to select the data.
94154
/// </param>
95155
/// <returns>
96-
/// If this result is a success, then the result of <paramref>selectData</paramref> function;
97-
/// otherwise the original error.
156+
/// A new result containing either; the output of the <paramref>selectData</paramref> function
157+
/// if this result is a success, otherwise the original error.
98158
/// </returns>
99159
public abstract Task<Result<TNewData>> Select<TNewData>(Func<TData, Task<TNewData>> selectData);
100160

@@ -104,7 +164,7 @@ public abstract Result<TNewData> Combine<TOtherData, TNewData>(
104164
/// </summary>
105165
/// <remarks>
106166
/// If this result is a failure then this is a no-op and the original failure is retained.
107-
/// This is useful form chaining serial operations together that return results.
167+
/// This is useful for chaining serial operations together that return results.
108168
/// </remarks>
109169
/// <typeparam name="TNewData">
110170
/// The type of data in the new result.
@@ -124,7 +184,7 @@ public abstract Result<TNewData> Combine<TOtherData, TNewData>(
124184
/// </summary>
125185
/// <remarks>
126186
/// If this result is a failure then this is a no-op and the original failure is retained.
127-
/// This is useful form chaining serial operations together that return results.
187+
/// This is useful for chaining serial operations together that return results.
128188
/// </remarks>
129189
/// <typeparam name="TNewData">
130190
/// The type of data in the new result.

src/Winton.DomainModelling.Abstractions/Success.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,32 @@ public override T Match<T>(Func<TData, T> onSuccess, Func<Error, T> onFailure)
7171
return onSuccess(Data);
7272
}
7373

74+
/// <inheritdoc />
75+
public override Result<TData> OnSuccess(Action onSuccess)
76+
{
77+
return OnSuccess(data => onSuccess());
78+
}
79+
80+
/// <inheritdoc />
81+
public override Result<TData> OnSuccess(Action<TData> onSuccess)
82+
{
83+
onSuccess(Data);
84+
return this;
85+
}
86+
87+
/// <inheritdoc />
88+
public override async Task<Result<TData>> OnSuccess(Func<Task> onSuccess)
89+
{
90+
return await OnSuccess(data => onSuccess());
91+
}
92+
93+
/// <inheritdoc />
94+
public override async Task<Result<TData>> OnSuccess(Func<TData, Task> onSuccess)
95+
{
96+
await onSuccess(Data);
97+
return this;
98+
}
99+
74100
/// <inheritdoc />
75101
public override Result<TNewData> Select<TNewData>(Func<TData, TNewData> selectData)
76102
{

0 commit comments

Comments
 (0)