@typed/async-data 0.3.3 → 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.
@@ -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 * as Option from "effect/Option";
9
- import * as Unify from "effect/Unify";
10
- import { FAILURE_TAG, LOADING_TAG, NO_DATA_TAG, SUCCESS_TAG } from "./tag.js";
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
- _tag = "Failure";
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] = (that) => {
28
- return isAsyncData(that) && that._tag === "Failure"
29
- && Equal.equals(this.cause, that.cause)
30
- && Equal.equals(this.timestamp, that.timestamp)
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
- _tag = "Success";
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] = (that) => {
54
- return isAsyncData(that) && that._tag === "Success"
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
- else
68
- return false;
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
- export function isRecord(u) {
77
- return typeof u === "object" && u !== null && !Array.isArray(u);
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
- if (isTaggedRecord(u) && hasEquality(u)) {
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":"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"}
1
+ {"version":3,"file":"async-data.js","sourceRoot":"","sources":["../../../src/internal/async-data.ts"],"names":[],"mappings":"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"}
@@ -2,4 +2,5 @@ export const NO_DATA_TAG = "NoData";
2
2
  export const LOADING_TAG = "Loading";
3
3
  export const FAILURE_TAG = "Failure";
4
4
  export const SUCCESS_TAG = "Success";
5
+ export const OPTIMISTIC_TAG = "Optimistic";
5
6
  //# sourceMappingURL=tag.js.map
@@ -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",
3
+ "version": "0.3.4",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -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) ? Option.isSome(data.refreshing) : false
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
- return isSuccess(data) ?
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
- data
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
- <A, E2, B>(f: (a: A, options: SuccessOptions) => AsyncData<E2, B>): <E>(data: AsyncData<E, A>) => AsyncData<E | E2, B>
361
- <E, A, E2, B>(data: AsyncData<E, A>, f: (a: A, options: SuccessOptions) => AsyncData<E, B>): AsyncData<E | E2, B>
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, options: SuccessOptions) => AsyncData<E2, B>
447
+ f: (a: A, data: Success<A> | Optimistic<E, A>) => AsyncData<E2, B>
367
448
  ): AsyncData<E | E2, B> {
368
- return isSuccess(data) ? f(data.value, data) : data
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
- <E, A>(valueEq: Equivalence.Equivalence<A> = Equal.equals): Equivalence.Equivalence<AsyncData<E, A>> => (a, b) => {
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) ? successEquivalence(valueEq)(s1, b) : false
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: () => false,
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 > millis
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
  }