-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
index.js
88 lines (74 loc) · 2.37 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
'use strict'
const EventEmitter = require('events')
const fp = require('fastify-plugin')
const { GraphQLObjectType } = require('graphql')
const MemoryStore = require('./lib/MemoryStore')
const kVisited = Symbol('mercurius-hit-map:visited')
function mercuriusHitMap (app, opts, next) {
const ee = new EventEmitter()
const store = opts.store?.(ee) || MemoryStore(ee)
if (opts.store && typeof store.readHits !== 'function') {
return next(new Error('store factory must return an object with a readHits function'))
}
app.decorate('getHitMap', async function getHitMap () { return store.readHits() })
try {
wrapGqlSchema(app.graphql.schema, hitCounter)
next()
} catch (error) {
next(error)
}
function hitCounter (originalFn, objectType, objectField) {
ee.emit('wrap', {
typeName: objectType.name,
fieldName: objectField.name,
rawType: objectType,
rawField: objectField
})
return function hitResolver (...args) {
try {
ee.emit('hit', {
typeName: objectType.name,
fieldName: objectField.name,
rawType: objectType,
rawField: objectField
})
} catch (error) {
app.log.warn(error, 'Error while emitting hit event')
}
return originalFn(...args)
}
}
}
function wrapGqlSchema (schema, hitCounter) {
const typeMap = schema.getTypeMap()
for (const type of Object.values(typeMap)) {
if (type instanceof GraphQLObjectType && !isSystemType(type)) {
wrapType(type, hitCounter)
}
}
}
function wrapType (objectType, hitCounter) {
// if (objectType[kVisited] || !objectType.getFields) { return }
const fields = objectType.getFields()
for (const typeField of Object.values(fields)) {
const resolveFn = typeField.resolve || buildDefaultResolver(typeField)
// if (!typeField[kVisited]) { // ? coverage
typeField[kVisited] = true
typeField.resolve = hitCounter(resolveFn, objectType, typeField)
// }
}
}
function buildDefaultResolver (objectField) {
return parent => parent[objectField.name]
}
function isSystemType (objectType) {
// __Schema, __Type, __TypeKind, __Field, __InputValue, __EnumValue, __Directive
return objectType.astNode === undefined && objectType.name.startsWith('__')
}
module.exports = fp(mercuriusHitMap,
{
name: 'mercurius-hit-map',
fastify: '5.x',
dependencies: ['mercurius']
}
)