From d5ccc9aefea335fa5333ff2756d156d292a2e715 Mon Sep 17 00:00:00 2001 From: Joseph Price Date: Fri, 10 Jan 2025 19:46:53 -0500 Subject: [PATCH 1/5] add requireSomeWith --- .../JobResult.fs | 6 +++++- src/FsToolkit.ErrorHandling/AsyncResult.fs | 7 +++++++ src/FsToolkit.ErrorHandling/Result.fs | 8 ++++++++ src/FsToolkit.ErrorHandling/TaskResult.fs | 4 ++++ .../JobResult.fs | 16 ++++++++++++++++ .../TaskResult.fs | 16 ++++++++++++++++ .../FsToolkit.ErrorHandling.Tests/AsyncResult.fs | 13 +++++++++++++ tests/FsToolkit.ErrorHandling.Tests/Result.fs | 14 ++++++++++++++ 8 files changed, 83 insertions(+), 1 deletion(-) diff --git a/src/FsToolkit.ErrorHandling.JobResult/JobResult.fs b/src/FsToolkit.ErrorHandling.JobResult/JobResult.fs index 63b8c4e6..f8c5d905 100644 --- a/src/FsToolkit.ErrorHandling.JobResult/JobResult.fs +++ b/src/FsToolkit.ErrorHandling.JobResult/JobResult.fs @@ -1,4 +1,4 @@ -namespace FsToolkit.ErrorHandling +namespace FsToolkit.ErrorHandling open Hopac open Hopac.Infixes @@ -124,6 +124,10 @@ module JobResult = option |> Job.map (Result.requireSome error) + let inline requireSomeWith error option = + option + |> Job.map (Result.requireSomeWith error) + // Converts an job-wrapped Option to a Result, using the given error if Some. let inline requireNone error option = option diff --git a/src/FsToolkit.ErrorHandling/AsyncResult.fs b/src/FsToolkit.ErrorHandling/AsyncResult.fs index 0335121e..ba7bdbc6 100644 --- a/src/FsToolkit.ErrorHandling/AsyncResult.fs +++ b/src/FsToolkit.ErrorHandling/AsyncResult.fs @@ -157,6 +157,13 @@ module AsyncResult = value |> Async.map (Result.requireSome error) + let inline requireSomeWith + (ifErrorThunk: unit -> 'error) + (value: Async<'ok option>) + : Async> = + value + |> Async.map (Result.requireSomeWith ifErrorThunk) + // Converts an async-wrapped Option to a Result, using the given error if Some. let inline requireNone (error: 'error) diff --git a/src/FsToolkit.ErrorHandling/Result.fs b/src/FsToolkit.ErrorHandling/Result.fs index fc2f6261..3ccf7b37 100644 --- a/src/FsToolkit.ErrorHandling/Result.fs +++ b/src/FsToolkit.ErrorHandling/Result.fs @@ -307,6 +307,14 @@ module Result = | Some x -> Ok x | None -> Error error + let inline requireSomeWith + (ifErrorThunk: unit -> 'error) + (option: 'ok option) + : Result<'ok, 'error> = + match option with + | Some x -> Ok x + | None -> Error(ifErrorThunk ()) + /// /// Requires a value to be None, otherwise returns an error result. /// diff --git a/src/FsToolkit.ErrorHandling/TaskResult.fs b/src/FsToolkit.ErrorHandling/TaskResult.fs index 8abfa50c..28f0336f 100644 --- a/src/FsToolkit.ErrorHandling/TaskResult.fs +++ b/src/FsToolkit.ErrorHandling/TaskResult.fs @@ -109,6 +109,10 @@ module TaskResult = option |> Task.map (Result.requireSome error) + let inline requireSomeWith error option = + option + |> Task.map (Result.requireSomeWith error) + // Converts an task-wrapped Option to a Result, using the given error if Some. let inline requireNone error option = option diff --git a/tests/FsToolkit.ErrorHandling.JobResult.Tests/JobResult.fs b/tests/FsToolkit.ErrorHandling.JobResult.Tests/JobResult.fs index 793d49d4..8c5fed21 100644 --- a/tests/FsToolkit.ErrorHandling.JobResult.Tests/JobResult.fs +++ b/tests/FsToolkit.ErrorHandling.JobResult.Tests/JobResult.fs @@ -284,6 +284,22 @@ let requireSomeTests = |> Expect.hasJobErrorValueSync err ] +[] +let requireSomeWithTests = + testList "JobResult.requireSomeWith Tests" [ + testCase "requireSomeWith happy path" + <| fun _ -> + toJob (Some 42) + |> JobResult.requireSomeWith (fun () -> err) + |> Expect.hasJobOkValueSync 42 + + testCase "requireSomeWith error path" + <| fun _ -> + toJob None + |> JobResult.requireSomeWith (fun () -> err) + |> Expect.hasJobErrorValueSync err + ] + [] let requireNoneTests = testList "JobResult.requireNone Tests" [ diff --git a/tests/FsToolkit.ErrorHandling.TaskResult.Tests/TaskResult.fs b/tests/FsToolkit.ErrorHandling.TaskResult.Tests/TaskResult.fs index ae36e625..e7e4975d 100644 --- a/tests/FsToolkit.ErrorHandling.TaskResult.Tests/TaskResult.fs +++ b/tests/FsToolkit.ErrorHandling.TaskResult.Tests/TaskResult.fs @@ -289,6 +289,22 @@ let requireSomeTests = |> Expect.hasTaskErrorValueSync err ] +[] +let requireSomeWithTests = + testList "TaskResult.requireSomeWith Tests" [ + testCase "requireSomeWith happy path" + <| fun _ -> + toTask (Some 42) + |> TaskResult.requireSomeWith (fun () -> err) + |> Expect.hasTaskOkValueSync 42 + + testCase "requireSomeWith error path" + <| fun _ -> + toTask None + |> TaskResult.requireSomeWith (fun () -> err) + |> Expect.hasTaskErrorValueSync err + ] + [] let requireNoneTests = testList "TaskResult.requireNone Tests" [ diff --git a/tests/FsToolkit.ErrorHandling.Tests/AsyncResult.fs b/tests/FsToolkit.ErrorHandling.Tests/AsyncResult.fs index be85a5e2..73e4ebd4 100644 --- a/tests/FsToolkit.ErrorHandling.Tests/AsyncResult.fs +++ b/tests/FsToolkit.ErrorHandling.Tests/AsyncResult.fs @@ -298,6 +298,18 @@ let requireSomeTests = |> Expect.hasAsyncErrorValue err) ] +let requireSomeWithTests = + testList "AsyncResult.requireSomeWith Tests" [ + testCaseAsync "requireSomeWith happy path" + <| (toAsync (Some 42) + |> AsyncResult.requireSomeWith (fun () -> err) + |> Expect.hasAsyncOkValue 42) + + testCaseAsync "requireSomeWith error path" + <| (toAsync None + |> AsyncResult.requireSomeWith (fun () -> err) + |> Expect.hasAsyncErrorValue err) + ] let requireNoneTests = testList "AsyncResult.requireNone Tests" [ @@ -1006,6 +1018,7 @@ let allTests = requireTrueTests requireFalseTests requireSomeTests + requireSomeWithTests requireNoneTests requireValueSomeTests requireValueNoneTests diff --git a/tests/FsToolkit.ErrorHandling.Tests/Result.fs b/tests/FsToolkit.ErrorHandling.Tests/Result.fs index acec025c..4fd4414f 100644 --- a/tests/FsToolkit.ErrorHandling.Tests/Result.fs +++ b/tests/FsToolkit.ErrorHandling.Tests/Result.fs @@ -332,6 +332,19 @@ let requireSomeTests = |> Expect.hasErrorValue err ] +let requireSomeWithTests = + testList "requireSomeWith Tests" [ + testCase "requireSomeWith happy path" + <| fun _ -> + Result.requireSomeWith (fun () -> err) (Some 42) + |> Expect.hasOkValue 42 + + testCase "requireSomeWith error path" + <| fun _ -> + Result.requireSomeWith (fun () -> err) None + |> Expect.hasErrorValue err + ] + let requireNotNullTests = testList "requireNotNull Tests" [ testCase "requireNotNull happy path" @@ -914,6 +927,7 @@ let allTests = requireTrueTests requireFalseTests requireSomeTests + requireSomeWithTests requireNoneTests requireValueSomeTests requireValueNoneTests From 99fca2fe30501f88c439bc687f1684f25a0383a1 Mon Sep 17 00:00:00 2001 From: Joseph Price Date: Sat, 11 Jan 2025 12:01:30 -0500 Subject: [PATCH 2/5] Update src/FsToolkit.ErrorHandling/TaskResult.fs Co-authored-by: Jimmy Byrd --- src/FsToolkit.ErrorHandling/TaskResult.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/FsToolkit.ErrorHandling/TaskResult.fs b/src/FsToolkit.ErrorHandling/TaskResult.fs index 28f0336f..f3c93bf5 100644 --- a/src/FsToolkit.ErrorHandling/TaskResult.fs +++ b/src/FsToolkit.ErrorHandling/TaskResult.fs @@ -109,9 +109,9 @@ module TaskResult = option |> Task.map (Result.requireSome error) - let inline requireSomeWith error option = + let inline requireSomeWith ifErrorThunk option = option - |> Task.map (Result.requireSomeWith error) + |> Task.map (Result.requireSomeWith ifErrorThunk) // Converts an task-wrapped Option to a Result, using the given error if Some. let inline requireNone error option = From f5a1c85b98771edc20daacfe7e7fea9ec95a98aa Mon Sep 17 00:00:00 2001 From: Joseph Price Date: Sat, 11 Jan 2025 12:01:37 -0500 Subject: [PATCH 3/5] Update src/FsToolkit.ErrorHandling.JobResult/JobResult.fs Co-authored-by: Jimmy Byrd --- src/FsToolkit.ErrorHandling.JobResult/JobResult.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/FsToolkit.ErrorHandling.JobResult/JobResult.fs b/src/FsToolkit.ErrorHandling.JobResult/JobResult.fs index f8c5d905..b97f2410 100644 --- a/src/FsToolkit.ErrorHandling.JobResult/JobResult.fs +++ b/src/FsToolkit.ErrorHandling.JobResult/JobResult.fs @@ -124,9 +124,9 @@ module JobResult = option |> Job.map (Result.requireSome error) - let inline requireSomeWith error option = + let inline requireSomeWith ifErrorThunk option = option - |> Job.map (Result.requireSomeWith error) + |> Job.map (Result.requireSomeWith ifErrorThunk) // Converts an job-wrapped Option to a Result, using the given error if Some. let inline requireNone error option = From 4c12451d734c47ee2c561d87d02d0d301fc42422 Mon Sep 17 00:00:00 2001 From: Joseph Price Date: Sat, 11 Jan 2025 14:18:42 -0500 Subject: [PATCH 4/5] add requireSomeWith doc --- gitbook/result/requireFunctions.md | 8 ++++---- src/FsToolkit.ErrorHandling/Result.fs | 8 ++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/gitbook/result/requireFunctions.md b/gitbook/result/requireFunctions.md index 31b152dd..3c642edc 100644 --- a/gitbook/result/requireFunctions.md +++ b/gitbook/result/requireFunctions.md @@ -64,9 +64,9 @@ let result : Result = // Error "Value must be false" ``` -## requireSome +## requireSomeWith -Converts an Option to a Result, using the given error if None. +Converts an Option to a Result, using the given function to supply an error if None. ### Function Signature @@ -81,7 +81,7 @@ Converts an Option to a Result, using the given error if None. ```fsharp let result : Result = Some 1 - |> Result.requireSome "Value must be Some" + |> Result.requireSomeWith (fun () -> "Value must be Some") // Ok () ``` @@ -91,7 +91,7 @@ let result : Result = ```fsharp let result : Result = None - |> Result.requireSome "Value must be Some" + |> Result.requireSomeWith (fun () -> "Value must be Some") // Error "Value must be Some" ``` diff --git a/src/FsToolkit.ErrorHandling/Result.fs b/src/FsToolkit.ErrorHandling/Result.fs index 3ccf7b37..d772746c 100644 --- a/src/FsToolkit.ErrorHandling/Result.fs +++ b/src/FsToolkit.ErrorHandling/Result.fs @@ -307,6 +307,14 @@ module Result = | Some x -> Ok x | None -> Error error + /// + /// Returns the contained value if Some, otherwise evaluates and returns the value. + /// + /// Documentation is found here: https://demystifyfp.gitbook.io/fstoolkit-errorhandling/fstoolkit.errorhandling/result/others#requireSomeWith + /// + /// The function to evaluate if the result is Error. + /// The input result. + /// The contained value if Some, otherwise the result of evaluating . let inline requireSomeWith (ifErrorThunk: unit -> 'error) (option: 'ok option) From 2b8c474c53db89117c79483ec85794e9f3f81645 Mon Sep 17 00:00:00 2001 From: Joseph Price Date: Sat, 11 Jan 2025 14:21:58 -0500 Subject: [PATCH 5/5] start adding docs --- gitbook/result/requireFunctions.md | 32 +++++++++++++++++++++++++++ src/FsToolkit.ErrorHandling/Result.fs | 4 ++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/gitbook/result/requireFunctions.md b/gitbook/result/requireFunctions.md index 3c642edc..a829fb03 100644 --- a/gitbook/result/requireFunctions.md +++ b/gitbook/result/requireFunctions.md @@ -64,6 +64,38 @@ let result : Result = // Error "Value must be false" ``` +## requireSome + +Converts an Option to a Result, using the given function to supply an error if None. + +### Function Signature + +```fsharp +'a -> 'b option -> Result<'b, 'a> +``` + +### Examples + +#### Example 1 + +```fsharp +let result : Result = + Some 1 + |> Result.requireSome "Value must be Some" + +// Ok () +``` + +#### Example 2 + +```fsharp +let result : Result = + None + |> Result.requireSome "Value must be Some" + +// Error "Value must be Some" +``` + ## requireSomeWith Converts an Option to a Result, using the given function to supply an error if None. diff --git a/src/FsToolkit.ErrorHandling/Result.fs b/src/FsToolkit.ErrorHandling/Result.fs index d772746c..52316375 100644 --- a/src/FsToolkit.ErrorHandling/Result.fs +++ b/src/FsToolkit.ErrorHandling/Result.fs @@ -312,8 +312,8 @@ module Result = /// /// Documentation is found here: https://demystifyfp.gitbook.io/fstoolkit-errorhandling/fstoolkit.errorhandling/result/others#requireSomeWith /// - /// The function to evaluate if the result is Error. - /// The input result. + /// The function to evaluate if the result is None. + /// The input option. /// The contained value if Some, otherwise the result of evaluating . let inline requireSomeWith (ifErrorThunk: unit -> 'error)