1 | 'use strict';
|
2 |
|
3 | Object.defineProperty(exports, "__esModule", {
|
4 | value: true
|
5 | });
|
6 | exports.attachConnectorsToContext = exports.addSchemaLevelResolveFunction = exports.buildSchemaFromTypeDefinitions = exports.addTracingToResolvers = exports.assertResolveFunctionsPresent = exports.addCatchUndefinedToSchema = exports.addResolveFunctionsToSchema = exports.addErrorLoggingToSchema = exports.forEachField = exports.SchemaError = exports.makeExecutableSchema = exports.generateSchema = undefined;
|
7 |
|
8 | var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
|
9 |
|
10 |
|
11 |
|
12 |
|
13 | var _language = require('graphql/language');
|
14 |
|
15 | var _lodash = require('lodash');
|
16 |
|
17 | var _utilities = require('graphql/utilities');
|
18 |
|
19 | var _type = require('graphql/type');
|
20 |
|
21 | var _tracing = require('./tracing');
|
22 |
|
23 |
|
24 |
|
25 | function SchemaError(message) {
|
26 | Error.captureStackTrace(this, this.constructor);
|
27 | this.message = message;
|
28 | }
|
29 | SchemaError.prototype = new Error();
|
30 |
|
31 | function generateSchema() {
|
32 | console.error('generateSchema is deprecated, use makeExecutableSchema instead');
|
33 | return _generateSchema.apply(undefined, arguments);
|
34 | }
|
35 |
|
36 |
|
37 | function _generateSchema(typeDefinitions, resolveFunctions, logger) {
|
38 | var allowUndefinedInResolve = arguments.length <= 3 || arguments[3] === undefined ? true : arguments[3];
|
39 |
|
40 | if (!typeDefinitions) {
|
41 | throw new SchemaError('Must provide typeDefinitions');
|
42 | }
|
43 | if (!resolveFunctions) {
|
44 | throw new SchemaError('Must provide resolveFunctions');
|
45 | }
|
46 |
|
47 |
|
48 |
|
49 | var schema = buildSchemaFromTypeDefinitions(typeDefinitions);
|
50 |
|
51 | addResolveFunctionsToSchema(schema, resolveFunctions);
|
52 |
|
53 | assertResolveFunctionsPresent(schema);
|
54 |
|
55 | if (!allowUndefinedInResolve) {
|
56 | addCatchUndefinedToSchema(schema);
|
57 | }
|
58 |
|
59 | if (logger) {
|
60 | addErrorLoggingToSchema(schema, logger);
|
61 | }
|
62 |
|
63 | return schema;
|
64 | }
|
65 |
|
66 | function makeExecutableSchema(_ref) {
|
67 | var typeDefs = _ref.typeDefs;
|
68 | var resolvers = _ref.resolvers;
|
69 | var connectors = _ref.connectors;
|
70 | var logger = _ref.logger;
|
71 | var _ref$allowUndefinedIn = _ref.allowUndefinedInResolve;
|
72 | var allowUndefinedInResolve = _ref$allowUndefinedIn === undefined ? false : _ref$allowUndefinedIn;
|
73 |
|
74 | var jsSchema = _generateSchema(typeDefs, resolvers, logger, allowUndefinedInResolve);
|
75 | if (typeof resolvers.__schema === 'function') {
|
76 |
|
77 |
|
78 | addSchemaLevelResolveFunction(jsSchema, resolvers.__schema);
|
79 | }
|
80 | if (connectors) {
|
81 |
|
82 |
|
83 | attachConnectorsToContext(jsSchema, connectors);
|
84 | }
|
85 | return jsSchema;
|
86 | }
|
87 |
|
88 | function concatenateTypeDefs(typeDefinitionsAry) {
|
89 | var functionsCalled = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
|
90 |
|
91 | var resolvedTypeDefinitions = [];
|
92 | typeDefinitionsAry.forEach(function (typeDef) {
|
93 | if (typeof typeDef === 'function') {
|
94 | if (!(typeDef in functionsCalled)) {
|
95 |
|
96 | functionsCalled[typeDef] = 1;
|
97 | resolvedTypeDefinitions = resolvedTypeDefinitions.concat(concatenateTypeDefs(typeDef(), functionsCalled));
|
98 | }
|
99 | } else {
|
100 | if (typeof typeDef === 'string') {
|
101 | resolvedTypeDefinitions.push(typeDef.trim());
|
102 | } else {
|
103 | var type = typeof typeDef === 'undefined' ? 'undefined' : _typeof(typeDef);
|
104 | throw new SchemaError('typeDef array must contain only strings and functions, got ' + type);
|
105 | }
|
106 | }
|
107 | });
|
108 | return (0, _lodash.uniq)(resolvedTypeDefinitions.map(function (x) {
|
109 | return x.trim();
|
110 | })).join('\n');
|
111 | }
|
112 |
|
113 | function buildSchemaFromTypeDefinitions(typeDefinitions) {
|
114 |
|
115 | var myDefinitions = typeDefinitions;
|
116 | if (typeof myDefinitions !== 'string') {
|
117 | if (!Array.isArray(myDefinitions)) {
|
118 |
|
119 | throw new SchemaError('`typeDefinitions` must be a string or array');
|
120 | }
|
121 | myDefinitions = concatenateTypeDefs(myDefinitions);
|
122 | }
|
123 | return (0, _utilities.buildASTSchema)((0, _language.parse)(myDefinitions));
|
124 | }
|
125 |
|
126 | function forEachField(schema, fn) {
|
127 | var typeMap = schema.getTypeMap();
|
128 | Object.keys(typeMap).forEach(function (typeName) {
|
129 | var type = typeMap[typeName];
|
130 |
|
131 | if (!(0, _type.getNamedType)(type).name.startsWith('__') && type instanceof _type.GraphQLObjectType) {
|
132 | (function () {
|
133 | var fields = type.getFields();
|
134 | Object.keys(fields).forEach(function (fieldName) {
|
135 | var field = fields[fieldName];
|
136 | fn(field, typeName, fieldName);
|
137 | });
|
138 | })();
|
139 | }
|
140 | });
|
141 | }
|
142 |
|
143 |
|
144 |
|
145 |
|
146 |
|
147 | function attachConnectorsToContext(schema, connectors) {
|
148 | if (!schema || !(schema instanceof _type.GraphQLSchema)) {
|
149 | throw new Error('schema must be an instance of GraphQLSchema. ' + 'This error could be caused by installing more than one version of GraphQL-JS');
|
150 | }
|
151 |
|
152 | if ((typeof connectors === 'undefined' ? 'undefined' : _typeof(connectors)) !== 'object') {
|
153 | var connectorType = typeof connectors === 'undefined' ? 'undefined' : _typeof(connectors);
|
154 | throw new Error('Expected connectors to be of type object, got ' + connectorType);
|
155 | }
|
156 | if (Object.keys(connectors).length === 0) {
|
157 | throw new Error('Expected connectors to not be an empty object');
|
158 | }
|
159 | if (Array.isArray(connectors)) {
|
160 | throw new Error('Expected connectors to be of type object, got Array');
|
161 | }
|
162 | if (schema._apolloConnectorsAttached) {
|
163 | throw new Error('Connectors already attached to context, cannot attach more than once');
|
164 | }
|
165 |
|
166 | schema._apolloConnectorsAttached = true;
|
167 | var attachconnectorFn = function attachconnectorFn(root, args, ctx) {
|
168 | if ((typeof ctx === 'undefined' ? 'undefined' : _typeof(ctx)) !== 'object') {
|
169 |
|
170 |
|
171 | var contextType = typeof ctx === 'undefined' ? 'undefined' : _typeof(ctx);
|
172 | throw new Error('Cannot attach connector because context is not an object: ' + contextType);
|
173 | }
|
174 | if (typeof ctx.connectors === 'undefined') {
|
175 |
|
176 | ctx.connectors = {};
|
177 | }
|
178 | Object.keys(connectors).forEach(function (connectorName) {
|
179 |
|
180 | ctx.connectors[connectorName] = new connectors[connectorName](ctx);
|
181 | });
|
182 | return root;
|
183 | };
|
184 | addSchemaLevelResolveFunction(schema, attachconnectorFn);
|
185 | }
|
186 |
|
187 |
|
188 |
|
189 | function addSchemaLevelResolveFunction(schema, fn) {
|
190 |
|
191 | var rootTypes = [schema.getQueryType(), schema.getMutationType(), schema.getSubscriptionType()].filter(function (x) {
|
192 | return !!x;
|
193 | });
|
194 | var rootResolveFn = runAtMostOnce(fn);
|
195 | rootTypes.forEach(function (type) {
|
196 | var fields = type.getFields();
|
197 | Object.keys(fields).forEach(function (fieldName) {
|
198 | fields[fieldName].resolve = wrapResolver(fields[fieldName].resolve, rootResolveFn);
|
199 | });
|
200 | });
|
201 | }
|
202 |
|
203 | function addResolveFunctionsToSchema(schema, resolveFunctions) {
|
204 | Object.keys(resolveFunctions).forEach(function (typeName) {
|
205 | var type = schema.getType(typeName);
|
206 | if (!type && typeName !== '__schema') {
|
207 | throw new SchemaError('"' + typeName + '" defined in resolvers, but not in schema');
|
208 | }
|
209 |
|
210 | Object.keys(resolveFunctions[typeName]).forEach(function (fieldName) {
|
211 | if (fieldName.startsWith('__')) {
|
212 |
|
213 |
|
214 | type[fieldName.substring(2)] = resolveFunctions[typeName][fieldName];
|
215 | return;
|
216 | }
|
217 |
|
218 | if (!type.getFields()[fieldName]) {
|
219 | throw new SchemaError(typeName + '.' + fieldName + ' defined in resolvers, but not in schema');
|
220 | }
|
221 | var field = type.getFields()[fieldName];
|
222 | var fieldResolve = resolveFunctions[typeName][fieldName];
|
223 | if (typeof fieldResolve === 'function') {
|
224 |
|
225 | setFieldProperties(field, { resolve: fieldResolve });
|
226 | } else {
|
227 | if ((typeof fieldResolve === 'undefined' ? 'undefined' : _typeof(fieldResolve)) !== 'object') {
|
228 | throw new SchemaError('Resolver ' + typeName + '.' + fieldName + ' must be object or function');
|
229 | }
|
230 | setFieldProperties(field, fieldResolve);
|
231 | }
|
232 | });
|
233 | });
|
234 | }
|
235 |
|
236 | function setFieldProperties(field, propertiesObj) {
|
237 | Object.keys(propertiesObj).forEach(function (propertyName) {
|
238 |
|
239 | field[propertyName] = propertiesObj[propertyName];
|
240 | });
|
241 | }
|
242 |
|
243 | function assertResolveFunctionsPresent(schema) {
|
244 | forEachField(schema, function (field, typeName, fieldName) {
|
245 |
|
246 | if (field.args.length > 0) {
|
247 | expectResolveFunction(field, typeName, fieldName);
|
248 | }
|
249 |
|
250 |
|
251 | if (!((0, _type.getNamedType)(field.type) instanceof _type.GraphQLScalarType)) {
|
252 | expectResolveFunction(field, typeName, fieldName);
|
253 | }
|
254 | });
|
255 | }
|
256 |
|
257 | function expectResolveFunction(field, typeName, fieldName) {
|
258 | if (!field.resolve) {
|
259 | throw new SchemaError('Resolve function missing for "' + typeName + '.' + fieldName + '"');
|
260 | }
|
261 | if (typeof field.resolve !== 'function') {
|
262 | throw new SchemaError('Resolver "' + typeName + '.' + fieldName + '" must be a function');
|
263 | }
|
264 | }
|
265 |
|
266 | function addErrorLoggingToSchema(schema, logger) {
|
267 | if (!logger) {
|
268 | throw new Error('Must provide a logger');
|
269 | }
|
270 | if (typeof logger.log !== 'function') {
|
271 | throw new Error('Logger.log must be a function');
|
272 | }
|
273 | forEachField(schema, function (field, typeName, fieldName) {
|
274 | var errorHint = typeName + '.' + fieldName;
|
275 |
|
276 | field.resolve = decorateWithLogger(field.resolve, logger, errorHint);
|
277 | });
|
278 | }
|
279 |
|
280 | function wrapResolver(innerResolver, outerResolver) {
|
281 | return function (obj, args, ctx, info) {
|
282 | var root = outerResolver(obj, args, ctx, info);
|
283 | if (innerResolver) {
|
284 | return innerResolver(root, args, ctx, info);
|
285 | }
|
286 | return defaultResolveFn(root, args, ctx, info);
|
287 | };
|
288 | }
|
289 |
|
290 |
|
291 |
|
292 |
|
293 |
|
294 | function decorateWithLogger(fn, logger) {
|
295 | var hint = arguments.length <= 2 || arguments[2] === undefined ? '' : arguments[2];
|
296 |
|
297 | if (typeof fn === 'undefined') {
|
298 |
|
299 | fn = defaultResolveFn;
|
300 | }
|
301 | return function () {
|
302 | try {
|
303 | return fn.apply(undefined, arguments);
|
304 | } catch (e) {
|
305 |
|
306 | var newE = new Error();
|
307 | newE.stack = e.stack;
|
308 | if (hint) {
|
309 | newE.originalMessage = e.message;
|
310 | newE.message = 'Error in resolver ' + hint + '\n' + e.message;
|
311 | }
|
312 | logger.log(newE);
|
313 |
|
314 | throw e;
|
315 | }
|
316 | };
|
317 | }
|
318 |
|
319 | function addCatchUndefinedToSchema(schema) {
|
320 | forEachField(schema, function (field, typeName, fieldName) {
|
321 | var errorHint = typeName + '.' + fieldName;
|
322 |
|
323 | field.resolve = decorateToCatchUndefined(field.resolve, errorHint);
|
324 | });
|
325 | }
|
326 |
|
327 | function addTracingToResolvers(schema, tracer) {
|
328 | forEachField(schema, function (field, typeName, fieldName) {
|
329 | var functionName = typeName + '.' + fieldName;
|
330 |
|
331 | field.resolve = (0, _tracing.decorateWithTracer)(field.resolve, tracer, { functionType: 'resolve', functionName: functionName });
|
332 | });
|
333 | }
|
334 |
|
335 | function decorateToCatchUndefined(fn, hint) {
|
336 | if (typeof fn === 'undefined') {
|
337 |
|
338 | fn = defaultResolveFn;
|
339 | }
|
340 | return function () {
|
341 | var result = fn.apply(undefined, arguments);
|
342 | if (typeof result === 'undefined') {
|
343 | throw new Error('Resolve function for "' + hint + '" returned undefined');
|
344 | }
|
345 | return result;
|
346 | };
|
347 | }
|
348 |
|
349 | function runAtMostOnce(fn) {
|
350 | var count = 0;
|
351 | var value = void 0;
|
352 | return function () {
|
353 | if (count === 0) {
|
354 | value = fn.apply(undefined, arguments);
|
355 | count += 1;
|
356 | }
|
357 | return value;
|
358 | };
|
359 | }
|
360 |
|
361 |
|
362 |
|
363 |
|
364 |
|
365 |
|
366 |
|
367 |
|
368 |
|
369 |
|
370 | function defaultResolveFn(source, args, context, _ref2) {
|
371 | var fieldName = _ref2.fieldName;
|
372 |
|
373 |
|
374 | if ((typeof source === 'undefined' ? 'undefined' : _typeof(source)) === 'object' || typeof source === 'function') {
|
375 | var property = source[fieldName];
|
376 | return typeof property === 'function' ? source[fieldName]() : property;
|
377 | }
|
378 | }
|
379 |
|
380 | exports.generateSchema = generateSchema;
|
381 | exports.
|
382 | makeExecutableSchema = makeExecutableSchema;
|
383 | exports.SchemaError = SchemaError;
|
384 | exports.forEachField = forEachField;
|
385 | exports.addErrorLoggingToSchema = addErrorLoggingToSchema;
|
386 | exports.addResolveFunctionsToSchema = addResolveFunctionsToSchema;
|
387 | exports.addCatchUndefinedToSchema = addCatchUndefinedToSchema;
|
388 | exports.assertResolveFunctionsPresent = assertResolveFunctionsPresent;
|
389 | exports.addTracingToResolvers = addTracingToResolvers;
|
390 | exports.buildSchemaFromTypeDefinitions = buildSchemaFromTypeDefinitions;
|
391 | exports.addSchemaLevelResolveFunction = addSchemaLevelResolveFunction;
|
392 | exports.attachConnectorsToContext = attachConnectorsToContext; |
\ | No newline at end of file |