Skip to content

Commit 4955543

Browse files
committed
Implements orElse/orElseWith
Closes #119
1 parent 33124e5 commit 4955543

File tree

18 files changed

+700
-170
lines changed

18 files changed

+700
-170
lines changed

build.fsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,4 +216,4 @@ Target.create "UpdateDocs" (fun _ ->
216216
==> "Release"
217217

218218
// *** Start Build ***
219-
Target.runOrDefaultWithArguments "Build"
219+
Target.runOrDefaultWithArguments "NuGet"

src/FsToolkit.ErrorHandling.JobResult/JobResult.fs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,14 @@ module JobResult =
4040
Ok x
4141
|> Job.result
4242

43+
let ok = retn
44+
4345
let returnError x =
4446
Error x
4547
|> Job.result
4648

49+
let error = returnError
50+
4751
let map2 f xJR yJR =
4852
Job.map2 (Result.map2 f) xJR yJR
4953

@@ -53,6 +57,58 @@ module JobResult =
5357
let apply fJR xJR =
5458
map2 (fun f x -> f x) fJR xJR
5559

60+
61+
/// <summary>
62+
/// Returns <paramref name="result"/> if it is <c>Ok</c>, otherwise returns <paramref name="ifError"/>
63+
/// </summary>
64+
/// <param name="ifError">The value to use if <paramref name="result"/> is <c>Error</c></param>
65+
/// <param name="result">The input result.</param>
66+
/// <remarks>
67+
/// </remarks>
68+
/// <example>
69+
/// <code>
70+
/// JobResult.error "First" |> JobResult.orElse (JobResult.error "Second") // evaluates to Error ("Second")
71+
/// JobResult.error "First" |> JobResult.orElse (JobResult.ok "Second") // evaluates to Ok ("Second")
72+
/// JobResult.ok "First" |> JobResult.orElse (JobResult.error "Second") // evaluates to Ok ("First")
73+
/// JobResult.ok "First" |> JobResult.orElse (JobResult.ok "Second") // evaluates to Ok ("First")
74+
/// </code>
75+
/// </example>
76+
/// <returns>
77+
/// The result if the result is Ok, else returns <paramref name="ifError"/>.
78+
/// </returns>
79+
let inline orElse (ifError : Job<Result<'ok,'error2>>) (result : Job<Result<'ok,'error>>) =
80+
job {
81+
match! result with
82+
| Ok r -> return Ok r
83+
| Error _ -> return! ifError
84+
}
85+
86+
/// <summary>
87+
/// Returns <paramref name="result"/> if it is <c>Ok</c>, otherwise executes <paramref name="ifErrorFunc"/> and returns the result.
88+
/// </summary>
89+
/// <param name="ifErrorFunc">A function that provides an alternate result when evaluated.</param>
90+
/// <param name="result">The input result.</param>
91+
/// <remarks>
92+
/// <paramref name="ifErrorFunc"/> is not executed unless <paramref name="result"/> is an <c>Error</c>.
93+
/// </remarks>
94+
/// <example>
95+
/// <code>
96+
/// JobResult.error "First" |> JobResult.orElseWith (fun _ -> JobResult.error "Second") // evaluates to Error ("Second")
97+
/// JobResult.error "First" |> JobResult.orElseWith (fun _ -> JobResult.ok "Second") // evaluates to Ok ("Second")
98+
/// JobResult.ok "First" |> JobResult.orElseWith (fun _ -> JobResult.error "Second") // evaluates to Ok ("First")
99+
/// JobResult.ok "First" |> JobResult.orElseWith (fun _ -> JobResult.ok "Second") // evaluates to Ok ("First")
100+
/// </code>
101+
/// </example>
102+
/// <returns>
103+
/// The result if the result is Ok, else the result of executing <paramref name="ifErrorFunc"/>.
104+
/// </returns>
105+
let inline orElseWith (ifErrorFunc : 'error -> Job<Result<'ok,'error2>>) (result : Job<Result<'ok,'error>>) =
106+
job {
107+
match! result with
108+
| Ok r -> return Ok r
109+
| Error e -> return! ifErrorFunc e
110+
}
111+
56112
/// Replaces the wrapped value with unit
57113
let ignore jr =
58114
jr |> map ignore

src/FsToolkit.ErrorHandling.TaskResult/TaskResult.fs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,13 @@ module TaskResult =
3434
Ok x
3535
|> Task.singleton
3636

37+
let ok = retn
38+
3739
let returnError x =
3840
Error x
3941
|> Task.singleton
42+
43+
let error = returnError
4044

4145
let map2 f xTR yTR =
4246
Task.map2 (Result.map2 f) xTR yTR
@@ -47,6 +51,58 @@ module TaskResult =
4751
let apply fTR xTR =
4852
map2 (fun f x -> f x) fTR xTR
4953

54+
55+
/// <summary>
56+
/// Returns <paramref name="result"/> if it is <c>Ok</c>, otherwise returns <paramref name="ifError"/>
57+
/// </summary>
58+
/// <param name="ifError">The value to use if <paramref name="result"/> is <c>Error</c></param>
59+
/// <param name="result">The input result.</param>
60+
/// <remarks>
61+
/// </remarks>
62+
/// <example>
63+
/// <code>
64+
/// TaskResult.error "First" |> TaskResult.orElse (TaskResult.error "Second") // evaluates to Error ("Second")
65+
/// TaskResult.error "First" |> TaskResult.orElse (TaskResult.ok "Second") // evaluates to Ok ("Second")
66+
/// TaskResult.ok "First" |> TaskResult.orElse (TaskResult.error "Second") // evaluates to Ok ("First")
67+
/// TaskResult.ok "First" |> TaskResult.orElse (TaskResult.ok "Second") // evaluates to Ok ("First")
68+
/// </code>
69+
/// </example>
70+
/// <returns>
71+
/// The result if the result is Ok, else returns <paramref name="ifError"/>.
72+
/// </returns>
73+
let inline orElse (ifError : Task<Result<'ok,'error2>>) (result : Task<Result<'ok,'error>>) =
74+
task {
75+
match! result with
76+
| Ok r -> return Ok r
77+
| Error _ -> return! ifError
78+
}
79+
80+
/// <summary>
81+
/// Returns <paramref name="result"/> if it is <c>Ok</c>, otherwise executes <paramref name="ifErrorFunc"/> and returns the result.
82+
/// </summary>
83+
/// <param name="ifErrorFunc">A function that provides an alternate result when evaluated.</param>
84+
/// <param name="result">The input result.</param>
85+
/// <remarks>
86+
/// <paramref name="ifErrorFunc"/> is not executed unless <paramref name="result"/> is an <c>Error</c>.
87+
/// </remarks>
88+
/// <example>
89+
/// <code>
90+
/// TaskResult.error "First" |> TaskResult.orElseWith (fun _ -> TaskResult.error "Second") // evaluates to Error ("Second")
91+
/// TaskResult.error "First" |> TaskResult.orElseWith (fun _ -> TaskResult.ok "Second") // evaluates to Ok ("Second")
92+
/// TaskResult.ok "First" |> TaskResult.orElseWith (fun _ -> TaskResult.error "Second") // evaluates to Ok ("First")
93+
/// TaskResult.ok "First" |> TaskResult.orElseWith (fun _ -> TaskResult.ok "Second") // evaluates to Ok ("First")
94+
/// </code>
95+
/// </example>
96+
/// <returns>
97+
/// The result if the result is Ok, else the result of executing <paramref name="ifErrorFunc"/>.
98+
/// </returns>
99+
let inline orElseWith (ifErrorFunc : 'error -> Task<Result<'ok,'error2>>) (result : Task<Result<'ok,'error>>) =
100+
task {
101+
match! result with
102+
| Ok r -> return Ok r
103+
| Error e -> return! ifErrorFunc e
104+
}
105+
50106
/// Replaces the wrapped value with unit
51107
let ignore tr =
52108
tr |> map ignore

src/FsToolkit.ErrorHandling/AsyncResult.fs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,15 @@ module AsyncResult =
4242
let retn x =
4343
Ok x
4444
|> Async.singleton
45+
46+
let ok = retn
4547

4648
let returnError x =
4749
Error x
4850
|> Async.singleton
4951

52+
let error = returnError
53+
5054
let map2 f xR yR =
5155
Async.map2 (Result.map2 f) xR yR
5256

@@ -56,6 +60,58 @@ module AsyncResult =
5660
let apply fAR xAR =
5761
map2 (fun f x -> f x) fAR xAR
5862

63+
64+
/// <summary>
65+
/// Returns <paramref name="result"/> if it is <c>Ok</c>, otherwise returns <paramref name="ifError"/>
66+
/// </summary>
67+
/// <param name="ifError">The value to use if <paramref name="result"/> is <c>Error</c></param>
68+
/// <param name="result">The input result.</param>
69+
/// <remarks>
70+
/// </remarks>
71+
/// <example>
72+
/// <code>
73+
/// AsyncResult.error "First" |> AsyncResult.orElse (AsyncResult.error "Second") // evaluates to Error ("Second")
74+
/// AsyncResult.error "First" |> AsyncResult.orElse (AsyncResult.ok "Second") // evaluates to Ok ("Second")
75+
/// AsyncResult.ok "First" |> AsyncResult.orElse (AsyncResult.error "Second") // evaluates to Ok ("First")
76+
/// AsyncResult.ok "First" |> AsyncResult.orElse (AsyncResult.ok "Second") // evaluates to Ok ("First")
77+
/// </code>
78+
/// </example>
79+
/// <returns>
80+
/// The result if the result is Ok, else returns <paramref name="ifError"/>.
81+
/// </returns>
82+
let inline orElse (ifError : Async<Result<'ok,'error2>>) (result : Async<Result<'ok,'error>>) =
83+
async {
84+
match! result with
85+
| Ok r -> return Ok r
86+
| Error _ -> return! ifError
87+
}
88+
89+
/// <summary>
90+
/// Returns <paramref name="result"/> if it is <c>Ok</c>, otherwise executes <paramref name="ifErrorFunc"/> and returns the result.
91+
/// </summary>
92+
/// <param name="ifErrorFunc">A function that provides an alternate result when evaluated.</param>
93+
/// <param name="result">The input result.</param>
94+
/// <remarks>
95+
/// <paramref name="ifErrorFunc"/> is not executed unless <paramref name="result"/> is an <c>Error</c>.
96+
/// </remarks>
97+
/// <example>
98+
/// <code>
99+
/// AsyncResult.error "First" |> AsyncResult.orElseWith (fun _ -> AsyncResult.error "Second") // evaluates to Error ("Second")
100+
/// AsyncResult.error "First" |> AsyncResult.orElseWith (fun _ -> AsyncResult.ok "Second") // evaluates to Ok ("Second")
101+
/// AsyncResult.ok "First" |> AsyncResult.orElseWith (fun _ -> AsyncResult.error "Second") // evaluates to Ok ("First")
102+
/// AsyncResult.ok "First" |> AsyncResult.orElseWith (fun _ -> AsyncResult.ok "Second") // evaluates to Ok ("First")
103+
/// </code>
104+
/// </example>
105+
/// <returns>
106+
/// The result if the result is Ok, else the result of executing <paramref name="ifErrorFunc"/>.
107+
/// </returns>
108+
let inline orElseWith (ifErrorFunc : 'error -> Async<Result<'ok,'error2>>) (result : Async<Result<'ok,'error>>) =
109+
async {
110+
match! result with
111+
| Ok r -> return Ok r
112+
| Error e -> return! ifErrorFunc e
113+
}
114+
59115
/// Replaces the wrapped value with unit
60116
let ignore ar =
61117
ar |> map ignore

src/FsToolkit.ErrorHandling/Result.fs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,55 @@ module Result =
4545
tryCreate' x
4646
|> Result.mapError (fun z -> (fieldName, z))
4747

48+
49+
/// <summary>
50+
/// Returns <paramref name="result"/> if it is <c>Ok</c>, otherwise returns <paramref name="ifError"/>
51+
/// </summary>
52+
/// <param name="ifError">The value to use if <paramref name="result"/> is <c>Error</c></param>
53+
/// <param name="result">The input result.</param>
54+
/// <remarks>
55+
/// </remarks>
56+
/// <example>
57+
/// <code>
58+
/// Error ("First") |> Result.orElse (Error ("Second")) // evaluates to Error ("Second")
59+
/// Error ("First") |> Result.orElseWith (Ok ("Second")) // evaluates to Ok ("Second")
60+
/// Ok ("First") |> Result.orElseWith (Error ("Second")) // evaluates to Ok ("First")
61+
/// Ok ("First") |> Result.orElseWith (Ok ("Second")) // evaluates to Ok ("First")
62+
/// </code>
63+
/// </example>
64+
/// <returns>
65+
/// The result if the result is Ok, else returns <paramref name="ifError"/>.
66+
/// </returns>
67+
let inline orElse (ifError : Result<'ok,'error2>) (result : Result<'ok,'error>) =
68+
match result with
69+
| Ok r -> Ok r
70+
| Error _ -> ifError
71+
72+
73+
/// <summary>
74+
/// Returns <paramref name="result"/> if it is <c>Ok</c>, otherwise executes <paramref name="ifErrorFunc"/> and returns the result.
75+
/// </summary>
76+
/// <param name="ifErrorFunc">A function that provides an alternate result when evaluated.</param>
77+
/// <param name="result">The input result.</param>
78+
/// <remarks>
79+
/// <paramref name="ifErrorFunc"/> is not executed unless <paramref name="result"/> is an <c>Error</c>.
80+
/// </remarks>
81+
/// <example>
82+
/// <code>
83+
/// Error ("First") |> Result.orElseWith (fun _ -> Error ("Second")) // evaluates to Error ("Second")
84+
/// Error ("First") |> Result.orElseWith (fun _ -> Ok ("Second")) // evaluates to Ok ("Second")
85+
/// Ok ("First") |> Result.orElseWith (fun _ -> Error ("Second")) // evaluates to Ok ("First")
86+
/// Ok ("First") |> Result.orElseWith (fun _ -> Ok ("Second")) // evaluates to Ok ("First")
87+
/// </code>
88+
/// </example>
89+
/// <returns>
90+
/// The result if the result is Ok, else the result of executing <paramref name="ifErrorFunc"/>.
91+
/// </returns>
92+
let inline orElseWith (ifErrorFunc : 'error -> Result<'ok,'error2>) (result : Result<'ok,'error>) =
93+
match result with
94+
| Ok r -> Ok r
95+
| Error e -> ifErrorFunc e
96+
4897
/// Replaces the wrapped value with unit
4998
let ignore result =
5099
result |> Result.map ignore

src/FsToolkit.ErrorHandling/Validation.fs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,57 @@ module Validation =
2323

2424
let retn x = ok x
2525

26+
let returnError e = error
27+
28+
29+
/// <summary>
30+
/// Returns <paramref name="result"/> if it is <c>Ok</c>, otherwise returns <paramref name="ifError"/>
31+
/// </summary>
32+
/// <param name="ifError">The value to use if <paramref name="result"/> is <c>Error</c></param>
33+
/// <param name="result">The input result.</param>
34+
/// <remarks>
35+
/// </remarks>
36+
/// <example>
37+
/// <code>
38+
/// Error (["First"]) |> Validation.orElse (Error (["Second"])) // evaluates to Error (["Second"])
39+
/// Error (["First"]) |> Validation.orElseWith (Ok ("Second")) // evaluates to Ok ("Second")
40+
/// Ok ("First") |> Validation.orElseWith (Error (["Second"])) // evaluates to Ok ("First")
41+
/// Ok ("First") |> Validation.orElseWith (Ok ("Second")) // evaluates to Ok ("First")
42+
/// </code>
43+
/// </example>
44+
/// <returns>
45+
/// The result if the result is Ok, else returns <paramref name="ifError"/>.
46+
/// </returns>
47+
let inline orElse (ifError : Validation<'ok,'error2>) (result : Validation<'ok,'error>) : Validation<'ok,'error2> =
48+
match result with
49+
| Ok r -> Ok r
50+
| Error _ -> ifError
51+
52+
53+
/// <summary>
54+
/// Returns <paramref name="result"/> if it is <c>Ok</c>, otherwise executes <paramref name="ifErrorFunc"/> and returns the result.
55+
/// </summary>
56+
/// <param name="ifErrorFunc">A function that provides an alternate result when evaluated.</param>
57+
/// <param name="result">The input result.</param>
58+
/// <remarks>
59+
/// <paramref name="ifErrorFunc"/> is not executed unless <paramref name="result"/> is an <c>Error</c>.
60+
/// </remarks>
61+
/// <example>
62+
/// <code>
63+
/// Error (["First"]) |> Validation.orElseWith (fun _ -> Error (["Second"])) // evaluates to Error (["Second"])
64+
/// Error (["First"]) |> Validation.orElseWith (fun _ -> Ok ("Second")) // evaluates to Ok ("Second")
65+
/// Ok ("First") |> Validation.orElseWith (fun _ -> Error (["Second"])) // evaluates to Ok ("First")
66+
/// Ok ("First") |> Validation.orElseWith (fun _ -> Ok ("Second")) // evaluates to Ok ("First")
67+
/// </code>
68+
/// </example>
69+
/// <returns>
70+
/// The result if the result is Ok, else the result of executing <paramref name="ifErrorFunc"/>.
71+
/// </returns>
72+
let inline orElseWith (ifErrorFunc : 'error list -> Validation<'ok,'error2>) (result : Validation<'ok,'error>) : Validation<'ok,'error2> =
73+
match result with
74+
| Ok r -> Ok r
75+
| Error e -> ifErrorFunc e
76+
2677
let map f (x : Validation<_,_>) : Validation<_,_>= Result.map f x
2778

2879
let map2 f (x : Validation<_,_>) (y : Validation<_,_>) : Validation<_,_> =

tests/FsToolkit.ErrorHandling.JobResult.Tests/Expect.JobResult.fs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,20 @@ module Expect =
1010
()
1111
else Tests.failtestf "Expected %A, was %A." v x
1212

13+
let hasJobOkValue v (jobX : Job<_>) = job {
14+
let! x = jobX
15+
TestHelpers.Expect.hasOkValue v x
16+
}
1317

14-
let hasJobOkValue v jobX =
18+
let hasJobOkValueSync v jobX =
1519
let x = run jobX
1620
TestHelpers.Expect.hasOkValue v x
1721

22+
let hasJobErrorValue v (jobX : Job<_>) = job {
23+
let! x = jobX
24+
TestHelpers.Expect.hasErrorValue v x
25+
}
1826

19-
let hasJobErrorValue v jobX =
27+
let hasJobErrorValueSync v jobX =
2028
let x = run jobX
2129
TestHelpers.Expect.hasErrorValue v x

0 commit comments

Comments
 (0)