Skip to content

Commit 224955f

Browse files
authored
Adds AsyncOption, TaskOption, JobOption helpers
* TaskOption Working on #77 -> AsyncOption.map * TaskOption Wirking on #77 -> AsyncOption.Bind * TaskOption Working on #77 -> AsyncOption.apply * TaskOption Working on #77 -> AsyncOption.retn * TaskOption Working on #77 -> AsyncOption basic Operators * TaskOption Working on #77 -> TaskOption basic Functions * TaskOption Fixes #77 -> JobOption * TaskOption Fixes #77 -> Add AsyncOption Tests to execution
1 parent 40c152a commit 224955f

File tree

19 files changed

+495
-2
lines changed

19 files changed

+495
-2
lines changed

src/FsToolkit.ErrorHandling.JobResult/FsToolkit.ErrorHandling.JobResult.fsproj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@
2121
<Compile Include="Job.fs" />
2222
<Compile Include="JobResult.fs" />
2323
<Compile Include="JobResultCE.fs" />
24-
<Compile Include="JobOptionCE.fs" />
2524
<Compile Include="JobResultOp.fs" />
25+
<Compile Include="JobOption.fs" />
26+
<Compile Include="JobOptionCE.fs" />
27+
<Compile Include="JobOptionOp.fs" />
2628
<Compile Include="List.fs" />
2729
<Compile Include="JobResultOption.fs" />
2830
<Compile Include="JobResultOptionCE.fs" />
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
namespace FsToolkit.ErrorHandling
2+
3+
open Hopac
4+
open Hopac.Infixes
5+
6+
[<RequireQualifiedAccess>]
7+
module JobOption =
8+
9+
let inline map f ar =
10+
Job.map (Option.map f) ar
11+
12+
let bind f (ar: Job<_>) = job {
13+
let! opt = ar
14+
let t =
15+
match opt with
16+
| Some x -> f x
17+
| None -> job { return None }
18+
return! t
19+
}
20+
21+
let retn x =
22+
job { return Some x }
23+
24+
let apply f x =
25+
bind (fun f' ->
26+
bind (fun x' -> retn (f' x')) x) f
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace FsToolkit.ErrorHandling.Operator.JobOption
2+
3+
open FsToolkit.ErrorHandling
4+
5+
[<AutoOpen>]
6+
module JobOption =
7+
8+
let inline (<!>) f x = JobOption.map f x
9+
let inline (<*>) f x = JobOption.apply f x
10+
let inline (>>=) x f = JobOption.bind f x

src/FsToolkit.ErrorHandling.TaskResult/FsToolkit.ErrorHandling.TaskResult.fsproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
<Compile Include="TaskResultCE.fs" />
2525
<Compile Include="TaskResultOp.fs" />
2626
<Compile Include="List.fs" />
27+
<Compile Include="TaskOption.fs" />
2728
<Compile Include="TaskOptionCE.fs" />
29+
<Compile Include="TaskOptionOp.fs" />
2830
<Compile Include="TaskResultOption.fs" />
2931
<Compile Include="TaskResultOptionCE.fs" />
3032
<Compile Include="TaskResultOptionOp.fs" />
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
namespace FsToolkit.ErrorHandling
2+
3+
open System.Threading.Tasks
4+
open FSharp.Control.Tasks.V2.ContextInsensitive
5+
6+
[<RequireQualifiedAccess>]
7+
module TaskOption =
8+
9+
let inline map f ar =
10+
Task.map (Option.map f) ar
11+
12+
let bind f (ar: Task<_>) =
13+
task {
14+
let! opt = ar
15+
let t =
16+
match opt with
17+
| Some x -> f x
18+
| None -> task { return None }
19+
return! t
20+
}
21+
22+
let retn x =
23+
task { return Some x }
24+
25+
let apply f x =
26+
bind (fun f' ->
27+
bind (fun x' -> retn (f' x')) x) f
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace FsToolkit.ErrorHandling.Operator.TaskOption
2+
3+
open FsToolkit.ErrorHandling
4+
5+
[<AutoOpen>]
6+
module TaskOption =
7+
8+
let inline (<!>) f x = TaskOption.map f x
9+
let inline (<*>) f x = TaskOption.apply f x
10+
let inline (>>=) x f = TaskOption.bind f x
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
namespace FsToolkit.ErrorHandling
2+
3+
open System.Threading.Tasks
4+
5+
[<RequireQualifiedAccess>]
6+
module AsyncOption =
7+
8+
let inline map f ar =
9+
Async.map (Option.map f) ar
10+
11+
let bind f ar = async {
12+
let! opt = ar
13+
let t =
14+
match opt with
15+
| Some x -> f x
16+
| None -> async { return None }
17+
return! t
18+
}
19+
20+
let retn x =
21+
async { return Some x }
22+
23+
let apply f x =
24+
bind (fun f' ->
25+
bind (fun x' -> retn (f' x')) x) f
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace FsToolkit.ErrorHandling.Operator.AsyncOption
2+
3+
open FsToolkit.ErrorHandling
4+
5+
[<AutoOpen>]
6+
module AsyncOption =
7+
8+
let inline (<!>) f x = AsyncOption.map f x
9+
let inline (<*>) f x = AsyncOption.apply f x
10+
let inline (>>=) x f = AsyncOption.bind f x

src/FsToolkit.ErrorHandling/FsToolkit.ErrorHandling.fsproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@
3737
<Compile Include="ValidationCE.fs" />
3838
<Compile Include="Option.fs" />
3939
<Compile Include="OptionCE.fs" />
40+
<Compile Include="AsyncOption.fs" />
4041
<Compile Include="AsyncOptionCE.fs" />
42+
<Compile Include="AsyncOptionOp.fs" />
4143
<Compile Include="List.fs" />
4244
<None Include="Script.fsx" />
4345
</ItemGroup>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
namespace Expects.JobOption
2+
3+
module Expect =
4+
open Expecto
5+
open Hopac
6+
7+
let hasJobValue v jobX =
8+
let x = run jobX
9+
if v = x then
10+
()
11+
else Tests.failtestf "Expected %A, was %A." v x
12+
13+
14+
let hasJobSomeValue v jobX =
15+
let x = run jobX
16+
TestHelpers.Expect.hasSomeValue v x
17+
18+
19+
let hasJobNoneValue jobX =
20+
let x = run jobX
21+
TestHelpers.Expect.hasNoneValue x

tests/FsToolkit.ErrorHandling.JobResult.Tests/FsToolkit.ErrorHandling.JobResult.Tests.fsproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515
<Compile Include="../FsToolkit.ErrorHandling.Tests/SampleDomain.fs" />
1616
<Compile Include="../FsToolkit.ErrorHandling.Tests/TestData.fs" />
1717
<Compile Include="../FsToolkit.ErrorHandling.Tests/Expect.fs" />
18+
<Compile Include="Expect.JobOption.fs" />
1819
<Compile Include="Expect.JobResult.fs" />
1920
<Compile Include="Result.fs" />
2021
<Compile Include="JobResult.fs" />
22+
<Compile Include="JobOption.fs" />
2123
<Compile Include="JobOptionCE.fs" />
2224
<Compile Include="JobResultCE.fs" />
2325
<Compile Include="List.fs" />
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
module JobOptionTests
2+
3+
4+
open Expecto
5+
open Expects.JobOption
6+
open SampleDomain
7+
open TestData
8+
open TestHelpers
9+
open FsToolkit.ErrorHandling
10+
open FsToolkit.ErrorHandling.Operator.JobOption
11+
open System
12+
open Hopac
13+
14+
let runJobSync = run
15+
let createPostSome = createPostSome >> Job.fromAsync
16+
let getFollowersSome = getFollowersSome >> Job.fromAsync
17+
let allowedToPostOptional = allowedToPostOptional >> Job.fromAsync
18+
19+
let mapTests =
20+
testList "JobOption.map Tests" [
21+
testCase "map with Job(Some x)" <| fun _ ->
22+
Job.singleton (Some validTweet)
23+
|> JobOption.map remainingCharacters
24+
|> Expect.hasJobSomeValue 267
25+
26+
testCase "map with Job(None)" <| fun _ ->
27+
Job.singleton (None)
28+
|> JobOption.map remainingCharacters
29+
|> Expect.hasJobNoneValue
30+
]
31+
32+
let bindTests =
33+
testList "JobOption.bind tests" [
34+
testCase "bind with Job(Some x)" <| fun _ ->
35+
allowedToPostOptional sampleUserId
36+
|> JobOption.bind (fun isAllowed -> job {
37+
if isAllowed then
38+
return! createPostSome validCreatePostRequest
39+
else
40+
return None })
41+
|> Expect.hasJobSomeValue (PostId newPostId)
42+
43+
testCase "bind with Job(None)" <| fun _ ->
44+
allowedToPostOptional (UserId (Guid.NewGuid()))
45+
|> JobOption.bind (fun isAllowed -> job {return Some isAllowed})
46+
|> Expect.hasJobNoneValue
47+
48+
testCase "bind with Job(Ok x) that returns Job (None)" <| fun _ ->
49+
allowedToPostOptional sampleUserId
50+
|> JobOption.bind (fun _ -> job {
51+
return None
52+
})
53+
|> Expect.hasJobNoneValue
54+
]
55+
56+
let applyTests =
57+
testList "JobOption.apply Tests" [
58+
testCase "apply with Job(Some x)" <| fun _ ->
59+
Job.singleton (Some validTweet)
60+
|> JobOption.apply (Job.singleton (Some remainingCharacters))
61+
|> Expect.hasJobSomeValue (267)
62+
63+
testCase "apply with Job(None)" <| fun _ ->
64+
Job.singleton None
65+
|> JobOption.apply (Job.singleton (Some remainingCharacters))
66+
|> Expect.hasJobNoneValue
67+
]
68+
69+
let retnTests =
70+
testList "JobOption.retn Tests" [
71+
testCase "retn with x" <| fun _ ->
72+
JobOption.retn 267
73+
|> Expect.hasJobSomeValue (267)
74+
]
75+
76+
let jobOptionOperatorTests =
77+
testList "JobOption Operators Tests" [
78+
testCase "map & apply operators" <| fun _ ->
79+
let getFollowersResult = getFollowersSome sampleUserId
80+
let createPostResult = createPostSome validCreatePostRequest
81+
newPostRequest <!> getFollowersResult <*> createPostResult
82+
|> Expect.hasJobSomeValue {NewPostId = PostId newPostId; UserIds = followerIds}
83+
84+
testCase "bind operator" <| fun _ ->
85+
allowedToPostOptional sampleUserId
86+
>>= (fun isAllowed ->
87+
if isAllowed then
88+
createPostSome validCreatePostRequest
89+
else
90+
Job.singleton None)
91+
|> Expect.hasJobSomeValue (PostId newPostId)
92+
]
93+
94+
let allTests = testList "Job Option Tests" [
95+
mapTests
96+
bindTests
97+
applyTests
98+
retnTests
99+
jobOptionOperatorTests
100+
]

tests/FsToolkit.ErrorHandling.TaskResult.Tests/FsToolkit.ErrorHandling.TaskResult.Tests.fsproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
<Compile Include="Result.fs" />
2020
<Compile Include="TaskResult.fs" />
2121
<Compile Include="TaskResultCE.fs" />
22+
<Compile Include="TaskOption.fs" />
2223
<Compile Include="TaskOptionCE.fs" />
2324
<Compile Include="List.fs" />
2425
<Compile Include="TaskResultOption.fs" />

0 commit comments

Comments
 (0)