mercurius-cache
Advanced tools
Comparing version 0.4.0 to 0.5.0
21
index.js
@@ -61,7 +61,8 @@ 'use strict' | ||
for (const [fieldName, field] of Object.entries(schemaType.getFields())) { | ||
if (all || fieldPolicy[fieldName]) { | ||
const policy = fieldPolicy[fieldName] | ||
if (all || policy) { | ||
// Override resolvers for caching purposes | ||
if (typeof field.resolve === 'function') { | ||
const originalFieldResolver = field.resolve | ||
field.resolve = makeCachedResolver(schemaType.toString(), fieldName, cache, originalFieldResolver, skip, remoteCache, onHit, onMiss) | ||
field.resolve = makeCachedResolver(schemaType.toString(), fieldName, cache, originalFieldResolver, policy, skip, remoteCache, onHit, onMiss) | ||
} | ||
@@ -74,3 +75,3 @@ } | ||
function makeCachedResolver (prefix, fieldName, cache, originalFieldResolver, skip, remoteCache, onHit, onMiss) { | ||
function makeCachedResolver (prefix, fieldName, cache, originalFieldResolver, policy, skip, remoteCache, onHit, onMiss) { | ||
const name = prefix + '.' + fieldName | ||
@@ -82,3 +83,3 @@ onHit = onHit.bind(null, prefix, fieldName) | ||
onHit, | ||
serialize ({ self, arg, info }) { | ||
serialize ({ self, arg, info, ctx }) { | ||
// We need to cache only for the selected fields to support Federation | ||
@@ -97,6 +98,14 @@ // TODO detect if we really need to do this in most cases | ||
let extendKey | ||
if (policy && policy.extendKey) { | ||
const append = policy.extendKey(self, arg, ctx, info) | ||
if (append) { | ||
extendKey = '~' + append | ||
} | ||
} | ||
// We must skip ctx and info as they are not easy to serialize | ||
return { self, arg, fields } | ||
return { self, arg, fields, extendKey } | ||
} | ||
}, async function ({ self, arg, ctx, info }, key) { | ||
}, async function ({ self, arg, ctx, info, extendKey }, key) { | ||
if (remoteCache) { | ||
@@ -103,0 +112,0 @@ const val = await remoteCache.get(name + '~' + key) |
{ | ||
"name": "mercurius-cache", | ||
"version": "0.4.0", | ||
"version": "0.5.0", | ||
"description": "Cache the results of your GraphQL resolvers, for Mercurius", | ||
@@ -26,5 +26,5 @@ "main": "index.js", | ||
"@fastify/pre-commit": "^2.0.2", | ||
"@sinonjs/fake-timers": "^7.1.2", | ||
"fastify": "^3.18.1", | ||
"mercurius": "^8.0.0", | ||
"@sinonjs/fake-timers": "^8.0.0", | ||
"fastify": "^3.21.3", | ||
"mercurius": "^8.2.1", | ||
"snazzy": "^9.0.0", | ||
@@ -31,0 +31,0 @@ "standard": "^16.0.3", |
134
README.md
@@ -19,3 +19,3 @@ # mercurius-cache | ||
## Usage | ||
## Quick start | ||
@@ -27,3 +27,3 @@ ```js | ||
const mercurius = require('mercurius') | ||
const cache = require('.') | ||
const cache = require('mercurius-cache') | ||
@@ -43,3 +43,3 @@ const app = fastify({ logger: true }) | ||
reply.log.info('add called') | ||
for (let i = 0; i < 10000000; i++) {} | ||
for (let i = 0; i < 10000000; i++) {} // something that takes time | ||
return x + y | ||
@@ -55,22 +55,115 @@ } | ||
// cache query "add" responses for 10 seconds | ||
app.register(cache, { | ||
// all: true, // install the cache in all resolvers | ||
// ttl: 10, // cache deta in process for ten seconds, default 0 | ||
ttl: 10, | ||
policy: { | ||
Query: { | ||
add: true | ||
// note: it cache "add" but it doesn't cache "hello" | ||
} | ||
} | ||
}) | ||
app.listen(3000) | ||
// Use the following to test | ||
// curl -X POST -H 'content-type: application/json' -d '{ "query": "{ add(x: 2, y: 2) }" }' localhost:3000/graphql | ||
``` | ||
## Options | ||
- **ttl** | ||
the time to live in seconds, default is zero, which means that the cache is disabled. | ||
Example | ||
```js | ||
ttl: 10 | ||
``` | ||
- **policy** | ||
specify queries to cache; default is empty. | ||
Example | ||
```js | ||
policy: { | ||
Query: { | ||
add: true | ||
} | ||
} | ||
``` | ||
- **policy~extendKey** | ||
extend the key to cache responses by different request, for example to enable custom cache per user; see [example/cache-per-user.js](example/cache-per-user.js) for a complete use case. | ||
```js | ||
policy: { | ||
Query: { | ||
welcome: { | ||
extendKey: function (source, args, context, info) { | ||
return context.userId ? `user:${context.userId}` : undefined | ||
} | ||
} | ||
} | ||
} | ||
``` | ||
- **all** | ||
use the cache in all resolvers; default is false. Use either `policy` or `all` but not both. | ||
Example | ||
```js | ||
all: true | ||
``` | ||
- **remoteCache** | ||
default cache is in memory, the remote cache is useful for a larger cache. See [example/redis.js](example/redis.js) for a complete use case. | ||
Example | ||
```js | ||
remoteCache: { | ||
// The remote cache is useful as a larger cache | ||
async get (key) { | ||
return ... // fetch a key from Redis | ||
// fetch by key from storage | ||
return storage.get(key) | ||
}, | ||
async set (key, value) { | ||
// set the value in Redis | ||
// set the value in the storage | ||
return storage.set(key, value) | ||
} | ||
}, | ||
} | ||
``` | ||
- **onHit** | ||
called when a cached value is returned. | ||
Example | ||
```js | ||
onHit (type, fieldName) { | ||
// Called when a cached value is returned | ||
}, | ||
console.log(`hit ${type} ${fieldName}`) | ||
} | ||
``` | ||
- **onMiss** | ||
called when there is no value in the cache; it is not called if a resolver is skipped. | ||
Example | ||
```js | ||
onMiss (type, fieldName) { | ||
// Called when there is no value in the cache | ||
// It is not called if a resolver is skipped | ||
}, | ||
// Useful to skip the cache for authenticated users or in some other condition | ||
console.log(`miss ${type} ${fieldName}`) | ||
} | ||
``` | ||
- **skip** | ||
skip cache use for a specific condition. | ||
Example | ||
```js | ||
skip (self, arg, ctx, info) { | ||
@@ -82,13 +175,2 @@ if (ctx.reply.request.headers.authorization) { | ||
} | ||
policy: { | ||
Query: { | ||
add: true | ||
} | ||
} | ||
}) | ||
app.listen(3000) | ||
// Use the following to test | ||
// curl -X POST -H 'content-type: application/json' -d '{ "query": "{ add(x: 2, y: 2) }" }' localhost:3000/graphql | ||
``` | ||
@@ -95,0 +177,0 @@ |
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
40679
15
1603
176