Skip to content

Commit

Permalink
Merge pull request #615 from phryneas/pr/configurable-cache
Browse files Browse the repository at this point in the history
Make `Cache` instance/class user-configurable via `options.cache`
  • Loading branch information
benjamn authored Nov 28, 2023
2 parents 1c3a4c1 + f0133c0 commit 56001fe
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 142 deletions.
24 changes: 22 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "optimism",
"version": "0.17.5",
"version": "0.18.0-pre.0",
"author": "Ben Newman <ben@benjamn.com>",
"description": "Composable reactive caching with efficient invalidation.",
"keywords": [
Expand Down Expand Up @@ -47,6 +47,7 @@
"typescript": "^5.0.2"
},
"dependencies": {
"@wry/caches": "^1.0.0",
"@wry/context": "^0.7.0",
"@wry/trie": "^0.4.3",
"tslib": "^2.3.0"
Expand Down
115 changes: 0 additions & 115 deletions src/cache.ts

This file was deleted.

2 changes: 2 additions & 0 deletions src/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export type NoInfer<T> = [T][T extends any ? 0 : never];

export const {
hasOwnProperty,
} = Object.prototype;
Expand Down
44 changes: 31 additions & 13 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Trie } from "@wry/trie";

import { Cache } from "./cache.js";
import { StrongCache, CommonCache } from "@wry/caches";
import { Entry, AnyEntry } from "./entry.js";
import { parentEntrySlot } from "./context.js";
import type { NoInfer } from "./helpers.js";

// These helper functions are important for making optimism work with
// asynchronous code. In order to register parent-child dependencies,
Expand Down Expand Up @@ -55,7 +56,7 @@ export type OptimisticWrapperFunction<
readonly size: number;

// Snapshot of wrap options used to create this wrapper function.
options: OptimisticWrapOptions<TArgs, TKeyArgs, TCacheKey>;
options: OptionsWithCacheInstance<TArgs, TKeyArgs, TCacheKey>;

// "Dirty" any cached Entry stored for the given arguments, marking that Entry
// and its ancestors as potentially needing to be recomputed. The .dirty(...)
Expand Down Expand Up @@ -89,10 +90,16 @@ export type OptimisticWrapperFunction<
makeCacheKey: (...args: TKeyArgs) => TCacheKey;
};

export { CommonCache }
export interface CommonCacheConstructor<TCacheKey, TResult, TArgs extends any[]> extends Function {
new <K extends TCacheKey, V extends Entry<TArgs, TResult>>(max?: number, dispose?: (value: V, key?: K) => void): CommonCache<K,V>;
}

export type OptimisticWrapOptions<
TArgs extends any[],
TKeyArgs extends any[] = TArgs,
TCacheKey = any,
TResult = any,
> = {
// The maximum number of cache entries that should be retained before the
// cache begins evicting the oldest ones.
Expand All @@ -103,13 +110,24 @@ export type OptimisticWrapOptions<
// The makeCacheKey function takes the same arguments that were passed to
// the wrapper function and returns a single value that can be used as a key
// in a Map to identify the cached result.
makeCacheKey?: (...args: TKeyArgs) => TCacheKey;
makeCacheKey?: (...args: NoInfer<TKeyArgs>) => TCacheKey;
// If provided, the subscribe function should either return an unsubscribe
// function or return nothing.
subscribe?: (...args: TArgs) => void | (() => any);
cache?: CommonCache<NoInfer<TCacheKey>, Entry<NoInfer<TArgs>, NoInfer<TResult>>>
| CommonCacheConstructor<NoInfer<TCacheKey>, NoInfer<TResult>, NoInfer<TArgs>>;
};

const caches = new Set<Cache<any, AnyEntry>>();
export interface OptionsWithCacheInstance<
TArgs extends any[],
TKeyArgs extends any[] = TArgs,
TCacheKey = any,
TResult = any,
> extends OptimisticWrapOptions<TArgs, TKeyArgs, TCacheKey, TResult> {
cache: CommonCache<NoInfer<TCacheKey>, Entry<NoInfer<TArgs>, NoInfer<TResult>>>;
};

const caches = new Set<CommonCache<any, AnyEntry>>();

export function wrap<
TArgs extends any[],
Expand All @@ -118,14 +136,15 @@ export function wrap<
TCacheKey = any,
>(originalFunction: (...args: TArgs) => TResult, {
max = Math.pow(2, 16),
makeCacheKey = defaultMakeCacheKey,
makeCacheKey = (defaultMakeCacheKey as () => TCacheKey),
keyArgs,
subscribe,
}: OptimisticWrapOptions<TArgs, TKeyArgs> = Object.create(null)) {
const cache = new Cache<TCacheKey, Entry<TArgs, TResult>>(
max,
entry => entry.dispose(),
);
cache: cacheOption = StrongCache,
}: OptimisticWrapOptions<TArgs, TKeyArgs, TCacheKey, TResult> = Object.create(null)) {
const cache: CommonCache<TCacheKey, Entry<TArgs, TResult>> =
typeof cacheOption === "function"
? new cacheOption(max, entry => entry.dispose())
: cacheOption;

const optimistic = function (): TResult {
const key = makeCacheKey.apply(
Expand Down Expand Up @@ -168,9 +187,7 @@ export function wrap<
} as OptimisticWrapperFunction<TArgs, TResult, TKeyArgs, TCacheKey>;

Object.defineProperty(optimistic, "size", {
get() {
return cache["map"].size;
},
get: () => cache.size,
configurable: false,
enumerable: false,
});
Expand All @@ -180,6 +197,7 @@ export function wrap<
makeCacheKey,
keyArgs,
subscribe,
cache,
});

function dirtyKey(key: TCacheKey) {
Expand Down
Loading

0 comments on commit 56001fe

Please sign in to comment.