Skip to content

Commit

Permalink
feat: add caches and keyed version
Browse files Browse the repository at this point in the history
  • Loading branch information
cprecioso committed Apr 14, 2023
1 parent 61a6ca9 commit 7067c65
Show file tree
Hide file tree
Showing 8 changed files with 67 additions and 35 deletions.
16 changes: 16 additions & 0 deletions src/cache/keyed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { CacheValue } from "../lib/cache-ref";
import { suspendOnPromise } from "../lib/suspend";

export interface KeyedCacheStorage<K, T> {
get(key: K): CacheValue<T> | undefined | null;
set(key: K, value: CacheValue<T>): void;
}

export const createKeyedCache = <K, T>(
storage: KeyedCacheStorage<K, T> = new Map()
) => {
const use = (key: K, fn: () => Promise<T>) =>
suspendOnPromise(fn, storage.get(key), (value) => storage.set(key, value));

return { use, storage };
};
15 changes: 15 additions & 0 deletions src/cache/single-value.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { CacheValue } from "../lib/cache-ref";
import { suspendOnPromise } from "../lib/suspend";

export const createSingleValueCache = <T>() => {
const storage = {
current: null as CacheValue<T> | null,
};

const use = (fn: () => Promise<T>) =>
suspendOnPromise(fn, storage.current, (value) => {
storage.current = value;
});

return { use, storage };
};
5 changes: 4 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
export { createSingleValueSuspense } from "./single-value";
export { createKeyedCache } from "./cache/keyed";
export { createSingleValueCache } from "./cache/single-value";
export { createKeyedSuspense } from "./suspense/keyed";
export { createSingleValueSuspense } from "./suspense/single-value";
File renamed without changes.
8 changes: 6 additions & 2 deletions src/suspend.ts → src/lib/suspend.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { CacheValue } from "./cache-ref";

// We wrap the `fn` in an async function to avoid
// throwing sync errors.
const callPromiseFn = async <T>(fn: () => Promise<T>) => await fn();

export const suspendOnPromise = <T>(
fn: () => Promise<T>,
cachedValue: CacheValue<T> | null,
cachedValue: CacheValue<T> | undefined | null,
storeInCache: (value: CacheValue<T>) => void
) => {
if (!cachedValue) {
const promise = fn().then(
const promise = callPromiseFn(fn).then(
(value) => storeInCache({ status: "fulfilled", value }),
(error) => storeInCache({ status: "rejected", error })
);
Expand Down
32 changes: 0 additions & 32 deletions src/single-value.ts

This file was deleted.

14 changes: 14 additions & 0 deletions src/suspense/keyed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { createKeyedCache } from "../cache/keyed";

export const createKeyedSuspense = <K extends string, T>(
fn: (key: K) => Promise<T>
) => {
const cache = createKeyedCache<K, T>();

const useKeyedSuspense = (key: K) => {
const value = cache.use(key, () => fn(key));
return { value, cache };
};

return useKeyedSuspense;
};
12 changes: 12 additions & 0 deletions src/suspense/single-value.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { createSingleValueCache } from "../cache/single-value";

export const createSingleValueSuspense = <T>(fn: () => Promise<T>) => {
const cache = createSingleValueCache<T>();

const useSingleValueSuspense = () => {
const value = cache.use(fn);
return { value, cache };
};

return useSingleValueSuspense;
};

0 comments on commit 7067c65

Please sign in to comment.