-
Notifications
You must be signed in to change notification settings - Fork 894
/
async_result.ex
143 lines (107 loc) · 3.4 KB
/
async_result.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
defmodule Phoenix.LiveView.AsyncResult do
@moduledoc ~S'''
Provides a datastructure for tracking the state of an async assign.
See the `Async Operations` section of the `Phoenix.LiveView` docs for more information.
## Fields
* `:ok?` - When true, indicates the `:result` has been set successfully at least once.
* `:loading` - The current loading state
* `:failed` - The current failed state
* `:result` - The successful result of the async task
'''
defstruct ok?: false,
loading: nil,
failed: nil,
result: nil
alias Phoenix.LiveView.AsyncResult
@doc """
Creates an async result in loading state.
## Examples
iex> result = AsyncResult.loading()
iex> result.loading
true
iex> result.ok?
false
"""
def loading do
%AsyncResult{loading: true}
end
@doc """
Updates the loading state.
When loading, the failed state will be reset to `nil`.
## Examples
iex> result = AsyncResult.loading(%{my: :loading_state})
iex> result.loading
%{my: :loading_state}
iex> result = AsyncResult.loading(result)
iex> result.loading
true
"""
def loading(%AsyncResult{} = result) do
%AsyncResult{result | loading: true, failed: nil}
end
def loading(loading_state) do
%AsyncResult{loading: loading_state, failed: nil}
end
@doc """
Updates the loading state of an existing `async_result`.
When loading, the failed state will be reset to `nil`.
If the result was previously `ok?`, both `result` and
`loading` will be set.
## Examples
iex> result = AsyncResult.loading()
iex> result = AsyncResult.loading(result, %{my: :other_state})
iex> result.loading
%{my: :other_state}
"""
def loading(%AsyncResult{} = result, loading_state) do
%AsyncResult{result | loading: loading_state, failed: nil}
end
@doc """
Updates the failed state.
When failed, the loading state will be reset to `nil`.
If the result was previously `ok?`, both `result` and
`failed` will be set.
## Examples
iex> result = AsyncResult.loading()
iex> result = AsyncResult.failed(result, {:exit, :boom})
iex> result.failed
{:exit, :boom}
iex> result.loading
nil
"""
def failed(%AsyncResult{} = result, reason) do
%AsyncResult{result | failed: reason, loading: nil}
end
@doc """
Creates a successful result.
The `:ok?` field will also be set to `true` to indicate this result has
completed successfully at least once, regardless of future state changes.
### Examples
iex> result = AsyncResult.ok("initial result")
iex> result.ok?
true
iex> result.result
"initial result"
"""
def ok(value) do
%AsyncResult{failed: nil, loading: nil, ok?: true, result: value}
end
@doc """
Updates the successful result.
The `:ok?` field will also be set to `true` to indicate this result has
completed successfully at least once, regardless of future state changes.
When ok'd, the loading and failed state will be reset to `nil`.
## Examples
iex> result = AsyncResult.loading()
iex> result = AsyncResult.ok(result, "completed")
iex> result.ok?
true
iex> result.result
"completed"
iex> result.loading
nil
"""
def ok(%AsyncResult{} = result, value) do
%AsyncResult{result | failed: nil, loading: nil, ok?: true, result: value}
end
end