Skip to content

Commit 35539a7

Browse files
authored
[response-cache] deprecate ttlPerType option in favor of ttlPerSchemaCoordinate (#2258)
* [response-cache] deprecate `ttlPerType` option in favor of `ttlPerSchemaCoordinate` * changeset * add tests
1 parent ad763b3 commit 35539a7

File tree

3 files changed

+129
-10
lines changed

3 files changed

+129
-10
lines changed

.changeset/twenty-camels-wonder.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
---
2+
'@envelop/response-cache': minor
3+
---
4+
5+
Deprecate `ttlPerType` in favor of `ttlPerSchemaCoordinate`, for a more streamlined API
6+
7+
## Migration instructions
8+
9+
If you where using `ttlPerType`, you can merge the object into the `ttlPerSchemaCoordinate`, the
10+
syntax doesn't change.
11+
12+
```diff
13+
useResponseCache({
14+
session: null,
15+
- ttlPerType: {
16+
- User: 10_000,
17+
- Profile: 600_000,
18+
- },
19+
ttlPerSchemaCoordinate: {
20+
'Query.me': 0
21+
+ User: 10_000,
22+
+ Profile: 600_000,
23+
}
24+
})
25+
```

packages/plugins/response-cache/src/plugin.ts

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,7 @@ export type UseResponseCacheParameter<PluginContext extends Record<string, any>
6868
*/
6969
ttl?: number;
7070
/**
71-
* Overwrite the ttl for query operations whose execution result contains a specific object type.
72-
* Useful if the occurrence of a object time in the execution result should reduce or increase the TTL of the query operation.
73-
* The TTL per type is always favored over the global TTL.
71+
* @deprecated Use `ttlPerSchemaCoordinate` instead.
7472
*/
7573
ttlPerType?: Record<string, number>;
7674
/**
@@ -308,7 +306,7 @@ export function useResponseCache<PluginContext extends Record<string, any> = {}>
308306
session,
309307
enabled,
310308
ignoredTypes = [],
311-
ttlPerType = {},
309+
ttlPerType,
312310
ttlPerSchemaCoordinate = {},
313311
scopePerSchemaCoordinate = {},
314312
idFields = ['id'],
@@ -329,6 +327,16 @@ export function useResponseCache<PluginContext extends Record<string, any> = {}>
329327

330328
// never cache Introspections
331329
ttlPerSchemaCoordinate = { 'Query.__schema': 0, ...ttlPerSchemaCoordinate };
330+
if (ttlPerType) {
331+
// eslint-disable-next-line no-console
332+
console.warn(
333+
'[useResponseCache] `ttlForType` is deprecated. To migrate, merge it with `ttlForSchemaCoordinate` option',
334+
);
335+
for (const [typeName, ttl] of Object.entries(ttlPerType)) {
336+
ttlPerSchemaCoordinate[typeName] = ttl;
337+
}
338+
}
339+
332340
const documentMetadataOptions = {
333341
queries: { invalidateViaMutation, ttlPerSchemaCoordinate },
334342
mutations: { invalidateViaMutation }, // remove ttlPerSchemaCoordinate for mutations to skip TTL calculation
@@ -366,7 +374,7 @@ export function useResponseCache<PluginContext extends Record<string, any> = {}>
366374
) as unknown as CacheControlDirective[] | undefined;
367375
cacheControlAnnotations?.forEach(cacheControl => {
368376
if (cacheControl.maxAge != null) {
369-
ttlPerType[type.name] = cacheControl.maxAge * 1000;
377+
ttlPerSchemaCoordinate[type.name] = cacheControl.maxAge * 1000;
370378
}
371379
if (cacheControl.scope) {
372380
scopePerSchemaCoordinate[type.name] = cacheControl.scope;
@@ -461,8 +469,8 @@ export function useResponseCache<PluginContext extends Record<string, any> = {}>
461469
}
462470

463471
types.add(entity.typename);
464-
if (entity.typename in ttlPerType) {
465-
const maybeTtl = ttlPerType[entity.typename] as unknown;
472+
if (entity.typename in ttlPerSchemaCoordinate) {
473+
const maybeTtl = ttlPerSchemaCoordinate[entity.typename] as unknown;
466474
currentTtl = calculateTtl(maybeTtl, currentTtl);
467475
}
468476
if (entity.id != null) {
@@ -473,8 +481,8 @@ export function useResponseCache<PluginContext extends Record<string, any> = {}>
473481
if (fieldData == null || (Array.isArray(fieldData) && fieldData.length === 0)) {
474482
const inferredTypes = typePerSchemaCoordinateMap.get(`${entity.typename}.${fieldName}`);
475483
inferredTypes?.forEach(inferredType => {
476-
if (inferredType in ttlPerType) {
477-
const maybeTtl = ttlPerType[inferredType] as unknown;
484+
if (inferredType in ttlPerSchemaCoordinate) {
485+
const maybeTtl = ttlPerSchemaCoordinate[inferredType] as unknown;
478486
currentTtl = calculateTtl(maybeTtl, currentTtl);
479487
}
480488
identifier.set(inferredType, { typename: inferredType });

packages/plugins/response-cache/test/response-cache.spec.ts

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import {
2727
describe('useResponseCache', () => {
2828
beforeEach(() => jest.useRealTimers());
2929

30-
it('custom ttl per type is used instead of the global ttl - only enable caching for a specific type when the global ttl is 0', async () => {
30+
it('deprecated ttlForType still work until removed', async () => {
3131
jest.useFakeTimers();
3232
const spy = jest.fn(() => [
3333
{
@@ -113,6 +113,92 @@ describe('useResponseCache', () => {
113113
expect(spy).toHaveBeenCalledTimes(2);
114114
});
115115

116+
it('custom ttl per type is used instead of the global ttl - only enable caching for a specific type when the global ttl is 0', async () => {
117+
jest.useFakeTimers();
118+
const spy = jest.fn(() => [
119+
{
120+
id: 1,
121+
name: 'User 1',
122+
comments: [
123+
{
124+
id: 1,
125+
text: 'Comment 1 of User 1',
126+
},
127+
],
128+
},
129+
{
130+
id: 2,
131+
name: 'User 2',
132+
comments: [
133+
{
134+
id: 2,
135+
text: 'Comment 2 of User 2',
136+
},
137+
],
138+
},
139+
]);
140+
141+
const schema = makeExecutableSchema({
142+
typeDefs: /* GraphQL */ `
143+
type Query {
144+
users: [User!]!
145+
}
146+
147+
type User {
148+
id: ID!
149+
name: String!
150+
comments: [Comment!]!
151+
recentComment: Comment
152+
}
153+
154+
type Comment {
155+
id: ID!
156+
text: String!
157+
}
158+
`,
159+
resolvers: {
160+
Query: {
161+
users: spy,
162+
},
163+
},
164+
});
165+
166+
const testInstance = createTestkit(
167+
[
168+
useResponseCache({
169+
session: () => null,
170+
ttl: 0,
171+
ttlPerSchemaCoordinate: {
172+
User: 200,
173+
},
174+
}),
175+
],
176+
schema,
177+
);
178+
179+
const query = /* GraphQL */ `
180+
query test {
181+
users {
182+
id
183+
name
184+
comments {
185+
id
186+
text
187+
}
188+
}
189+
}
190+
`;
191+
192+
await testInstance.execute(query);
193+
await testInstance.execute(query);
194+
expect(spy).toHaveBeenCalledTimes(1);
195+
await testInstance.execute(query);
196+
expect(spy).toHaveBeenCalledTimes(1);
197+
jest.advanceTimersByTime(201);
198+
await testInstance.execute(query);
199+
expect(spy).toHaveBeenCalledTimes(2);
200+
});
201+
116202
it('reuses the cache if the same query operation is executed in sequence without a TTL', async () => {
117203
const spy = jest.fn(() => [
118204
{

0 commit comments

Comments
 (0)