@typed/async-data 0.3.2 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/TypeId/package.json +6 -0
- package/dist/cjs/AsyncData.js +88 -24
- package/dist/cjs/AsyncData.js.map +1 -1
- package/dist/cjs/Schema.js +308 -143
- package/dist/cjs/Schema.js.map +1 -1
- package/dist/cjs/TypeId.js +14 -0
- package/dist/cjs/TypeId.js.map +1 -0
- package/dist/cjs/internal/async-data.js +47 -55
- package/dist/cjs/internal/async-data.js.map +1 -1
- package/dist/cjs/internal/tag.js +2 -1
- package/dist/cjs/internal/tag.js.map +1 -1
- package/dist/dts/AsyncData.d.ts +52 -9
- package/dist/dts/AsyncData.d.ts.map +1 -1
- package/dist/dts/Schema.d.ts +23 -82
- package/dist/dts/Schema.d.ts.map +1 -1
- package/dist/dts/TypeId.d.ts +12 -0
- package/dist/dts/TypeId.d.ts.map +1 -0
- package/dist/dts/internal/async-data.d.ts +23 -22
- package/dist/dts/internal/async-data.d.ts.map +1 -1
- package/dist/dts/internal/tag.d.ts +1 -0
- package/dist/dts/internal/tag.d.ts.map +1 -1
- package/dist/esm/AsyncData.js +92 -25
- package/dist/esm/AsyncData.js.map +1 -1
- package/dist/esm/Schema.js +294 -142
- package/dist/esm/Schema.js.map +1 -1
- package/dist/esm/TypeId.js +8 -0
- package/dist/esm/TypeId.js.map +1 -0
- package/dist/esm/internal/async-data.js +51 -56
- package/dist/esm/internal/async-data.js.map +1 -1
- package/dist/esm/internal/tag.js +1 -0
- package/dist/esm/internal/tag.js.map +1 -1
- package/package.json +11 -3
- package/src/AsyncData.ts +148 -32
- package/src/Schema.ts +427 -280
- package/src/TypeId.ts +13 -0
- package/src/internal/async-data.ts +65 -54
- package/src/internal/tag.ts +2 -0
|
@@ -1,22 +1,20 @@
|
|
|
1
1
|
// Internal
|
|
2
|
-
import * as Cause from "effect/Cause";
|
|
3
2
|
import * as Effect from "effect/Effect";
|
|
4
3
|
import * as Effectable from "effect/Effectable";
|
|
5
4
|
import * as Equal from "effect/Equal";
|
|
6
5
|
import { constant, pipe } from "effect/Function";
|
|
7
6
|
import * as Hash from "effect/Hash";
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import { FAILURE_TAG,
|
|
7
|
+
import { hasProperty } from "effect/Predicate";
|
|
8
|
+
import { AsyncDataTypeId } from "../TypeId.js";
|
|
9
|
+
import { FAILURE_TAG, OPTIMISTIC_TAG, SUCCESS_TAG } from "./tag.js";
|
|
10
|
+
// @ts-expect-error
|
|
11
11
|
export class FailureImpl extends Effectable.Class {
|
|
12
12
|
cause;
|
|
13
13
|
timestamp;
|
|
14
14
|
refreshing;
|
|
15
|
-
|
|
15
|
+
[AsyncDataTypeId] = AsyncDataTypeId;
|
|
16
|
+
_tag = FAILURE_TAG;
|
|
16
17
|
commit;
|
|
17
|
-
[Unify.typeSymbol];
|
|
18
|
-
[Unify.unifySymbol];
|
|
19
|
-
[Unify.ignoreSymbol];
|
|
20
18
|
constructor(cause, timestamp, refreshing) {
|
|
21
19
|
super();
|
|
22
20
|
this.cause = cause;
|
|
@@ -24,25 +22,28 @@ export class FailureImpl extends Effectable.Class {
|
|
|
24
22
|
this.refreshing = refreshing;
|
|
25
23
|
this.commit = constant(Effect.failCause(cause));
|
|
26
24
|
}
|
|
27
|
-
[Equal.symbol]
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
[Equal.symbol](that) {
|
|
26
|
+
if (this === that)
|
|
27
|
+
return true;
|
|
28
|
+
if (!isAsyncData(that) || that._tag !== FAILURE_TAG)
|
|
29
|
+
return false;
|
|
30
|
+
console.log(Equal.equals(this.cause, that.cause), this.timestamp === that.timestamp, Equal.equals(this.refreshing, that.refreshing));
|
|
31
|
+
return Equal.equals(this.cause, that.cause)
|
|
32
|
+
&& this.timestamp === that.timestamp
|
|
31
33
|
&& Equal.equals(this.refreshing, that.refreshing);
|
|
32
|
-
}
|
|
33
|
-
[Hash.symbol]
|
|
34
|
-
return pipe(Hash.string(this._tag), Hash.combine(Hash.hash(this.cause)), Hash.combine(Hash.hash(this.refreshing)));
|
|
35
|
-
}
|
|
34
|
+
}
|
|
35
|
+
[Hash.symbol]() {
|
|
36
|
+
return pipe(Hash.string(this._tag), Hash.combine(Hash.hash(this.cause)), Hash.combine(Hash.hash(this.timestamp)), Hash.combine(Hash.hash(this.refreshing)));
|
|
37
|
+
}
|
|
36
38
|
}
|
|
39
|
+
// @ts-expect-error
|
|
37
40
|
export class SuccessImpl extends Effectable.Class {
|
|
38
41
|
value;
|
|
39
42
|
timestamp;
|
|
40
43
|
refreshing;
|
|
41
|
-
|
|
44
|
+
[AsyncDataTypeId] = AsyncDataTypeId;
|
|
45
|
+
_tag = SUCCESS_TAG;
|
|
42
46
|
commit;
|
|
43
|
-
[Unify.typeSymbol];
|
|
44
|
-
[Unify.unifySymbol];
|
|
45
|
-
[Unify.ignoreSymbol];
|
|
46
47
|
constructor(value, timestamp, refreshing) {
|
|
47
48
|
super();
|
|
48
49
|
this.value = value;
|
|
@@ -50,48 +51,42 @@ export class SuccessImpl extends Effectable.Class {
|
|
|
50
51
|
this.refreshing = refreshing;
|
|
51
52
|
this.commit = constant(Effect.succeed(value));
|
|
52
53
|
}
|
|
53
|
-
[Equal.symbol]
|
|
54
|
-
return isAsyncData(that) && that._tag ===
|
|
54
|
+
[Equal.symbol](that) {
|
|
55
|
+
return isAsyncData(that) && that._tag === SUCCESS_TAG
|
|
55
56
|
&& Equal.equals(this.value, that.value)
|
|
56
57
|
&& Equal.equals(this.timestamp, that.timestamp)
|
|
57
58
|
&& Equal.equals(this.refreshing, that.refreshing);
|
|
58
|
-
};
|
|
59
|
-
[Hash.symbol] = () => {
|
|
60
|
-
return pipe(Hash.string(this._tag), Hash.combine(Hash.hash(this.value)), Hash.combine(Hash.hash(this.refreshing)));
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
export function hasDataOptions(u) {
|
|
64
|
-
if ("timestamp" in u && "refreshing" in u) {
|
|
65
|
-
return typeof u.timestamp === "bigint" && Option.isOption(u.refreshing);
|
|
66
59
|
}
|
|
67
|
-
|
|
68
|
-
return
|
|
69
|
-
}
|
|
70
|
-
export function hasEquality(u) {
|
|
71
|
-
return Equal.symbol in u && Hash.symbol in u;
|
|
72
|
-
}
|
|
73
|
-
export function isTaggedRecord(u) {
|
|
74
|
-
return isRecord(u) && "_tag" in u;
|
|
60
|
+
[Hash.symbol]() {
|
|
61
|
+
return pipe(Hash.string(this._tag), Hash.combine(Hash.hash(this.value)), Hash.combine(Hash.hash(this.timestamp)), Hash.combine(Hash.hash(this.refreshing)));
|
|
62
|
+
}
|
|
75
63
|
}
|
|
76
|
-
|
|
77
|
-
|
|
64
|
+
// @ts-expect-error
|
|
65
|
+
export class OptimisticImpl extends Effectable.Class {
|
|
66
|
+
value;
|
|
67
|
+
timestamp;
|
|
68
|
+
previous;
|
|
69
|
+
[AsyncDataTypeId] = AsyncDataTypeId;
|
|
70
|
+
_tag = OPTIMISTIC_TAG;
|
|
71
|
+
commit;
|
|
72
|
+
constructor(value, timestamp, previous) {
|
|
73
|
+
super();
|
|
74
|
+
this.value = value;
|
|
75
|
+
this.timestamp = timestamp;
|
|
76
|
+
this.previous = previous;
|
|
77
|
+
this.commit = constant(Effect.succeed(value));
|
|
78
|
+
}
|
|
79
|
+
[Equal.symbol](that) {
|
|
80
|
+
return isAsyncData(that) && that._tag === OPTIMISTIC_TAG
|
|
81
|
+
&& Equal.equals(this.value, that.value)
|
|
82
|
+
&& Equal.equals(this.timestamp, that.timestamp)
|
|
83
|
+
&& Equal.equals(this.previous, that.previous);
|
|
84
|
+
}
|
|
85
|
+
[Hash.symbol]() {
|
|
86
|
+
return pipe(Hash.string(this._tag), Hash.combine(Hash.hash(this.value)), Hash.combine(Hash.hash(this.timestamp)), Hash.combine(Hash.hash(this.previous)));
|
|
87
|
+
}
|
|
78
88
|
}
|
|
79
89
|
export function isAsyncData(u) {
|
|
80
|
-
|
|
81
|
-
switch (u._tag) {
|
|
82
|
-
case NO_DATA_TAG:
|
|
83
|
-
return "timstamp" in u && typeof u.timestamp === "bigint";
|
|
84
|
-
case LOADING_TAG:
|
|
85
|
-
return "progress" in u && Option.isOption(u.progress);
|
|
86
|
-
case FAILURE_TAG:
|
|
87
|
-
return hasDataOptions(u) && "cause" in u && Cause.isCause(u.cause);
|
|
88
|
-
case SUCCESS_TAG:
|
|
89
|
-
return hasDataOptions(u) && "value" in u;
|
|
90
|
-
default:
|
|
91
|
-
return false;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
else
|
|
95
|
-
return false;
|
|
90
|
+
return hasProperty(u, AsyncDataTypeId);
|
|
96
91
|
}
|
|
97
92
|
//# sourceMappingURL=async-data.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"async-data.js","sourceRoot":"","sources":["../../../src/internal/async-data.ts"],"names":[],"mappings":"AAAA,WAAW;
|
|
1
|
+
{"version":3,"file":"async-data.js","sourceRoot":"","sources":["../../../src/internal/async-data.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/internal/tag.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tag.js","sourceRoot":"","sources":["../../../src/internal/tag.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG,QAAiB,CAAA;AAE5C,MAAM,CAAC,MAAM,WAAW,GAAG,SAAkB,CAAA;AAE7C,MAAM,CAAC,MAAM,WAAW,GAAG,SAAkB,CAAA;AAE7C,MAAM,CAAC,MAAM,WAAW,GAAG,SAAkB,CAAA"}
|
|
1
|
+
{"version":3,"file":"tag.js","sourceRoot":"","sources":["../../../src/internal/tag.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG,QAAiB,CAAA;AAE5C,MAAM,CAAC,MAAM,WAAW,GAAG,SAAkB,CAAA;AAE7C,MAAM,CAAC,MAAM,WAAW,GAAG,SAAkB,CAAA;AAE7C,MAAM,CAAC,MAAM,WAAW,GAAG,SAAkB,CAAA;AAE7C,MAAM,CAAC,MAAM,cAAc,GAAG,YAAqB,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@typed/async-data",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
"sideEffects": [],
|
|
11
11
|
"author": "Typed contributors",
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@effect/schema": "0.60.
|
|
14
|
-
"effect": "^2.1.
|
|
13
|
+
"@effect/schema": "0.60.6",
|
|
14
|
+
"effect": "^2.1.2",
|
|
15
15
|
"fast-check": "^3.15.0"
|
|
16
16
|
},
|
|
17
17
|
"exports": {
|
|
@@ -30,6 +30,11 @@
|
|
|
30
30
|
"types": "./dist/dts/Schema.d.ts",
|
|
31
31
|
"import": "./dist/esm/Schema.js",
|
|
32
32
|
"default": "./dist/cjs/Schema.js"
|
|
33
|
+
},
|
|
34
|
+
"./TypeId": {
|
|
35
|
+
"types": "./dist/dts/TypeId.d.ts",
|
|
36
|
+
"import": "./dist/esm/TypeId.js",
|
|
37
|
+
"default": "./dist/cjs/TypeId.js"
|
|
33
38
|
}
|
|
34
39
|
},
|
|
35
40
|
"typesVersions": {
|
|
@@ -42,6 +47,9 @@
|
|
|
42
47
|
],
|
|
43
48
|
"Schema": [
|
|
44
49
|
"./dist/dts/Schema.d.ts"
|
|
50
|
+
],
|
|
51
|
+
"TypeId": [
|
|
52
|
+
"./dist/dts/TypeId.d.ts"
|
|
45
53
|
]
|
|
46
54
|
}
|
|
47
55
|
}
|
package/src/AsyncData.ts
CHANGED
|
@@ -17,8 +17,9 @@ import { dual } from "effect/Function"
|
|
|
17
17
|
import * as Option from "effect/Option"
|
|
18
18
|
import * as Unify from "effect/Unify"
|
|
19
19
|
import * as internal from "./internal/async-data.js"
|
|
20
|
-
import { FAILURE_TAG, LOADING_TAG, NO_DATA_TAG, SUCCESS_TAG } from "./internal/tag.js"
|
|
20
|
+
import { FAILURE_TAG, LOADING_TAG, NO_DATA_TAG, OPTIMISTIC_TAG, SUCCESS_TAG } from "./internal/tag.js"
|
|
21
21
|
import * as Progress from "./Progress.js"
|
|
22
|
+
import { AsyncDataTypeId } from "./TypeId.js"
|
|
22
23
|
|
|
23
24
|
const getCurrentTimestamp = () => Date.now()
|
|
24
25
|
|
|
@@ -28,7 +29,7 @@ const getCurrentTimestamp = () => Date.now()
|
|
|
28
29
|
*
|
|
29
30
|
* @since 1.0.0
|
|
30
31
|
*/
|
|
31
|
-
export type AsyncData<E, A> = NoData | Loading | Failure<E> | Success<A>
|
|
32
|
+
export type AsyncData<E, A> = NoData | Loading | Failure<E> | Success<A> | Optimistic<E, A>
|
|
32
33
|
|
|
33
34
|
/**
|
|
34
35
|
* @since 1.0.0
|
|
@@ -73,6 +74,11 @@ export namespace AsyncData {
|
|
|
73
74
|
* @since 1.0.0
|
|
74
75
|
*/
|
|
75
76
|
export class NoData extends Data.TaggedError(NO_DATA_TAG)<{}> {
|
|
77
|
+
/**
|
|
78
|
+
* @since 1.0.0
|
|
79
|
+
*/
|
|
80
|
+
readonly [AsyncDataTypeId]: AsyncDataTypeId = AsyncDataTypeId
|
|
81
|
+
|
|
76
82
|
/**
|
|
77
83
|
* @since 1.0.0
|
|
78
84
|
*/
|
|
@@ -99,6 +105,11 @@ export const noData: {
|
|
|
99
105
|
* @since 1.0.0
|
|
100
106
|
*/
|
|
101
107
|
export class Loading extends Data.TaggedError(LOADING_TAG)<LoadingOptions> {
|
|
108
|
+
/**
|
|
109
|
+
* @since 1.0.0
|
|
110
|
+
*/
|
|
111
|
+
readonly [AsyncDataTypeId]: AsyncDataTypeId = AsyncDataTypeId
|
|
112
|
+
|
|
102
113
|
/**
|
|
103
114
|
* @since 1.0.0
|
|
104
115
|
*/
|
|
@@ -138,14 +149,17 @@ export const loading: {
|
|
|
138
149
|
<E, A>(options?: OptionalPartial<LoadingOptions>): AsyncData<E, A>
|
|
139
150
|
} = (options?: OptionalPartial<LoadingOptions>): Loading =>
|
|
140
151
|
new Loading({
|
|
152
|
+
[AsyncDataTypeId]: AsyncDataTypeId,
|
|
141
153
|
timestamp: options?.timestamp ?? getCurrentTimestamp(),
|
|
142
154
|
progress: Option.fromNullable(options?.progress)
|
|
143
|
-
})
|
|
155
|
+
} as any)
|
|
144
156
|
|
|
145
157
|
/**
|
|
146
158
|
* @since 1.0.0
|
|
147
159
|
*/
|
|
148
160
|
export interface Failure<out E> extends Effect.Effect<never, E, never> {
|
|
161
|
+
readonly [AsyncDataTypeId]: AsyncDataTypeId
|
|
162
|
+
|
|
149
163
|
/**
|
|
150
164
|
* @since 1.18.0
|
|
151
165
|
*/
|
|
@@ -201,7 +215,7 @@ export const failCause: {
|
|
|
201
215
|
cause,
|
|
202
216
|
options?.timestamp ?? getCurrentTimestamp(),
|
|
203
217
|
Option.fromNullable(options?.refreshing)
|
|
204
|
-
)
|
|
218
|
+
) as any
|
|
205
219
|
|
|
206
220
|
/**
|
|
207
221
|
* @since 1.0.0
|
|
@@ -215,6 +229,8 @@ export const fail: {
|
|
|
215
229
|
* @since 1.0.0
|
|
216
230
|
*/
|
|
217
231
|
export interface Success<out A> extends Effect.Effect<never, never, A> {
|
|
232
|
+
readonly [AsyncDataTypeId]: AsyncDataTypeId
|
|
233
|
+
|
|
218
234
|
readonly _tag: typeof SUCCESS_TAG
|
|
219
235
|
readonly value: A
|
|
220
236
|
/**
|
|
@@ -247,13 +263,59 @@ export const success: {
|
|
|
247
263
|
value,
|
|
248
264
|
options?.timestamp ?? getCurrentTimestamp(),
|
|
249
265
|
Option.fromNullable(options?.refreshing)
|
|
250
|
-
)
|
|
266
|
+
) as any
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* @since 1.0.0
|
|
270
|
+
*/
|
|
271
|
+
export interface Optimistic<E, A> extends Effect.Effect<never, never, A> {
|
|
272
|
+
readonly [AsyncDataTypeId]: AsyncDataTypeId
|
|
273
|
+
readonly _tag: "Optimistic"
|
|
274
|
+
readonly value: A
|
|
275
|
+
readonly timestamp: number // Date.now()
|
|
276
|
+
readonly previous: AsyncData<E, A>
|
|
277
|
+
|
|
278
|
+
readonly [Unify.typeSymbol]: unknown
|
|
279
|
+
readonly [Unify.unifySymbol]: AsyncData.Unify<this>
|
|
280
|
+
readonly [Unify.ignoreSymbol]: AsyncData.IgnoreList
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* @since 1.0.0
|
|
285
|
+
*/
|
|
286
|
+
export interface OptimisticOptions {
|
|
287
|
+
readonly timestamp: number // Date.now()
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const isAsyncDataFirst = (args: IArguments) => isAsyncData(args[0])
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* @since 1.0.0
|
|
294
|
+
*/
|
|
295
|
+
export const optimistic: {
|
|
296
|
+
<A>(value: A, options?: OptionalPartial<OptimisticOptions>): <E>(previous: AsyncData<E, A>) => Optimistic<E, A>
|
|
297
|
+
<E, A>(previous: AsyncData<E, A>, value: A, options?: OptionalPartial<OptimisticOptions>): Optimistic<E, A>
|
|
298
|
+
} = dual(
|
|
299
|
+
(args) => args.length === 3 || isAsyncDataFirst(args),
|
|
300
|
+
<E, A>(previous: AsyncData<E, A>, value: A, options?: OptionalPartial<OptimisticOptions>): Optimistic<E, A> =>
|
|
301
|
+
new internal.OptimisticImpl(
|
|
302
|
+
value,
|
|
303
|
+
options?.timestamp ?? getCurrentTimestamp(),
|
|
304
|
+
// We don't want to nest Optimistic values, so we unwrap the previous value if it's already optimistic
|
|
305
|
+
previous._tag === "Optimistic" ? previous.previous : previous
|
|
306
|
+
) as any
|
|
307
|
+
)
|
|
251
308
|
|
|
252
309
|
/**
|
|
253
310
|
* @since 1.0.0
|
|
254
311
|
*/
|
|
255
312
|
export const isSuccess = <E, A>(data: AsyncData<E, A>): data is Success<A> => data._tag === SUCCESS_TAG
|
|
256
313
|
|
|
314
|
+
/**
|
|
315
|
+
* @since 1.0.0
|
|
316
|
+
*/
|
|
317
|
+
export const isOptimistic = <E, A>(data: AsyncData<E, A>): data is Optimistic<E, A> => data._tag === OPTIMISTIC_TAG
|
|
318
|
+
|
|
257
319
|
/**
|
|
258
320
|
* @since 1.0.0
|
|
259
321
|
*/
|
|
@@ -292,41 +354,48 @@ export interface RefreshingSuccess<A> extends Success<A> {
|
|
|
292
354
|
* @since 1.0.0
|
|
293
355
|
*/
|
|
294
356
|
export const isRefreshing = <E, A>(data: AsyncData<E, A>): data is Refreshing<E, A> =>
|
|
295
|
-
isSuccess(data) || isFailure(data)
|
|
357
|
+
isSuccess(data) || isFailure(data)
|
|
358
|
+
? Option.isSome(data.refreshing)
|
|
359
|
+
: isOptimistic(data)
|
|
360
|
+
? isRefreshing(data.previous)
|
|
361
|
+
: false
|
|
296
362
|
|
|
297
363
|
/**
|
|
298
364
|
* @since 1.0.0
|
|
299
365
|
*/
|
|
300
366
|
export const isLoadingOrRefreshing = <E, A>(data: AsyncData<E, A>): data is Loading | Refreshing<E, A> =>
|
|
301
|
-
isLoading(data) || isRefreshing(data)
|
|
367
|
+
isLoading(data) || isRefreshing(data) || (isOptimistic(data) && isLoadingOrRefreshing(data.previous))
|
|
302
368
|
|
|
303
369
|
/**
|
|
304
370
|
* @since 1.0.0
|
|
305
371
|
*/
|
|
306
372
|
export const match: {
|
|
307
|
-
<E, A, R1, R2, R3, R4>(
|
|
373
|
+
<E, A, R1, R2, R3, R4, R5>(
|
|
308
374
|
matchers: {
|
|
309
375
|
NoData: (data: NoData) => R1
|
|
310
376
|
Loading: (data: Loading) => R2
|
|
311
377
|
Failure: (cause: Cause.Cause<E>, data: Failure<E>) => R3
|
|
312
378
|
Success: (value: A, data: Success<A>) => R4
|
|
379
|
+
Optimistic: (value: A, data: Optimistic<E, A>) => R5
|
|
313
380
|
}
|
|
314
|
-
): (data: AsyncData<E, A>) => Unify.Unify<R1 | R2 | R3 | R4>
|
|
381
|
+
): (data: AsyncData<E, A>) => Unify.Unify<R1 | R2 | R3 | R4 | R5>
|
|
315
382
|
|
|
316
|
-
<E, A, R1, R2, R3, R4>(
|
|
383
|
+
<E, A, R1, R2, R3, R4, R5>(
|
|
317
384
|
data: AsyncData<E, A>,
|
|
318
385
|
matchers: {
|
|
319
386
|
NoData: (data: NoData) => R1
|
|
320
387
|
Loading: (data: Loading) => R2
|
|
321
388
|
Failure: (cause: Cause.Cause<E>, data: Failure<E>) => R3
|
|
322
389
|
Success: (value: A, data: Success<A>) => R4
|
|
390
|
+
Optimistic: (value: A, data: Optimistic<E, A>) => R5
|
|
323
391
|
}
|
|
324
|
-
): Unify.Unify<R1 | R2 | R3 | R4>
|
|
325
|
-
} = dual(2, <E, A, R1, R2, R3, R4>(data: AsyncData<E, A>, matchers: {
|
|
392
|
+
): Unify.Unify<R1 | R2 | R3 | R4 | R5>
|
|
393
|
+
} = dual(2, <E, A, R1, R2, R3, R4, R5>(data: AsyncData<E, A>, matchers: {
|
|
326
394
|
NoData: (data: NoData) => R1
|
|
327
395
|
Loading: (data: Loading) => R2
|
|
328
396
|
Failure: (cause: Cause.Cause<E>, data: Failure<E>) => R3
|
|
329
397
|
Success: (value: A, data: Success<A>) => R4
|
|
398
|
+
Optimistic: (value: A, data: Optimistic<E, A>) => R5
|
|
330
399
|
}): Unify.Unify<R1 | R2 | R3 | R4> => {
|
|
331
400
|
if (isSuccess(data)) {
|
|
332
401
|
return matchers.Success(data.value, data) as Unify.Unify<R1 | R2 | R3 | R4>
|
|
@@ -334,8 +403,10 @@ export const match: {
|
|
|
334
403
|
return matchers.Failure(data.cause, data) as Unify.Unify<R1 | R2 | R3 | R4>
|
|
335
404
|
} else if (isLoading(data)) {
|
|
336
405
|
return matchers.Loading(data) as Unify.Unify<R1 | R2 | R3 | R4>
|
|
337
|
-
} else {
|
|
406
|
+
} else if (isNoData(data)) {
|
|
338
407
|
return matchers.NoData(data) as Unify.Unify<R1 | R2 | R3 | R4>
|
|
408
|
+
} else {
|
|
409
|
+
return matchers.Optimistic(data.value, data) as Unify.Unify<R1 | R2 | R3 | R4>
|
|
339
410
|
}
|
|
340
411
|
})
|
|
341
412
|
|
|
@@ -345,27 +416,41 @@ export const match: {
|
|
|
345
416
|
export const map: {
|
|
346
417
|
<A, B>(f: (a: A) => B): <E>(data: AsyncData<E, A>) => AsyncData<E, B>
|
|
347
418
|
<E, A, B>(data: AsyncData<E, A>, f: (a: A) => B): AsyncData<E, B>
|
|
348
|
-
} = dual(2, function<E, A, B>(data: AsyncData<E, A>, f: (a: A) => B): AsyncData<E, B> {
|
|
349
|
-
|
|
350
|
-
success(f(data.value), {
|
|
419
|
+
} = dual(2, function map<E, A, B>(data: AsyncData<E, A>, f: (a: A) => B): AsyncData<E, B> {
|
|
420
|
+
if (isSuccess(data)) {
|
|
421
|
+
return success(f(data.value), {
|
|
422
|
+
timestamp: data.timestamp,
|
|
351
423
|
refreshing: Option.getOrUndefined(data.refreshing)
|
|
352
|
-
})
|
|
353
|
-
|
|
424
|
+
})
|
|
425
|
+
} else if (isOptimistic(data)) {
|
|
426
|
+
return optimistic(map(data.previous, f), f(data.value), { timestamp: data.timestamp })
|
|
427
|
+
} else {
|
|
428
|
+
return data
|
|
429
|
+
}
|
|
354
430
|
})
|
|
355
431
|
|
|
356
432
|
/**
|
|
357
433
|
* @since 1.0.0
|
|
358
434
|
*/
|
|
359
435
|
export const flatMap: {
|
|
360
|
-
<
|
|
361
|
-
|
|
436
|
+
<E, A, E2, B>(
|
|
437
|
+
f: (a: A, data: Success<A> | Optimistic<E, A>) => AsyncData<E2, B>
|
|
438
|
+
): (data: AsyncData<E, A>) => AsyncData<E | E2, B>
|
|
439
|
+
<E, A, E2, B>(
|
|
440
|
+
data: AsyncData<E, A>,
|
|
441
|
+
f: (a: A, data: Success<A> | Optimistic<E, A>) => AsyncData<E, B>
|
|
442
|
+
): AsyncData<E | E2, B>
|
|
362
443
|
} = dual(
|
|
363
444
|
2,
|
|
364
445
|
function<E, A, E2, B>(
|
|
365
446
|
data: AsyncData<E, A>,
|
|
366
|
-
f: (a: A,
|
|
447
|
+
f: (a: A, data: Success<A> | Optimistic<E, A>) => AsyncData<E2, B>
|
|
367
448
|
): AsyncData<E | E2, B> {
|
|
368
|
-
|
|
449
|
+
if (isSuccess(data) || isOptimistic(data)) {
|
|
450
|
+
return f(data.value, data)
|
|
451
|
+
} else {
|
|
452
|
+
return data
|
|
453
|
+
}
|
|
369
454
|
}
|
|
370
455
|
)
|
|
371
456
|
|
|
@@ -379,6 +464,8 @@ export const startLoading = <E, A>(data: AsyncData<E, A>): AsyncData<E, A> => {
|
|
|
379
464
|
return Option.isSome(data.refreshing)
|
|
380
465
|
? data
|
|
381
466
|
: failCause(data.cause, { ...data, refreshing: loading() })
|
|
467
|
+
} else if (isOptimistic(data)) {
|
|
468
|
+
return optimistic(startLoading(data.previous), data.value, data)
|
|
382
469
|
} else {
|
|
383
470
|
return loading()
|
|
384
471
|
}
|
|
@@ -392,6 +479,8 @@ export const stopLoading = <E, A>(data: AsyncData<E, A>): AsyncData<E, A> => {
|
|
|
392
479
|
return Option.isSome(data.refreshing) ? success(data.value) : data
|
|
393
480
|
} else if (isFailure(data)) {
|
|
394
481
|
return Option.isSome(data.refreshing) ? failCause(data.cause) : data
|
|
482
|
+
} else if (isOptimistic(data)) {
|
|
483
|
+
return optimistic(stopLoading(data.previous), data.value, data)
|
|
395
484
|
} else {
|
|
396
485
|
return noData()
|
|
397
486
|
}
|
|
@@ -421,7 +510,7 @@ export const getFailure = <E, A>(data: AsyncData<E, A>): Option.Option<E> =>
|
|
|
421
510
|
* @since 1.0.0
|
|
422
511
|
*/
|
|
423
512
|
export const getSuccess = <E, A>(data: AsyncData<E, A>): Option.Option<A> =>
|
|
424
|
-
isSuccess(data) ? Option.some(data.value) : Option.none()
|
|
513
|
+
isSuccess(data) || isOptimistic(data) ? Option.some(data.value) : Option.none()
|
|
425
514
|
|
|
426
515
|
const optionProgressEq = Option.getEquivalence(Progress.equals)
|
|
427
516
|
|
|
@@ -448,20 +537,45 @@ const successEquivalence = <A>(valueEq: Equivalence.Equivalence<A>): Equivalence
|
|
|
448
537
|
refreshing: optionLoadingEq
|
|
449
538
|
})
|
|
450
539
|
|
|
540
|
+
const optimisticEquivalence = <E, A>(
|
|
541
|
+
valueEq: Equivalence.Equivalence<A>
|
|
542
|
+
): Equivalence.Equivalence<Optimistic<E, A>> => {
|
|
543
|
+
let previousEq: Equivalence.Equivalence<AsyncData<E, A>> | undefined
|
|
544
|
+
const get = () => {
|
|
545
|
+
if (previousEq === undefined) {
|
|
546
|
+
previousEq = getEquivalence(valueEq)
|
|
547
|
+
}
|
|
548
|
+
return previousEq
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
return Equivalence.struct({
|
|
552
|
+
_tag: Equivalence.string,
|
|
553
|
+
value: valueEq,
|
|
554
|
+
timestamp: Equivalence.number,
|
|
555
|
+
previous: (a, b) => get()(a, b)
|
|
556
|
+
})
|
|
557
|
+
}
|
|
558
|
+
|
|
451
559
|
/**
|
|
452
560
|
* @since 1.0.0
|
|
453
561
|
*/
|
|
454
|
-
export const getEquivalence =
|
|
455
|
-
|
|
562
|
+
export const getEquivalence = <E, A>(
|
|
563
|
+
valueEq: Equivalence.Equivalence<A> = Equal.equals
|
|
564
|
+
): Equivalence.Equivalence<AsyncData<E, A>> => {
|
|
565
|
+
const successEq_ = successEquivalence(valueEq)
|
|
566
|
+
const optimisticEq_ = optimisticEquivalence(valueEq)
|
|
567
|
+
return (a, b) => {
|
|
456
568
|
if (a === b) return true
|
|
457
569
|
|
|
458
570
|
return match(a, {
|
|
459
571
|
NoData: () => isNoData(b),
|
|
460
572
|
Loading: (l1) => isLoading(b) ? loadingEquivalence(l1, b) : false,
|
|
461
573
|
Failure: (_, f1) => isFailure(b) ? failureEquivalence(f1, b) : false,
|
|
462
|
-
Success: (_, s1) => isSuccess(b) ?
|
|
574
|
+
Success: (_, s1) => isSuccess(b) ? successEq_(s1, b) : false,
|
|
575
|
+
Optimistic: (_, o1) => isOptimistic(b) ? optimisticEq_(o1, b) : false
|
|
463
576
|
})
|
|
464
577
|
}
|
|
578
|
+
}
|
|
465
579
|
|
|
466
580
|
/**
|
|
467
581
|
* @since 1.0.0
|
|
@@ -483,8 +597,6 @@ export function fromEither<E, A>(either: Either.Either<E, A>): AsyncData<E, A> {
|
|
|
483
597
|
})
|
|
484
598
|
}
|
|
485
599
|
|
|
486
|
-
const isAsyncDataFirst = (args: IArguments) => args.length === 3 || isAsyncData(args[0])
|
|
487
|
-
|
|
488
600
|
/**
|
|
489
601
|
* @since 1.0.0
|
|
490
602
|
*/
|
|
@@ -498,7 +610,7 @@ export const isExpired: {
|
|
|
498
610
|
): boolean {
|
|
499
611
|
return match(data, {
|
|
500
612
|
NoData: () => true,
|
|
501
|
-
Loading: () =>
|
|
613
|
+
Loading: ({ timestamp }) => isPastTTL(timestamp, ttl, now),
|
|
502
614
|
Failure: (_, f) =>
|
|
503
615
|
Option.isNone(f.refreshing)
|
|
504
616
|
? isPastTTL(f.timestamp, ttl, now)
|
|
@@ -506,14 +618,16 @@ export const isExpired: {
|
|
|
506
618
|
Success: (_, s) =>
|
|
507
619
|
Option.isNone(s.refreshing)
|
|
508
620
|
? isPastTTL(s.timestamp, ttl, now) :
|
|
509
|
-
isPastTTL(s.refreshing.value.timestamp, ttl, now)
|
|
621
|
+
isPastTTL(s.refreshing.value.timestamp, ttl, now),
|
|
622
|
+
Optimistic: (_, o) =>
|
|
623
|
+
isPastTTL(o.timestamp, ttl, now) || (o.previous._tag === NO_DATA_TAG ? false : isExpired(o.previous, ttl, now))
|
|
510
624
|
})
|
|
511
625
|
})
|
|
512
626
|
|
|
513
627
|
function isPastTTL(timestamp: number, ttl: Duration.DurationInput, now: number): boolean {
|
|
514
628
|
const millis = Duration.toMillis(ttl)
|
|
515
629
|
|
|
516
|
-
return now - timestamp
|
|
630
|
+
return now - timestamp >= millis
|
|
517
631
|
}
|
|
518
632
|
|
|
519
633
|
/**
|
|
@@ -529,6 +643,8 @@ export function dataEqual<E, A>(first: AsyncData<E, A>, second: AsyncData<E, A>)
|
|
|
529
643
|
Failure: (_, f1) =>
|
|
530
644
|
isFailure(second) && Equal.equals(f1.cause, second.cause) && Equal.equals(f1.refreshing, second.refreshing),
|
|
531
645
|
Success: (_, s1) =>
|
|
532
|
-
isSuccess(second) && Equal.equals(s1.value, second.value) && Equal.equals(s1.refreshing, second.refreshing)
|
|
646
|
+
isSuccess(second) && Equal.equals(s1.value, second.value) && Equal.equals(s1.refreshing, second.refreshing),
|
|
647
|
+
Optimistic: (_, o1) =>
|
|
648
|
+
isOptimistic(second) && Equal.equals(o1.value, second.value) && dataEqual(o1.previous, second.previous)
|
|
533
649
|
})
|
|
534
650
|
}
|