mercurius-cache
Advanced tools
Comparing version 0.1.0 to 0.2.0
28
index.js
@@ -6,3 +6,3 @@ 'use strict' | ||
module.exports = fp(async function (app, { all, policy, ttl, cacheSize }) { | ||
module.exports = fp(async function (app, { all, policy, ttl, cacheSize, skip, remoteCache }) { | ||
if (typeof policy !== 'object' && !all) { | ||
@@ -22,3 +22,3 @@ throw new Error('policy must be an object') | ||
buildCache() | ||
setupSchema(app.graphql.schema, policy, all, cache) | ||
setupSchema(app.graphql.schema, policy, all, cache, skip, remoteCache) | ||
}, | ||
@@ -38,3 +38,3 @@ | ||
buildCache() | ||
setupSchema(schema, policy, all, cache) | ||
setupSchema(schema, policy, all, cache, skip, remoteCache) | ||
}) | ||
@@ -50,3 +50,3 @@ | ||
function setupSchema (schema, policy, all, cache) { | ||
function setupSchema (schema, policy, all, cache, skip, remoteCache) { | ||
const schemaTypeMap = schema.getTypeMap() | ||
@@ -66,3 +66,3 @@ for (const schemaType of Object.values(schemaTypeMap)) { | ||
const originalFieldResolver = field.resolve | ||
field.resolve = makeCachedResolver(schemaType.toString(), fieldName, cache, originalFieldResolver) | ||
field.resolve = makeCachedResolver(schemaType.toString(), fieldName, cache, originalFieldResolver, skip, remoteCache) | ||
} | ||
@@ -75,3 +75,3 @@ } | ||
function makeCachedResolver (prefix, fieldName, cache, originalFieldResolver) { | ||
function makeCachedResolver (prefix, fieldName, cache, originalFieldResolver, skip, remoteCache) { | ||
const name = prefix + '.' + fieldName | ||
@@ -96,9 +96,21 @@ cache.define(name, { | ||
} | ||
}, async function ({ self, arg, ctx, info }) { | ||
}, async function ({ self, arg, ctx, info }, key) { | ||
if (remoteCache) { | ||
const val = await remoteCache.get(name + '~' + key) | ||
if (val) { | ||
return val | ||
} | ||
} | ||
const res = await originalFieldResolver(self, arg, ctx, info) | ||
if (remoteCache) { | ||
await remoteCache.set(name + '~' + key, JSON.stringify(res)) | ||
} | ||
return res | ||
}) | ||
return function (self, arg, ctx, info) { | ||
return async function (self, arg, ctx, info) { | ||
if (skip && await skip(self, arg, ctx, info)) { | ||
return originalFieldResolver(self, arg, ctx, info) | ||
} | ||
return cache[name]({ self, arg, ctx, info }) | ||
} | ||
} |
{ | ||
"name": "mercurius-cache", | ||
"version": "0.1.0", | ||
"version": "0.2.0", | ||
"description": "Cache the results of your GraphQL resolvers, for Mercurius", | ||
@@ -34,3 +34,3 @@ "main": "index.js", | ||
"dependencies": { | ||
"async-cache-dedupe": "^0.2.0", | ||
"async-cache-dedupe": "^0.3.0", | ||
"fastify-plugin": "^3.0.0" | ||
@@ -37,0 +37,0 @@ }, |
@@ -55,3 +55,19 @@ # mercurius-cache | ||
// all: true, // install the cache in all resolvers | ||
// ttl: 10, // ten seconds, default 0 | ||
// ttl: 10, // cache deta in process for ten seconds, default 0 | ||
remoteCache: { | ||
// The remote cache is useful as a larger cache | ||
async get (key) { | ||
return ... // fetch a key from Redis | ||
}, | ||
async set (key, value) { | ||
// set the value in Redis | ||
} | ||
}, | ||
// Useful to skip the cache for authenticated users or in some other condition | ||
skip (self, arg, ctx, info) { | ||
if (ctx.reply.request.headers.authorization) { | ||
return true | ||
} | ||
return false | ||
} | ||
policy: { | ||
@@ -58,0 +74,0 @@ Query: { |
@@ -8,2 +8,4 @@ 'use strict' | ||
const FakeTimers = require('@sinonjs/fake-timers') | ||
test('cache a resolver', async ({ equal, same, pass, plan, teardown }) => { | ||
@@ -385,1 +387,176 @@ plan(5) | ||
}) | ||
test('skip the cache', async ({ equal, same, pass, plan, teardown }) => { | ||
plan(8) | ||
const app = fastify() | ||
teardown(app.close.bind(app)) | ||
const schema = ` | ||
type Query { | ||
add(x: Int, y: Int): Int | ||
hello: String | ||
} | ||
` | ||
const resolvers = { | ||
Query: { | ||
async add (_, { x, y }) { | ||
pass('add called twice') | ||
return x + y | ||
} | ||
} | ||
} | ||
app.register(mercurius, { | ||
schema, | ||
resolvers | ||
}) | ||
app.register(cache, { | ||
async skip (self, arg, ctx, info) { | ||
same(arg, { x: 2, y: 2 }) | ||
if (ctx.reply.request.headers.authorization) { | ||
return true | ||
} | ||
return false | ||
}, | ||
policy: { | ||
Query: { | ||
add: true | ||
} | ||
} | ||
}) | ||
const query = '{ add(x: 2, y: 2) }' | ||
{ | ||
const res = await app.inject({ | ||
method: 'POST', | ||
url: '/graphql', | ||
body: { | ||
query | ||
} | ||
}) | ||
equal(res.statusCode, 200) | ||
same(res.json(), { | ||
data: { | ||
add: 4 | ||
} | ||
}) | ||
} | ||
{ | ||
const res = await app.inject({ | ||
method: 'POST', | ||
url: '/graphql', | ||
headers: { | ||
Authorization: 'Bearer xyz' | ||
}, | ||
body: { | ||
query | ||
} | ||
}) | ||
equal(res.statusCode, 200) | ||
same(res.json(), { | ||
data: { | ||
add: 4 | ||
} | ||
}) | ||
} | ||
}) | ||
test('external cache', async ({ equal, same, pass, plan, teardown }) => { | ||
plan(8) | ||
const clock = FakeTimers.install({ | ||
shouldAdvanceTime: true, | ||
advanceTimeDelta: 40 | ||
}) | ||
teardown(() => clock.uninstall()) | ||
const app = fastify() | ||
teardown(app.close.bind(app)) | ||
const schema = ` | ||
type Query { | ||
add(x: Int, y: Int): Int | ||
hello: String | ||
} | ||
` | ||
const resolvers = { | ||
Query: { | ||
async add (_, { x, y }) { | ||
pass('add called once') | ||
return x + y | ||
} | ||
} | ||
} | ||
app.register(mercurius, { | ||
schema, | ||
resolvers | ||
}) | ||
const map = new Map() | ||
app.register(cache, { | ||
ttl: 1, | ||
remoteCache: { | ||
async get (key) { | ||
pass('get called with ' + key) | ||
return map.get(key) | ||
}, | ||
async set (key, value) { | ||
pass('set called') | ||
map.set(key, value) | ||
} | ||
}, | ||
policy: { | ||
Query: { | ||
add: true | ||
} | ||
} | ||
}) | ||
const query = '{ add(x: 2, y: 2) }' | ||
{ | ||
const res = await app.inject({ | ||
method: 'POST', | ||
url: '/graphql', | ||
body: { | ||
query | ||
} | ||
}) | ||
equal(res.statusCode, 200) | ||
same(res.json(), { | ||
data: { | ||
add: 4 | ||
} | ||
}) | ||
} | ||
await clock.tickAsync(2000) | ||
{ | ||
const res = await app.inject({ | ||
method: 'POST', | ||
url: '/graphql', | ||
body: { | ||
query | ||
} | ||
}) | ||
equal(res.statusCode, 200) | ||
same(res.json(), { | ||
data: { | ||
add: 4 | ||
} | ||
}) | ||
} | ||
}) |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
31384
1261
88
+ Addedasync-cache-dedupe@0.3.0(transitive)
- Removedasync-cache-dedupe@0.2.0(transitive)
Updatedasync-cache-dedupe@^0.3.0