Skip to content

Commit

Permalink
feat: Cache.updateValue with function
Browse files Browse the repository at this point in the history
fix: Cache.updateValue with promise
  • Loading branch information
schummar committed Mar 13, 2024
1 parent 17e4f0c commit 427e665
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 18 deletions.
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"typescript.tsdk": "node_modules/typescript/lib",
"vitest.commandLine": "pnpm test --",
"vitest.commandLine": "node --expose-gc node_modules/vitest/vitest.mjs",
"testing.automaticallyOpenPeekView": "never"
}
10 changes: 7 additions & 3 deletions src/core/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,12 @@ export class Cache<T> extends Store<Promise<T>> {
return promise;
}

updateValue(value: MaybePromise<T>) {
this.set(PromiseWithState.resolve(value));
updateValue(value: MaybePromise<T> | ((value: T) => T)) {
if (value instanceof Function) {
this.set(this.get().then((v) => value(v)));
} else {
this.set(PromiseWithState.resolve(value));
}
}

updateError(error: unknown) {
Expand Down Expand Up @@ -154,7 +158,7 @@ export class Cache<T> extends Store<Promise<T>> {
protected watchPromise() {
this.subscribe(
async (promise) => {
if (promise instanceof PromiseWithState) {
if (promise instanceof PromiseWithState && promise.state.status !== 'pending') {
this.state.set((state) => ({
...promise.state,
isStale: false,
Expand Down
2 changes: 1 addition & 1 deletion src/core/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ export class Store<T> extends Callable<any, any> {

resolve(value);
stopped = true;
clearTimeout(timer);
timer && clearTimeout(timer);
setTimeout(() => cancel());
},
{
Expand Down
8 changes: 8 additions & 0 deletions src/lib/isPromise.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export default function isPromise(value: unknown): value is Promise<unknown> {
return (
typeof value === 'object' &&
value !== null &&
'then' in value &&
typeof value.then === 'function'
);
}
26 changes: 14 additions & 12 deletions src/lib/promiseWithState.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import isPromise from '@lib/isPromise';
import { type ErrorState, type PendingState, type ValueState } from './cacheState';
import { type MaybePromise } from './maybePromise';

Expand All @@ -11,28 +12,29 @@ export class PromiseWithState<T> extends Promise<T> {
static override resolve<T>(value: MaybePromise<T>): PromiseWithState<T>;

static override resolve<T>(value?: MaybePromise<T>) {
return new PromiseWithState<T>(Promise.resolve(value as MaybePromise<T>), {
status: 'value',
value: value as T,
});
return new PromiseWithState<T>(value as MaybePromise<T>);
}

static override reject<T = never>(error: unknown) {
return new PromiseWithState<T>(Promise.reject(error), { status: 'error', error });
}

constructor(
value: Promise<T>,
value: MaybePromise<T>,
public state: ValueState<T> | ErrorState | PendingState = { status: 'pending' },
) {
super((resolve) => resolve(value));

value
.then((value) => {
this.state = { status: 'value', value };
})
.catch((error) => {
this.state = { status: 'error', error };
});
if (isPromise(value)) {
value
.then((value) => {
this.state = { status: 'value', value: value };
})
.catch((error) => {
this.state = { status: 'error', error };
});
} else {
this.state = { status: 'value', value: value };
}
}
}
30 changes: 29 additions & 1 deletion test/core/cache.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ describe('cache', () => {
});

describe('update cache', () => {
test('update plain value', async () => {
test('with plain value', async () => {
const cache = createCache(async () => 1);
cache.updateValue(2);

Expand All @@ -120,6 +120,34 @@ describe('cache', () => {
isConnected: false,
});
});

test('with promise', async () => {
const cache = createCache(async () => 1);
cache.updateValue(Promise.resolve(2));
await cache.get();

expect(cache.state.get()).toStrictEqual({
status: 'value',
value: 2,
isStale: false,
isUpdating: false,
isConnected: false,
});
});

test('with function', async () => {
const cache = createCache(async () => 1);
cache.updateValue((x) => x + 1);
await cache.get();

expect(cache.state.get()).toStrictEqual({
status: 'value',
value: 2,
isStale: false,
isUpdating: false,
isConnected: false,
});
});
});

describe('sub', () => {
Expand Down

0 comments on commit 427e665

Please sign in to comment.