Skip to content

Commit 1a9dc17

Browse files
garcianavalonbenjie
authored andcommitted
feat: allow passing readCache as an object (#479)
1 parent d723558 commit 1a9dc17

File tree

3 files changed

+148
-58
lines changed

3 files changed

+148
-58
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3-
exports[`when cache file has invalid content, getPostGraphileBuilder should error 1`] = `[Error: Failed to parse cache file 'path/to/cache', perhaps it is corrupted? SyntaxError: Unexpected token h in JSON at position 1]`;
3+
exports[`When readCache is String if cache file has invalid content, getPostGraphileBuilder should error 1`] = `[Error: Failed to parse cache file 'path/to/cache', perhaps it is corrupted? SyntaxError: Unexpected token h in JSON at position 1]`;
4+
5+
exports[`when readCache is not String or Object, getPostGraphileBuilder should error when its Array 1`] = `[Error: 'readCache' not understood; expected string or object, but received 'array']`;
6+
7+
exports[`when readCache is not String or Object, getPostGraphileBuilder should error when its Boolean 1`] = `[Error: 'readCache' not understood; expected string or object, but received 'boolean']`;
8+
9+
exports[`when readCache is not String or Object, getPostGraphileBuilder should error when its Number 1`] = `[Error: 'readCache' not understood; expected string or object, but received 'number']`;

packages/postgraphile-core/__tests__/unit/read-cache.test.js

+112-43
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,16 @@ beforeEach(() => {
1111
});
1212

1313
/*
14-
1514
Current behaviour of getPostGraphileBuilder and readCache option:
1615
16+
If readCache is String:
1717
1. cacheString is loaded by reading the file defined by readCache
1818
2. memoizeCache is set by JSON.parse(cacheString)
19+
20+
If readCache is Object:
21+
1. memoizeCache is set as readCache directly
22+
23+
Then
1924
3. persistentMemoizeWithKey is a function created dynamically that will use memoizeCache
2025
4. getBuilder(imported from graphile-build) is called, passing persistentMemoizeWithKey as one of the arguments
2126
@@ -24,34 +29,7 @@ Test strategy for readCache
2429
1. Mock fs.readFile to control input
2530
2. Mock getBuilder to control output
2631
3. Test different inputs and validate that getBuilder is called with expected output
27-
2832
*/
29-
30-
test("when cache file has content, persistentMemoizeWithKey should be a valid function", async () => {
31-
// mock fs.readFile to return an object
32-
fs.readFile.mockImplementationOnce((path, options, cb) =>
33-
cb(null, '{ "__test": true }')
34-
);
35-
36-
// mock getBuilder to fake output
37-
const expectedOutput = {};
38-
graphileBuild.getBuilder.mockResolvedValueOnce(expectedOutput);
39-
// call our method and test output
40-
const output = await getPostGraphileBuilder({}, [], {
41-
readCache: "path/to/cache",
42-
});
43-
expect(output).toBe(expectedOutput);
44-
expect(fs.readFile).toHaveBeenCalledTimes(1);
45-
expect(graphileBuild.getBuilder).toHaveBeenCalledTimes(1);
46-
// check persistentMemoizeWithKey, the actual "result" of readCache flag
47-
const {
48-
persistentMemoizeWithKey,
49-
} = graphileBuild.getBuilder.mock.calls[0][1];
50-
expect(typeof persistentMemoizeWithKey).toBe("function");
51-
expect(persistentMemoizeWithKey("__test")).toEqual(true);
52-
expect(() => persistentMemoizeWithKey("unknown_key")).toThrow();
53-
});
54-
5533
test("when no readCache flag, persistentMemoizeWithKey should be undefined", async () => {
5634
// mock getBuilder to fake output
5735
const expectedOutput = {};
@@ -67,22 +45,113 @@ test("when no readCache flag, persistentMemoizeWithKey should be undefined", asy
6745
expect(persistentMemoizeWithKey).toBeUndefined();
6846
});
6947

70-
test("when cache file has invalid content, getPostGraphileBuilder should error", async () => {
71-
// mock fs.readFile to return an object
72-
fs.readFile.mockImplementationOnce((path, options, cb) =>
73-
cb(null, "thisisnotjson")
74-
);
75-
76-
// call our method and check error
48+
describe("When readCache is String", () => {
49+
test("if cache file has content, persistentMemoizeWithKey should be a valid function", async () => {
50+
// mock fs.readFile to return an object
51+
fs.readFile.mockImplementationOnce((path, options, cb) =>
52+
cb(null, '{ "__test": true }')
53+
);
7754

78-
let error;
79-
try {
80-
await getPostGraphileBuilder({}, [], {
55+
// mock getBuilder to fake output
56+
const expectedOutput = {};
57+
graphileBuild.getBuilder.mockResolvedValueOnce(expectedOutput);
58+
// call our method and test output
59+
const output = await getPostGraphileBuilder({}, [], {
8160
readCache: "path/to/cache",
8261
});
83-
} catch (e) {
84-
error = e;
85-
}
86-
expect(error).toMatchSnapshot();
87-
expect(fs.readFile).toHaveBeenCalledTimes(1);
62+
expect(output).toBe(expectedOutput);
63+
expect(fs.readFile).toHaveBeenCalledTimes(1);
64+
expect(graphileBuild.getBuilder).toHaveBeenCalledTimes(1);
65+
// check persistentMemoizeWithKey, the actual "result" of readCache flag
66+
const {
67+
persistentMemoizeWithKey,
68+
} = graphileBuild.getBuilder.mock.calls[0][1];
69+
expect(typeof persistentMemoizeWithKey).toBe("function");
70+
expect(persistentMemoizeWithKey("__test")).toEqual(true);
71+
expect(() => persistentMemoizeWithKey("unknown_key")).toThrow();
72+
});
73+
74+
test("if cache file has invalid content, getPostGraphileBuilder should error", async () => {
75+
// mock fs.readFile to return an object
76+
fs.readFile.mockImplementationOnce((path, options, cb) =>
77+
cb(null, "thisisnotjson")
78+
);
79+
80+
// call our method and check error
81+
82+
let error;
83+
try {
84+
await getPostGraphileBuilder({}, [], {
85+
readCache: "path/to/cache",
86+
});
87+
} catch (e) {
88+
error = e;
89+
}
90+
expect(error).toBeDefined();
91+
expect(error).toMatchSnapshot();
92+
expect(fs.readFile).toHaveBeenCalledTimes(1);
93+
});
94+
});
95+
96+
describe("When readCache is Object", () => {
97+
test("persistentMemoizeWithKey should be a valid function", async () => {
98+
// mock getBuilder to fake output
99+
const expectedOutput = {};
100+
graphileBuild.getBuilder.mockResolvedValueOnce(expectedOutput);
101+
// call our method and test output
102+
const output = await getPostGraphileBuilder({}, [], {
103+
readCache: { __test: true },
104+
});
105+
expect(output).toBe(expectedOutput);
106+
expect(graphileBuild.getBuilder).toHaveBeenCalledTimes(1);
107+
// check persistentMemoizeWithKey, the actual "result" of readCache flag
108+
const {
109+
persistentMemoizeWithKey,
110+
} = graphileBuild.getBuilder.mock.calls[0][1];
111+
expect(typeof persistentMemoizeWithKey).toBe("function");
112+
expect(persistentMemoizeWithKey("__test")).toEqual(true);
113+
expect(() => persistentMemoizeWithKey("unknown_key")).toThrow();
114+
});
115+
});
116+
117+
describe("when readCache is not String or Object, getPostGraphileBuilder should error", () => {
118+
test("when its Boolean", async () => {
119+
// call our method with invalid readCache value and check error
120+
let error;
121+
try {
122+
await getPostGraphileBuilder({}, [], {
123+
readCache: true,
124+
});
125+
} catch (e) {
126+
error = e;
127+
}
128+
expect(error).toBeDefined();
129+
expect(error).toMatchSnapshot();
130+
});
131+
test("when its Array", async () => {
132+
// call our method with invalid readCache value and check error
133+
let error;
134+
try {
135+
await getPostGraphileBuilder({}, [], {
136+
readCache: [],
137+
});
138+
} catch (e) {
139+
error = e;
140+
}
141+
expect(error).toBeDefined();
142+
expect(error).toMatchSnapshot();
143+
});
144+
test("when its Number", async () => {
145+
// call our method with invalid readCache value and check error
146+
let error;
147+
try {
148+
await getPostGraphileBuilder({}, [], {
149+
readCache: 3,
150+
});
151+
} catch (e) {
152+
error = e;
153+
}
154+
expect(error).toBeDefined();
155+
expect(error).toMatchSnapshot();
156+
});
88157
});

packages/postgraphile-core/src/index.ts

+29-14
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ export interface PostGraphileCoreOptions {
9292
*/
9393
viewUniqueKey?: string;
9494
enableTags?: boolean;
95-
readCache?: string;
95+
readCache?: string | object;
9696
writeCache?: string;
9797
setWriteCacheCallback?: (fn: () => Promise<void>) => void;
9898
legacyRelations?: "only" | "deprecated" | "omit";
@@ -265,22 +265,37 @@ export const getPostGraphileBuilder = async (
265265

266266
let persistentMemoizeWithKey; // NOT null, otherwise it won't default correctly.
267267
let memoizeCache = {};
268-
269268
if (readCache) {
270-
const cacheString: string = await new Promise<string>((resolve, reject) => {
271-
fs.readFile(readCache, "utf8", (err?: Error | null, data?: string) => {
272-
if (err) {
273-
reject(err);
274-
} else {
275-
resolve(data);
269+
if (typeof readCache === "string") {
270+
const cacheString: string = await new Promise<string>(
271+
(resolve, reject) => {
272+
fs.readFile(
273+
readCache,
274+
"utf8",
275+
(err?: Error | null, data?: string) => {
276+
if (err) {
277+
reject(err);
278+
} else {
279+
resolve(data);
280+
}
281+
}
282+
);
276283
}
277-
});
278-
});
279-
try {
280-
memoizeCache = JSON.parse(cacheString);
281-
} catch (e) {
284+
);
285+
try {
286+
memoizeCache = JSON.parse(cacheString);
287+
} catch (e) {
288+
throw new Error(
289+
`Failed to parse cache file '${readCache}', perhaps it is corrupted? ${e}`
290+
);
291+
}
292+
} else if (typeof readCache === "object" && !Array.isArray(readCache)) {
293+
memoizeCache = readCache;
294+
} else {
282295
throw new Error(
283-
`Failed to parse cache file '${readCache}', perhaps it is corrupted? ${e}`
296+
`'readCache' not understood; expected string or object, but received '${
297+
Array.isArray(readCache) ? "array" : typeof readCache
298+
}'`
284299
);
285300
}
286301
}

0 commit comments

Comments
 (0)