Skip to content

Commit abccacc

Browse files
committed
Cache immutable KeySpecifier-derived information to improve performance.
1 parent 4f436aa commit abccacc

File tree

1 file changed

+37
-10
lines changed

1 file changed

+37
-10
lines changed

src/cache/inmemory/key-extractor.ts

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,31 @@ import {
1414
KeyArgsFunction,
1515
} from "./policies";
1616

17+
// Mapping from JSON-encoded KeySpecifier strings to associated information.
18+
const specifierInfoCache: Record<string, {
19+
paths?: string[][];
20+
keyFieldsFn?: KeyFieldsFunction;
21+
keyArgsFn?: KeyArgsFunction;
22+
}> = Object.create(null);
23+
24+
function lookupSpecifierInfo(spec: KeySpecifier) {
25+
// It's safe to encode KeySpecifier arrays with JSON.stringify, since they're
26+
// just arrays of strings or nested KeySpecifier arrays, and the order of the
27+
// array elements is important (and suitably preserved by JSON.stringify).
28+
const cacheKey = JSON.stringify(spec);
29+
return specifierInfoCache[cacheKey] ||
30+
(specifierInfoCache[cacheKey] = Object.create(null));
31+
}
32+
1733
export function keyFieldsFnFromSpecifier(
1834
specifier: KeySpecifier,
1935
): KeyFieldsFunction {
20-
return (object, context) => {
36+
const info = lookupSpecifierInfo(specifier);
37+
38+
return info.keyFieldsFn || (info.keyFieldsFn = (
39+
object,
40+
context,
41+
) => {
2142
const extract: typeof extractKey =
2243
(from, key) => context.readField(key, from);
2344

@@ -62,7 +83,7 @@ export function keyFieldsFnFromSpecifier(
6283
);
6384

6485
return `${context.typename}:${JSON.stringify(keyObject)}`;
65-
};
86+
});
6687
}
6788

6889
// The keyArgs extraction process is roughly analogous to keyFields extraction,
@@ -73,7 +94,13 @@ export function keyFieldsFnFromSpecifier(
7394
// function to collectSpecifierPaths, reusing the shared extractKeyPath helper
7495
// wherever possible.
7596
export function keyArgsFnFromSpecifier(specifier: KeySpecifier): KeyArgsFunction {
76-
return (args, { field, variables, fieldName }) => {
97+
const info = lookupSpecifierInfo(specifier);
98+
99+
return info.keyArgsFn || (info.keyArgsFn = (args, {
100+
field,
101+
variables,
102+
fieldName,
103+
}) => {
77104
const collected = collectSpecifierPaths(specifier, keyPath => {
78105
const firstKey = keyPath[0];
79106
const firstChar = firstKey.charAt(0);
@@ -138,7 +165,7 @@ export function keyArgsFnFromSpecifier(specifier: KeySpecifier): KeyArgsFunction
138165
}
139166

140167
return fieldName;
141-
};
168+
});
142169
}
143170

144171
export function collectSpecifierPaths(
@@ -162,11 +189,11 @@ export function collectSpecifierPaths(
162189
}, Object.create(null));
163190
}
164191

165-
export function getSpecifierPaths(spec: KeySpecifier & {
166-
paths?: string[][];
167-
}): string[][] {
168-
if (!spec.paths) {
169-
const paths: string[][] = spec.paths = [];
192+
export function getSpecifierPaths(spec: KeySpecifier): string[][] {
193+
const info = lookupSpecifierInfo(spec);
194+
195+
if (!info.paths) {
196+
const paths: string[][] = info.paths = [];
170197
const currentPath: string[] = [];
171198

172199
spec.forEach((s, i) => {
@@ -183,7 +210,7 @@ export function getSpecifierPaths(spec: KeySpecifier & {
183210
});
184211
}
185212

186-
return spec.paths!;
213+
return info.paths!;
187214
}
188215

189216
function extractKey<

0 commit comments

Comments
 (0)