-
Notifications
You must be signed in to change notification settings - Fork 24
Expand file tree
/
Copy pathdirectives.ts
More file actions
45 lines (41 loc) · 1.57 KB
/
Copy pathdirectives.ts
File metadata and controls
45 lines (41 loc) · 1.57 KB
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
import { defaultFieldResolver, GraphQLError, GraphQLSchema } from "graphql";
import { Int } from "grats";
import { Ctx } from "../ViewerContext.js";
import { getDirective, MapperKind, mapSchema } from "@graphql-tools/utils";
/**
* Some fields cost credits to access. This directive specifies how many credits
* a given field costs.
*
* @gqlDirective cost on FIELD_DEFINITION
*/
export function debitCredits(args: { credits: Int }, context: Ctx): void {
if (context.credits < args.credits) {
// Using `GraphQLError` here ensures the error is not masked by Yoga.
throw new GraphQLError(
`Insufficient credits remaining. This field cost ${args.credits} credits.`,
);
}
context.credits -= args.credits;
}
type CostArgs = { credits: Int };
// Monkey patches the `resolve` function of fields with the `@cost` directive
// to deduct credits from the user's account when the field is accessed.
export function applyCreditLimit(schema: GraphQLSchema): GraphQLSchema {
return mapSchema(schema, {
[MapperKind.OBJECT_FIELD]: (fieldConfig) => {
const costDirective = getDirective(schema, fieldConfig, "cost", [
"grats",
"directives",
]);
if (costDirective == null || costDirective.length === 0) {
return fieldConfig;
}
const originalResolve = fieldConfig.resolve ?? defaultFieldResolver;
fieldConfig.resolve = (source, args, context, info) => {
debitCredits(costDirective[0] as CostArgs, context);
return originalResolve(source, args, context, info);
};
return fieldConfig;
},
});
}