Skip to content

Commit 8f6067c

Browse files
JmaharmanTheAngryByrd
authored andcommitted
Converted JobOptionCE to use Source overload and added Job/Task/Async
1 parent 993f738 commit 8f6067c

File tree

2 files changed

+79
-39
lines changed

2 files changed

+79
-39
lines changed

src/FsToolkit.ErrorHandling.JobResult/JobOptionCE.fs

Lines changed: 45 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -12,31 +12,11 @@ module JobOptionCE =
1212
member __.Return (value: 'T) : Job<Option<_>> =
1313
job.Return <| option.Return value
1414

15-
member __.ReturnFrom
16-
(asyncResult: Async<Option<_>>)
17-
: Job<Option<_>> =
18-
asyncResult |> Job.fromAsync
19-
2015
member __.ReturnFrom
2116
(jobResult: Job<Option<_>>)
2217
: Job<Option<_>> =
2318
jobResult
2419

25-
member __.ReturnFrom
26-
(taskResult: Task<Option<_>>)
27-
: Job<Option<_>> =
28-
Job.awaitTask taskResult
29-
30-
member __.ReturnFrom
31-
(taskResult: unit -> Task<Option<_>>)
32-
: Job<Option<_>> =
33-
Job.fromTask taskResult
34-
35-
member __.ReturnFrom
36-
(result: Option<_>)
37-
: Job<Option<_>> =
38-
job.Return result
39-
4020
member __.Zero () : Job<Option<_>> =
4121
job.Return <| option.Zero ()
4222

@@ -50,29 +30,13 @@ module JobOptionCE =
5030
| Some x -> return! binder x
5131
| None -> return None
5232
}
53-
member this.Bind
54-
(asyncResult: Async<Option<_>>,
55-
binder: 'T -> Job<Option<_>>)
56-
: Job<Option<_>> =
57-
this.Bind(Job.fromAsync asyncResult, binder)
58-
59-
member this.Bind
60-
(taskResult: Task<Option<_>>,
61-
binder: 'T -> Job<Option<_>>)
62-
: Job<Option<_>> =
63-
this.Bind(Job.awaitTask taskResult, binder)
6433

6534
member this.Bind
6635
(taskResult: unit -> Task<Option<_>>,
6736
binder: 'T -> Job<Option<_>>)
6837
: Job<Option<_>> =
6938
this.Bind(Job.fromTask taskResult, binder)
7039

71-
member this.Bind
72-
(result: Option<_>, binder: 'T -> Job<Option<_>>)
73-
: Job<Option<_>> =
74-
this.Bind(this.ReturnFrom result, binder)
75-
7640
member __.Delay
7741
(generator: unit -> Job<Option<_>>)
7842
: Job<Option<_>> =
@@ -127,4 +91,49 @@ module JobOptionCE =
12791
this.While(enum.MoveNext,
12892
this.Delay(fun () -> binder enum.Current)))
12993

94+
/// <summary>
95+
/// Method lets us transform data types into our internal representation. This is the identity method to recognize the self type.
96+
///
97+
/// See https://stackoverflow.com/questions/35286541/why-would-you-use-builder-source-in-a-custom-computation-expression-builder
98+
/// </summary>
99+
member inline _.Source(job : Job<Option<_>>) : Job<Option<_>> = job
100+
101+
/// <summary>
102+
/// Method lets us transform data types into our internal representation.
103+
/// </summary>
104+
member inline _.Source(async : Async<Option<_>>) : Job<Option<_>> = async |> Job.fromAsync
105+
106+
/// <summary>
107+
/// Method lets us transform data types into our internal representation.
108+
/// </summary>
109+
member inline _.Source(task : Task<Option<_>>) : Job<Option<_>> = task |> Job.awaitTask
110+
130111
let jobOption = JobOptionBuilder()
112+
113+
[<AutoOpen>]
114+
// Having members as extensions gives them lower priority in
115+
// overload resolution and allows skipping more type annotations.
116+
module JobOptionCEExtensions =
117+
118+
type JobOptionBuilder with
119+
/// <summary>
120+
/// Needed to allow `for..in` and `for..do` functionality
121+
/// </summary>
122+
member inline __.Source(s: #seq<_>) = s
123+
124+
/// <summary>
125+
/// Method lets us transform data types into our internal representation.
126+
/// </summary>
127+
member inline __.Source(r: Option<'t>) = Job.singleton r
128+
/// <summary>
129+
/// Method lets us transform data types into our internal representation.
130+
/// </summary>
131+
member inline __.Source(a: Job<'t>) = a |> Job.map Some
132+
/// <summary>
133+
/// Method lets us transform data types into our internal representation.
134+
/// </summary>
135+
member inline __.Source(a: Async<'t>) = a |> Job.fromAsync |> Job.map Some
136+
/// <summary>
137+
/// Method lets us transform data types into our internal representation.
138+
/// </summary>
139+
member inline __.Source(a: Task<'t>) = a |> Job.awaitTask |> Job.map Some

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

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,21 @@ let ceTests =
3333
}
3434
Expect.equal actual expected "Should return value wrapped in option"
3535
}
36-
36+
3737
testCaseJob "ReturnFrom Async None" <| job {
3838
let expected = None
3939
let! actual = jobOption {
4040
return! (async.Return None)
4141
}
4242
Expect.equal actual expected "Should return value wrapped in option"
4343
}
44+
testCaseJob "ReturnFrom Async" <| job {
45+
let expected = Some 42
46+
let! actual = jobOption {
47+
return! (async.Return 42)
48+
}
49+
Expect.equal actual expected "Should return value wrapped in option"
50+
}
4451

4552
testCaseJob "ReturnFrom Task None" <| job {
4653
let expected = None
@@ -51,9 +58,9 @@ let ceTests =
5158
}
5259

5360
testCaseJob "ReturnFrom Job None" <| job {
54-
let expected = None
61+
let expected = Some 42
5562
let! actual = jobOption {
56-
return! (Job.result None)
63+
return! (Job.result (Some 42))
5764
}
5865
Expect.equal actual expected "Should return value wrapped in option"
5966
}
@@ -82,6 +89,14 @@ let ceTests =
8289
}
8390
Expect.equal actual expected "Should bind value wrapped in option"
8491
}
92+
testCaseJob "Bind Async" <| job {
93+
let expected = Some 42
94+
let! actual = jobOption {
95+
let! value = async.Return 42
96+
return value
97+
}
98+
Expect.equal actual expected "Should bind value wrapped in option"
99+
}
85100
testCaseJob "Bind Task None" <| job {
86101
let expected = None
87102
let! actual = jobOption {
@@ -90,6 +105,14 @@ let ceTests =
90105
}
91106
Expect.equal actual expected "Should bind value wrapped in option"
92107
}
108+
testCaseJob "Bind Task" <| job {
109+
let expected = Some 42
110+
let! actual = jobOption {
111+
let! value = Task.FromResult 42
112+
return value
113+
}
114+
Expect.equal actual expected "Should bind value wrapped in option"
115+
}
93116

94117
testCaseJob "Bind Job None" <| job {
95118
let expected = None
@@ -99,6 +122,14 @@ let ceTests =
99122
}
100123
Expect.equal actual expected "Should bind value wrapped in option"
101124
}
125+
testCaseJob "Bind Job" <| job {
126+
let expected = Some 42
127+
let! actual = jobOption {
128+
let! value = Job.result 42
129+
return value
130+
}
131+
Expect.equal actual expected "Should bind value wrapped in option"
132+
}
102133

103134
testCaseJob "Zero/Combine/Delay/Run" <| job {
104135
let data = 42

0 commit comments

Comments
 (0)