1 | ;
|
2 |
|
3 | Object.defineProperty(exports, "__esModule", {
|
4 | value: true
|
5 | });
|
6 | exports.GQLBase = exports.PROPS = exports.SETTERS = exports.GETTERS = exports.AUTO_PROPS = exports.META_KEY = exports.REQ_DATA_KEY = exports.MODEL_KEY = undefined;
|
7 |
|
8 | var _defineProperty = require('babel-runtime/core-js/object/define-property');
|
9 |
|
10 | var _defineProperty2 = _interopRequireDefault(_defineProperty);
|
11 |
|
12 | var _promise = require('babel-runtime/core-js/promise');
|
13 |
|
14 | var _promise2 = _interopRequireDefault(_promise);
|
15 |
|
16 | var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator');
|
17 |
|
18 | var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);
|
19 |
|
20 | var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
|
21 |
|
22 | var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
|
23 |
|
24 | var _toStringTag = require('babel-runtime/core-js/symbol/to-string-tag');
|
25 |
|
26 | var _toStringTag2 = _interopRequireDefault(_toStringTag);
|
27 |
|
28 | var _getOwnPropertyDescriptor = require('babel-runtime/core-js/object/get-own-property-descriptor');
|
29 |
|
30 | var _getOwnPropertyDescriptor2 = _interopRequireDefault(_getOwnPropertyDescriptor);
|
31 |
|
32 | var _keys = require('babel-runtime/core-js/object/keys');
|
33 |
|
34 | var _keys2 = _interopRequireDefault(_keys);
|
35 |
|
36 | var _symbol = require('babel-runtime/core-js/symbol');
|
37 |
|
38 | var _symbol2 = _interopRequireDefault(_symbol);
|
39 |
|
40 | var _for = require('babel-runtime/core-js/symbol/for');
|
41 |
|
42 | var _for2 = _interopRequireDefault(_for);
|
43 |
|
44 | exports.notDefined = notDefined;
|
45 |
|
46 | var _path = require('path');
|
47 |
|
48 | var _path2 = _interopRequireDefault(_path);
|
49 |
|
50 | var _fs = require('fs');
|
51 |
|
52 | var _fs2 = _interopRequireDefault(_fs);
|
53 |
|
54 | var _utils = require('./utils');
|
55 |
|
56 | var _neTypes = require('ne-types');
|
57 |
|
58 | var _SyntaxTree = require('./SyntaxTree');
|
59 |
|
60 | var _ModelProperties = require('./decorators/ModelProperties');
|
61 |
|
62 | var _graphql = require('graphql');
|
63 |
|
64 | var _IDLFileHandler = require('./IDLFileHandler');
|
65 |
|
66 | var _lodash = require('lodash');
|
67 |
|
68 | var _neTagFns = require('ne-tag-fns');
|
69 |
|
70 | var _AsyncFunctionExecutionError = require('./errors/AsyncFunctionExecutionError');
|
71 |
|
72 | var _AsyncFunctionExecutionError2 = _interopRequireDefault(_AsyncFunctionExecutionError);
|
73 |
|
74 | var _FunctionExecutionError = require('./errors/FunctionExecutionError');
|
75 |
|
76 | var _FunctionExecutionError2 = _interopRequireDefault(_FunctionExecutionError);
|
77 |
|
78 | var _AwaitingPromiseError = require('./errors/AwaitingPromiseError');
|
79 |
|
80 | var _AwaitingPromiseError2 = _interopRequireDefault(_AwaitingPromiseError);
|
81 |
|
82 | var _events = require('events');
|
83 |
|
84 | var _events2 = _interopRequireDefault(_events);
|
85 |
|
86 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
87 |
|
88 | /* Internal implementation to detect the existence of proxies. When present
|
89 | * additional functionality is enabled. Proxies are native in Node >= 6 */
|
90 | const hasProxy = typeof global.Proxy !== 'undefined';
|
91 |
|
92 | /* Internal Symbol referring to real accessor to GQLBase model object */
|
93 | /** @namespace GQLBaseEnv */
|
94 |
|
95 |
|
96 | const _MODEL_KEY = (0, _for2.default)('data-model-contents-value');
|
97 |
|
98 | /* Internal Symbol referring to the static object containing a proxy handler */
|
99 | const _PROXY_HANDLER = (0, _for2.default)('internal-base-proxy-handler');
|
100 |
|
101 | /**
|
102 | * Simple function to check if a supplied key matches a string of your
|
103 | * choosing and that string is not a defined property on the instance
|
104 | * passed to the check.
|
105 | *
|
106 | * @method GQLBaseEnv~notDefined
|
107 | * @memberof GQLBaseEnv
|
108 | * @since 2.5.0
|
109 | *
|
110 | * @param {string} keyToTest a String denoting the property you wish to test
|
111 | * @param {mixed} keySupplied a value, coerced `toString()`, to compare to
|
112 | * `keyToTest`
|
113 | * @param {mixed} instance an object instance to check `hasOwnProperty` on for
|
114 | * the `keyToTest` supplied.
|
115 | * @return {Boolean} true if the property matches the supplied key and that
|
116 | * property is not an ownedProperty of the instance supplied.
|
117 | */
|
118 | function notDefined(keyToTest, keySupplied, instance) {
|
119 | return new RegExp("^" + keyToTest + "$").test(keySupplied.toString()) && !instance.hasOwnProperty(keyToTest);
|
120 | }
|
121 |
|
122 | /**
|
123 | * A `Symbol` used as a key to store the backing model data. Designed as a
|
124 | * way to separate model data and GraphQL property accessors into logical bits.
|
125 | *
|
126 | * @type {Symbol}
|
127 | * @memberof GQLBaseEnv
|
128 | * @const
|
129 | */
|
130 | const MODEL_KEY = exports.MODEL_KEY = (0, _for2.default)('data-model-contents-key');
|
131 |
|
132 | /**
|
133 | * A `Symbol` used as a key to store the request data for an instance of the
|
134 | * GQLBase object in question.
|
135 | *
|
136 | * @type {Symbol}
|
137 | * @const
|
138 | * @inner
|
139 | * @memberof GQLBaseEnv
|
140 | */
|
141 | const REQ_DATA_KEY = exports.REQ_DATA_KEY = (0, _for2.default)('request-data-object-key');
|
142 |
|
143 | /**
|
144 | * A nameless Symbol for use as a key to the internal decorator storage
|
145 | *
|
146 | * @type {Symbol}
|
147 | * @const
|
148 | * @inner
|
149 | * @memberof GQLBaseEnv
|
150 | */
|
151 | const META_KEY = exports.META_KEY = (0, _symbol2.default)();
|
152 |
|
153 | /**
|
154 | * A Symbol used to identify calls to @Properties for properties generated
|
155 | * automatically upon instance creation.
|
156 | *
|
157 | * @type {Symbol}
|
158 | * @const
|
159 | * @inner
|
160 | * @memberOf GQLBaseEnv
|
161 | */
|
162 | const AUTO_PROPS = exports.AUTO_PROPS = (0, _for2.default)('auto-props');
|
163 |
|
164 | /**
|
165 | * A Symbol used to identify calls to @Getters for properties generated
|
166 | * via decorator. These are stored in <class>[META_KEY][GETTERS]
|
167 | *
|
168 | * @type {Symbol}
|
169 | * @const
|
170 | * @inner
|
171 | * @memberOf GQLBaseEnv
|
172 | */
|
173 | const GETTERS = exports.GETTERS = (0, _for2.default)('getters');
|
174 |
|
175 | /**
|
176 | * A Symbol used to identify calls to @Setters for properties generated
|
177 | * via decorator. These are stored in <class>[META_KEY][SETTERS]
|
178 | *
|
179 | * @type {Symbol}
|
180 | * @const
|
181 | * @inner
|
182 | * @memberOf GQLBaseEnv
|
183 | */
|
184 | const SETTERS = exports.SETTERS = (0, _for2.default)('setters');
|
185 |
|
186 | /**
|
187 | * A Symbol used to identify calls to @Properties for properties generated
|
188 | * via decorator. These are stored in <class>[META_KEY][PROPS]
|
189 | *
|
190 | * @type {Symbol}
|
191 | * @const
|
192 | * @inner
|
193 | * @memberOf GQLBaseEnv
|
194 | */
|
195 | const PROPS = exports.PROPS = (0, _for2.default)('props');
|
196 |
|
197 | /**
|
198 | * All GraphQL Type objects used in this system are assumed to have extended
|
199 | * from this class. An instance of this class can be used to wrap an existing
|
200 | * structure if you have one.
|
201 | *
|
202 | * @class GQLBase
|
203 | */
|
204 | let GQLBase = exports.GQLBase = class GQLBase extends _events2.default {
|
205 |
|
206 | /**
|
207 | * Request data is passed to this object when constructed. Typically these
|
208 | * objects, and their children, are instantiated by its own static MUTATORS
|
209 | * and RESOLVERS. They should contain request specific state if any is to
|
210 | * be shared.
|
211 | *
|
212 | * These can be considered request specific controllers for the object in
|
213 | * question. The base class takes a single object which should contain all
|
214 | * the HTTP/S request data and the graphQLParams is provided as the object
|
215 | * { query, variables, operationName, raw }.
|
216 | *
|
217 | * When used with express-graphql, the requestData object has the format
|
218 | * { req, res, gql } where
|
219 | * • req is an Express 4.x request object
|
220 | * • res is an Express 4.x response object
|
221 | * • gql is the graphQLParams object in the format of
|
222 | * { query, variables, operationName, raw }
|
223 | * See https://github.com/graphql/express-graphql for more info
|
224 | *
|
225 | * @memberof GQLBase
|
226 | * @method ⎆⠀constructor
|
227 | * @constructor
|
228 | *
|
229 | * @param {mixed} modelData this, typically an object, although anything
|
230 | * really is supported, represents the model data for our GraphQL object
|
231 | * instance.
|
232 | * @param {Object} requestData see description above
|
233 | */
|
234 | constructor(modelData = {}, requestData = null, options = { autoProps: true }) {
|
235 | super();
|
236 |
|
237 | const Class = this.constructor;
|
238 | const tree = _SyntaxTree.SyntaxTree.from(Class.SCHEMA);
|
239 | const outline = tree && tree.outline || null;
|
240 |
|
241 | if (!outline) {
|
242 | throw new _FunctionExecutionError2.default(new Error(_neTagFns.dedent`
|
243 | The SDL is unparsable. Please check your SCHEMA and make sure
|
244 | it is valid GraphQL SDL/IDL. Your SCHEMA is defined as:
|
245 |
|
246 | ${this.SCHEMA}
|
247 | `));
|
248 | }
|
249 |
|
250 | if (outline && !(Class.name in outline)) {
|
251 | throw new _FunctionExecutionError2.default(new Error(_neTagFns.dedent`
|
252 | The class name "${Class.name}" does not match any of the types,
|
253 | enums, scalars, unions or interfaces defined in the SCHEMA for
|
254 | this class (${(0, _keys2.default)(outline)}).
|
255 |
|
256 | \x1b[1mIn most clases this is because your class name and SCHEMA
|
257 | type do not match.\x1b[0m
|
258 | `));
|
259 | }
|
260 |
|
261 | GQLBase.setupModel(this);
|
262 | this.setModel(modelData);
|
263 | this.requestData = requestData || {};
|
264 | this.fileHandler = new _IDLFileHandler.IDLFileHandler(this.constructor);
|
265 |
|
266 | if (options && !!options.autoProps !== false) {
|
267 | this.applyAutoProps();
|
268 | }
|
269 |
|
270 | // @ComputedType
|
271 | return hasProxy ? new Proxy(this, GQLBase[_PROXY_HANDLER]) : this;
|
272 | }
|
273 |
|
274 | /**
|
275 | * Since reading the Schema for a given GraphQL Lattice type or
|
276 | * interface is simple enough, we should be able to automatically
|
277 | * apply one to one GraphQL:Model properties.
|
278 | *
|
279 | * @instance
|
280 | * @method ⌾⠀applyAutoProps
|
281 | * @memberof GQLBase
|
282 | */
|
283 | applyAutoProps() {
|
284 | if (!this.constructor.SCHEMA || !this.constructor.SCHEMA.length) {
|
285 | _utils.LatticeLogs.warn(_utils.joinLines`
|
286 | There is no SCHEMA for ${this.constructor.name}!! This will likely
|
287 | end in an error. Proceed with caution. Skipping \`applyAutoProps\`
|
288 | `);
|
289 | return;
|
290 | }
|
291 |
|
292 | // Individual property getters do not need to be auto-created for enum
|
293 | // types. Potentially do some checks for Interfaces and Unions as well
|
294 | if (this.constructor.GQL_TYPE === _graphql.GraphQLEnumType) {
|
295 | return;
|
296 | }
|
297 |
|
298 | let Class = this.constructor;
|
299 | let tree = _SyntaxTree.SyntaxTree.from(Class.SCHEMA);
|
300 | let outline = tree ? tree.outline : {};
|
301 | let props = [];
|
302 |
|
303 | // $FlowFixMe
|
304 | for (let propName of (0, _keys2.default)(outline[Class.name])) {
|
305 | // $FlowFixMe
|
306 | let desc = (0, _getOwnPropertyDescriptor2.default)(Class.prototype, propName);
|
307 | let hasCustomImpl = !!(
|
308 | // We have a descriptor for the property name
|
309 | desc && (
|
310 | // We have a getter function defined
|
311 | typeof desc.get !== 'undefined' ||
|
312 | // ...or we have a function, async or not, defined
|
313 | typeof desc.value === 'function'));
|
314 |
|
315 | // Only create auto-props for non custom implementations
|
316 | if (!hasCustomImpl) {
|
317 | props.push(propName);
|
318 | }
|
319 | }
|
320 |
|
321 | if (props.length) {
|
322 | _utils.LatticeLogs.info(`Creating auto-props for [${Class.name}]: `, props);
|
323 | try {
|
324 | (0, _ModelProperties.Properties)(...props)(Class, [AUTO_PROPS]);
|
325 | } catch (error) {
|
326 | let parsed = /Cannot redefine property: (\w+)/.exec(error.message);
|
327 | if (parsed) {
|
328 | _utils.LatticeLogs.warn(`Skipping auto-prop '${Class.name}.${parsed[1]}'`);
|
329 | } else {
|
330 | _utils.LatticeLogs.error(`Failed to apply auto-properties\nReason: `);
|
331 | _utils.LatticeLogs.error(error);
|
332 | }
|
333 | }
|
334 | }
|
335 | }
|
336 |
|
337 | /**
|
338 | * Getter for the internally stored model data. The contents of this
|
339 | * object are abstracted away behind a `Symbol` key to prevent collision
|
340 | * between the underlying model and any GraphQL Object Definition properties.
|
341 | *
|
342 | * @instance
|
343 | * @memberof GQLBase
|
344 | * @method ⌾⠀getModel
|
345 | * @since 2.5
|
346 | *
|
347 | * @param {Object} value any object you wish to use as a data store
|
348 | */
|
349 | getModel() {
|
350 | // @ComputedType
|
351 | return this[MODEL_KEY];
|
352 | }
|
353 |
|
354 | /**
|
355 | * Setter for the internally stored model data. The contents of this
|
356 | * object are abstracted away behind a `Symbol` key to prevent collision
|
357 | * between the underlying model and any GraphQL Object Definition properties.
|
358 | *
|
359 | * @instance
|
360 | * @memberof GQLBase
|
361 | * @method ⌾⠀setModel
|
362 | * @since 2.5
|
363 | *
|
364 | * @param {Object} value any object you wish to use as a data store
|
365 | */
|
366 | setModel(value) {
|
367 | // @ComputedType
|
368 | this[MODEL_KEY] = value;
|
369 | return this;
|
370 | }
|
371 |
|
372 | /**
|
373 | * Uses `_.merge()` to modify the internal backing data store for the
|
374 | * object instance. This is a shortcut for
|
375 | * `_.merge()(instance[MODEL_KEY], ...extensions)`
|
376 | *
|
377 | * @instance
|
378 | * @memberof GQLBase
|
379 | * @method ⌾⠀extendModel
|
380 | * @since 2.5
|
381 | *
|
382 | * @param {mixed} extensions n-number of valid `_.merge()` parameters
|
383 | * @return {GQLBase} this is returned
|
384 | */
|
385 | extendModel(...extensions) {
|
386 | // $FlowFixMe
|
387 | (0, _lodash.merge)(this[MODEL_KEY], ...extensions);
|
388 | return this;
|
389 | }
|
390 |
|
391 | /**
|
392 | * A getter that retrieves the inner request data object. When used with
|
393 | * GQLExpressMiddleware, this is an object matching {req, res, gql}.
|
394 | *
|
395 | * @instance
|
396 | * @memberof GQLBase
|
397 | * @method ⬇︎⠀requestData
|
398 | *
|
399 | * @return {Object} an object, usually matching { req, res, gql }
|
400 | */
|
401 | get requestData() {
|
402 | // @ComputedType
|
403 | return this[REQ_DATA_KEY];
|
404 | }
|
405 |
|
406 | /**
|
407 | * A setter that assigns a value to the inner request data object. When
|
408 | * used with GQLExpressMiddleware, this is an object matching {req, res, gql}.
|
409 | *
|
410 | * @instance
|
411 | * @memberof GQLBase
|
412 | * @method ⬆︎⠀requestData
|
413 | *
|
414 | * @param {Object} value an object, usually matching { req, res, gql }
|
415 | */
|
416 | set requestData(value) {
|
417 | // @ComputedType
|
418 | this[REQ_DATA_KEY] = value;
|
419 | }
|
420 |
|
421 | /**
|
422 | * Returns the `constructor` name. If invoked as the context, or `this`,
|
423 | * object of the `toString` method of `Object`'s `prototype`, the resulting
|
424 | * value will be `[object MyClass]`, given an instance of `MyClass`
|
425 | *
|
426 | * @method ⌾⠀[Symbol.toStringTag]
|
427 | * @memberof ModuleParser
|
428 | *
|
429 | * @return {string} the name of the class this is an instance of
|
430 | * @ComputedType
|
431 | */
|
432 | get [_toStringTag2.default]() {
|
433 | return this.constructor.name;
|
434 | }
|
435 |
|
436 | /**
|
437 | * Properties defined for GraphQL types in Lattice can be defined as
|
438 | * a getter, a function or an async function. In the case of standard
|
439 | * functions, if they return a promise they will be handled as though
|
440 | * they were async
|
441 | *
|
442 | * Given the variety of things a GraphQL type can actually be, obtaining
|
443 | * its value can annoying. This method tends to lessen that boilerplate.
|
444 | * Errors raised will be thrown.
|
445 | *
|
446 | * @instance
|
447 | * @memberof GQLBase
|
448 | * @method ⌾⠀getProp
|
449 | *
|
450 | * @param {string|Symbol} propName the name of the property in question
|
451 | * @param {boolean} bindGetters true, by default, if the `get` or
|
452 | * `initializer` descriptor values should be bound to the current instance
|
453 | * or an object of the programmers choice before returning
|
454 | * @param {mixed} bindTo the `this` object to use for binding when
|
455 | * `bindGetters` is set to true.
|
456 | * @return {mixed} the value of the `propName` as a Function or something
|
457 | * else when the requested property name exists
|
458 | *
|
459 | * @throws {Error} errors raised in awaiting results will be thrown
|
460 | */
|
461 | getProp(propName, bindGetters = true, bindTo) {
|
462 | // $FlowFixMe
|
463 | let proto = (0, _getPrototypeOf2.default)(this);
|
464 | let descriptor = (0, _getOwnPropertyDescriptor2.default)(proto, propName);
|
465 | let result;
|
466 |
|
467 | if (!descriptor) {
|
468 | return null;
|
469 | }
|
470 |
|
471 | if (descriptor) {
|
472 | if (descriptor.initializer || descriptor.get) {
|
473 | let what = descriptor.initializer || descriptor.get;
|
474 |
|
475 | if (bindGetters) {
|
476 | result = what.bind(bindTo || this);
|
477 | } else {
|
478 | result = what;
|
479 | }
|
480 | } else if (descriptor.value) {
|
481 | result = descriptor.value;
|
482 | }
|
483 | }
|
484 |
|
485 | return result;
|
486 | }
|
487 |
|
488 | /**
|
489 | * Properties defined for GraphQL types in Lattice can be defined as
|
490 | * a getter, a function or an async function. In the case of standard
|
491 | * functions, if they return a promise they will be handled as though
|
492 | * they were async. In addition to fetching the property, or field
|
493 | * resolver, its resulting function or getter will be invoked.
|
494 | *
|
495 | * Given the variety of things a GraphQL type can actually be, obtaining
|
496 | * its value can annoying. This method tends to lessen that boilerplate.
|
497 | * Errors raised will be thrown.
|
498 | *
|
499 | * @instance
|
500 | * @memberof GQLBase
|
501 | * @method ⌾⠀callProp
|
502 | *
|
503 | * @param {string} propName the name of the property in question
|
504 | * @param {Array<mixed>} args the arguments array that will be passed
|
505 | * to `.apply()` should the property evaluate to a `function`
|
506 | * @return {mixed} the return value of any resulting function or
|
507 | * value returned by a getter; wrapped in a promise as all async
|
508 | * functions do.
|
509 | *
|
510 | * @throws {Error} errors raised in awaiting results will be thrown
|
511 | */
|
512 | callProp(propName, ...args) {
|
513 | var _this = this;
|
514 |
|
515 | return (0, _asyncToGenerator3.default)(function* () {
|
516 | // $FlowFixMe
|
517 | let prop = _this.getProp(propName, ...args);
|
518 | let result;
|
519 |
|
520 | if (prop && (0, _neTypes.typeOf)(prop) === 'AsyncFunction') {
|
521 | try {
|
522 | result = yield prop.apply(_this, args);
|
523 | } catch (error) {
|
524 | throw new _AsyncFunctionExecutionError2.default(error, prop, args, result);
|
525 | }
|
526 | } else if (prop && (0, _neTypes.typeOf)(prop) === Function.name) {
|
527 | try {
|
528 | result = prop.apply(_this, args);
|
529 | } catch (error) {
|
530 | throw new _FunctionExecutionError2.default(error, prop, args, result);
|
531 | }
|
532 |
|
533 | if ((0, _neTypes.typeOf)(result) === _promise2.default.name) {
|
534 | try {
|
535 | result = yield result;
|
536 | } catch (error) {
|
537 | throw new _AwaitingPromiseError2.default(error).setPromise(result);
|
538 | }
|
539 | }
|
540 | }
|
541 |
|
542 | return result;
|
543 | })();
|
544 | }
|
545 |
|
546 | /**
|
547 | * A pass-thru method to the static function of the same name. The
|
548 | * difference being that if `requestData` is not specified, the
|
549 | * `requestData` object from this instance will be used to build the
|
550 | * resolvers in question.
|
551 | *
|
552 | * @instance
|
553 | * @method ⌾⠀getResolver
|
554 | * @memberof GQLBase
|
555 | *
|
556 | * @param {string} resolverName the name of the resolver as a string
|
557 | * @param {Object} requestData the requestData used to build the
|
558 | * resolver methods from which to choose
|
559 | * @return {Function} returns either a `function` representing the
|
560 | * resolver requested or null if there wasn't one to be found
|
561 | */
|
562 | getResolver(resolverName, requestData) {
|
563 | var _this2 = this;
|
564 |
|
565 | return (0, _asyncToGenerator3.default)(function* () {
|
566 | return yield _this2.constructor.getResolver(resolverName, requestData || _this2.requestData);
|
567 | })();
|
568 | }
|
569 |
|
570 | /**
|
571 | * Resolvers are created in a number of different ways. OOP design
|
572 | * dictates that instances of a created class will handle field
|
573 | * resolvers, but query, mutation and subscription resolvers are
|
574 | * typically what creates these instances.
|
575 | *
|
576 | * Since a resolver can be created using `@mutator/@subscriptor/@resolver`
|
577 | * or via method on a object returned from `RESOLVERS()`, `MUTATORS()` or
|
578 | * `SUBSCRIPTIONS()`, there should be an easy to use way to fetch a
|
579 | * resolver by name; if for nothing else, code reuse.
|
580 | *
|
581 | * Pass the name of the resolver to the function and optionally pass a
|
582 | * requestData object. The `getMergedRoot()` method will build an object
|
583 | * containing all the root resolvers for the type, bound to the supplied
|
584 | * `requestData` object. It is from this object that `resolverName` will
|
585 | * be used to fetch the function in question. If one exists, it will be
|
586 | * returned, ready for use. Otherwise, null will be your answer.
|
587 | *
|
588 | *
|
589 | * @static
|
590 | * @method ⌾⠀getResolver
|
591 | * @memberof GQLBase
|
592 | *
|
593 | * @param {string} resolverName the name of the resolver as a string
|
594 | * @param {Object} requestData the requestData used to build the
|
595 | * resolver methods from which to choose
|
596 | * @return {Function} returns either a `function` representing the
|
597 | * resolver requested or null if there wasn't one to be found
|
598 | */
|
599 | static getResolver(resolverName, requestData) {
|
600 | var _this3 = this;
|
601 |
|
602 | return (0, _asyncToGenerator3.default)(function* () {
|
603 | const reqData = requestData || null;
|
604 | const rootObj = yield _this3.getMergedRoot(reqData);
|
605 |
|
606 | return rootObj[resolverName] || null;
|
607 | })();
|
608 | }
|
609 |
|
610 | /**
|
611 | * The static version of getProp reads into the prototype to find the field
|
612 | * that is desired. If the field is either a getter or a initializer (see
|
613 | * class properties descriptors), then the option to bind that to either the
|
614 | * prototype object or one of your choosing is available.
|
615 | *
|
616 | * @memberof GQLBase
|
617 | * @method ⌾⠀getProp
|
618 | * @static
|
619 | *
|
620 | * @param {string|Symbol} propName a string or Symbol denoting the name of
|
621 | * the property or field you desire
|
622 | * @param {boolean} bindGetters true if a resulting `getter` or `initializer`
|
623 | * should be bound to the prototype or other object
|
624 | * @param {mixed} bindTo the object to which to bind the `getter` or
|
625 | * `initializer` functions to if other than the class prototype.
|
626 | * @return {mixed} a `Function` or other mixed value making up the property
|
627 | * name requested
|
628 | */
|
629 | static getProp(propName, bindGetters = false, bindTo) {
|
630 | let descriptor = (0, _getOwnPropertyDescriptor2.default)(this.prototype, propName);
|
631 |
|
632 | if (descriptor) {
|
633 | if (descriptor.get || descriptor.initializer) {
|
634 | let what = descriptor.initializer || descriptor.get;
|
635 |
|
636 | if (bindGetters) {
|
637 | bindTo = bindTo || this.prototype;
|
638 |
|
639 | return what.bind(bindTo);
|
640 | } else {
|
641 | return what;
|
642 | }
|
643 | } else {
|
644 | return descriptor.value;
|
645 | }
|
646 | } else {
|
647 | return null;
|
648 | }
|
649 | }
|
650 |
|
651 | /**
|
652 | * Until such time as the reference implementation of Facebook's GraphQL
|
653 | * SDL AST parser supports comments, or until we take advantage of Apollo's
|
654 | * AST parser, this is how comments will be applied to a built schema.
|
655 | *
|
656 | * Several constants are defined on the GQLBase object itself, and thereby
|
657 | * all its subclasses. They pertain to how to define description fields
|
658 | * for various parts of your GQL implementation.
|
659 | *
|
660 | * ```
|
661 | * // To define a description on the top level class
|
662 | * [this.DOC_CLASS]: string
|
663 | *
|
664 | * // To define a description on a field (getter, function or async function)
|
665 | * [this.DOC_FIELDS]: {
|
666 | * fieldName: string
|
667 | * }
|
668 | *
|
669 | * // To define a description on a query, mutation or subscription field
|
670 | * [this.DOC_QUERIES || this.DOC_MUTATORS || this.DOC_SUBSCRIPTIONS]: {
|
671 | * fieldName: string
|
672 | * }
|
673 | * ```
|
674 | *
|
675 | * To make writing code easier, the `joinLines()` template function is
|
676 | * available so your source code can look nice and neat and your descriptions
|
677 | * won't get annoying line breaks and spaces as part of that process.
|
678 | *
|
679 | * @static
|
680 | * @memberof GQLBase
|
681 | * @method apiDocs
|
682 | *
|
683 | * @return {Object} an object with various keys and values denoting
|
684 | * description fields that should be applied to the final schema object
|
685 | */
|
686 | static apiDocs() {
|
687 | return {
|
688 | [this.DOC_CLASS]: _utils.joinLines`
|
689 | GQLBase class implementation. GQLBase is the root class used in
|
690 | graphql-lattice to describe a GraphQLObjectType. If you are reading
|
691 | this, the person using lattice failed to provide documentation for
|
692 | their type. :)
|
693 | `,
|
694 |
|
695 | [this.DOC_QUERY]: _utils.joinLines`
|
696 | ## Welcome to GraphQL Lattice
|
697 | **Query**
|
698 |
|
699 | You will want to define a \`DOC_QUERY\` apiDoc comment with something
|
700 | more meaningful to your particular Schema here.
|
701 | `,
|
702 |
|
703 | [this.DOC_MUTATION]: _utils.joinLines`
|
704 | ## Welcome to GraphQL Lattice
|
705 | **Mutation**
|
706 |
|
707 | You will want to define a \`DOC_MUTATION\` apiDoc comment with
|
708 | something more meaningful to your particular Schema here.
|
709 | `,
|
710 |
|
711 | [this.DOC_SUBSCRIPTION]: _utils.joinLines`
|
712 | ## Welcome to GraphQL Lattice
|
713 | **Subscription**
|
714 |
|
715 | You will want to define a \`DOC_SUBSCRIPTION\` apiDoc comment with
|
716 | something more meaningful to your particular Schema here.
|
717 | `,
|
718 |
|
719 | [this.DOC_FIELDS]: {
|
720 | // fieldName: `fieldDescription`,
|
721 | },
|
722 |
|
723 | [this.DOC_QUERIES]: {
|
724 | // queryName: `queryDescription`,
|
725 | },
|
726 |
|
727 | [this.DOC_MUTATORS]: {
|
728 | // mutatorName: `mutatorDescription`
|
729 | },
|
730 |
|
731 | [this.DOC_SUBSCRIPTIONS]: {
|
732 | // subscriptionName: `subscriptionDescription`
|
733 | }
|
734 | };
|
735 | }
|
736 |
|
737 | /**
|
738 | * Defined in a base class, this getter should return either a String
|
739 | * detailing the full IDL schema of a GraphQL handler or one of two
|
740 | * types of Symbols.
|
741 | *
|
742 | * The first Symbol type is the constant `ADJACENT_FILE`. If this Symbol is
|
743 | * returned, the system assumes that next to the source file in question is
|
744 | * a file of the same name with a .graphql extension. This file should be
|
745 | * made of the GraphQL IDL schema definitions for the object types being
|
746 | * created.
|
747 | *
|
748 | * Example:
|
749 | * ```js
|
750 | * static get SCHEMA(): string | Symbol {
|
751 | * return GQLBase.ADJACENT_FILE
|
752 | * }
|
753 | * ```
|
754 | *
|
755 | * The primary advantage of this approach is allowing an outside editor that
|
756 | * provides syntax highlighting rather than returning a string from the
|
757 | * SCHEMA getter.
|
758 | *
|
759 | * Alternatively, the static method IDLFilePath can be used to point to an
|
760 | * alternate location where the GraphQL IDL file resides. The extension can
|
761 | * also be changed from .graphql to something else if need be using this
|
762 | * method.
|
763 | *
|
764 | * Example:
|
765 | * ```js
|
766 | * static get SCHEMA(): string | Symbol {
|
767 | * return GQLBase.IDLFilePath('/path/to/file', '.idl')
|
768 | * }
|
769 | * ```
|
770 | *
|
771 | * @instance
|
772 | * @memberof GQLBase
|
773 | * @method ⬇︎⠀SCHEMA
|
774 | * @readonly
|
775 | * @static
|
776 | *
|
777 | * @return {string|Symbol} a valid IDL string or one of the Symbols
|
778 | * described above.
|
779 | *
|
780 | * @see {@link GQLBase#ADJACENT_FILE}
|
781 | * @see {@link GQLBase#IDLFilePath}
|
782 | */
|
783 | static get SCHEMA() {
|
784 | return '';
|
785 | }
|
786 |
|
787 | /**
|
788 | * This method should return a promise that resolves to an object of
|
789 | * functions matching the names of the mutation operations. These are to be
|
790 | * injected into the root object when used by `GQLExpressMiddleware`.
|
791 | *
|
792 | * @instance
|
793 | * @memberof GQLBase
|
794 | * @method ⌾⠀MUTATORS
|
795 | * @readonly
|
796 | * @static
|
797 | *
|
798 | * @param {Object} requestData typically an object containing three
|
799 | * properties; {req, res, gql}
|
800 | * @return {Promise} a promise that resolves to an object; see above for more
|
801 | * information.
|
802 | */
|
803 | static MUTATORS(requestData) {
|
804 | return (0, _asyncToGenerator3.default)(function* () {
|
805 | // define in base class
|
806 | return {};
|
807 | })();
|
808 | }
|
809 |
|
810 | /**
|
811 | * This method should return a promise that resolves to an object of
|
812 | * functions matching the names of the query operations. These are to be
|
813 | * injected into the root object when used by `GQLExpressMiddleware`.
|
814 | *
|
815 | * @instance
|
816 | * @memberof GQLBase
|
817 | * @method ⌾⠀RESOLVERS
|
818 | * @readonly
|
819 | * @static
|
820 | *
|
821 | * @param {Object} requestData typically an object containing three
|
822 | * properties; {req, res, gql}
|
823 | * @return {Promise} a promise that resolves to an object; see above for more
|
824 | * information.
|
825 | */
|
826 | static RESOLVERS(requestData) {
|
827 | return (0, _asyncToGenerator3.default)(function* () {
|
828 | // define in base class
|
829 | return {};
|
830 | })();
|
831 | }
|
832 |
|
833 | /**
|
834 | * @see {@link GQLBase#SCHEMA}
|
835 | *
|
836 | * @memberof GQLBase
|
837 | * @method ⬇︎⠀ADJACENT_FILE
|
838 | * @static
|
839 | * @const
|
840 | *
|
841 | * @return {Symbol} the Symbol, when returned from SCHEMA, causes
|
842 | * the logic to load an IDL Schema from an associated file with a .graphql
|
843 | * extension and bearing the same name.
|
844 | */
|
845 | static get ADJACENT_FILE() {
|
846 | return (0, _for2.default)('.graphql file located adjacent to source');
|
847 | }
|
848 |
|
849 | /**
|
850 | * Determines the default type targeted by this GQLBase class. Any
|
851 | * type will technically be valid but only will trigger special behavior
|
852 | *
|
853 | * @memberof GQLBase
|
854 | * @method ⬇︎⠀GQL_TYPE
|
855 | * @static
|
856 | * @const
|
857 | *
|
858 | * @return {Function} a type, such as `GraphQLObjectType` or
|
859 | * `GraphQLInterfaceType`
|
860 | */
|
861 | static get GQL_TYPE() {
|
862 | return _graphql.GraphQLObjectType;
|
863 | }
|
864 |
|
865 | /**
|
866 | * Creates an appropriate Symbol crafted with the right data for use by
|
867 | * the IDLFileHandler class below.
|
868 | *
|
869 | * @static
|
870 | * @memberof GQLBase
|
871 | * @method ⌾⠀IDLFilePath
|
872 | *
|
873 | * @param {string} path a path to the IDL containing file
|
874 | * @param {string} [extension='.graphql'] an extension, including the
|
875 | * prefixed period, that will be added to the supplied path should it not
|
876 | * already exist.
|
877 | * @return Symbol
|
878 | *
|
879 | * @see {@link GQLBase#SCHEMA}
|
880 | */
|
881 | static IDLFilePath(path, extension = '.graphql') {
|
882 | return (0, _for2.default)(`Path ${path} Extension ${extension}`);
|
883 | }
|
884 |
|
885 | /**
|
886 | * A file handler for fetching the IDL schema string from the file system
|
887 | * for those `GQLBase` extended classes that have indicated to do so by
|
888 | * returning a `Symbol` for their `SCHEMA` property.
|
889 | *
|
890 | * @static
|
891 | * @memberof GQLBase
|
892 | * @method ⬇︎⠀handler
|
893 | *
|
894 | * @return {IDLFileHandler} instance of IDLFileHandler, created if one does
|
895 | * not already exist, for fetching the contents from disk.
|
896 | */
|
897 | static get handler() {
|
898 | const key = (0, _for2.default)(`${_IDLFileHandler.IDLFileHandler.name}.${this.name}`);
|
899 |
|
900 | // @ComputedType
|
901 | if (!this[key]) {
|
902 | // @ComputedType
|
903 | this[key] = new _IDLFileHandler.IDLFileHandler(this);
|
904 | }
|
905 |
|
906 | // @ComputedType
|
907 | return this[key];
|
908 | }
|
909 |
|
910 | /**
|
911 | * Returns the module object where your class is created. This needs to be
|
912 | * defined on your class, as a static getter, in the FILE where you are
|
913 | * defining your Class definition.
|
914 | *
|
915 | * @static
|
916 | * @memberof GQLBase
|
917 | * @method ⬇︎⠀module
|
918 | * @const
|
919 | *
|
920 | * @return {Object} the reference to the module object defined and injected
|
921 | * by node.js' module loading system.
|
922 | *
|
923 | * @see https://nodejs.org/api/modules.html
|
924 | */
|
925 | static get module() {
|
926 | return module;
|
927 | }
|
928 |
|
929 | /**
|
930 | * The internal data model has some custom `EventEmitter` code wrapped
|
931 | * it here. When the data model is set via `setModel` or by accessing it
|
932 | * via `instance[MODEL_KEY]`, an event `EVENT_MODEL_SET` is emitted. Any
|
933 | * listener listening for this event receives an object with two keys
|
934 | * ```
|
935 | * {
|
936 | * model: The actual model being set; changes are persisted
|
937 | * instance: The GQLBase instance the model is associated with
|
938 | * }
|
939 | * ```
|
940 | *
|
941 | * Subsequently, the events `EVENT_MODEL_PROP_CHANGE` and
|
942 | * `EVENT_MODEL_PROP_DELETE` can be listened to if your version of node
|
943 | * supports Proxy objects. They allow you to be notified whenever your
|
944 | * model has a property changed or deleted, respectively.
|
945 | *
|
946 | * The callback for `change` receives an object with four properties
|
947 | * ```
|
948 | * {
|
949 | * model: The model object the value is being changed on
|
950 | * old: The old value being replaced; undefined if it is the first time
|
951 | * key: The property key for the value being changed
|
952 | * value: The new value being set
|
953 | * }
|
954 | * ```
|
955 | *
|
956 | * The callback for `delete` receives an object with four properties
|
957 | * ```
|
958 | * {
|
959 | * model: The model object the value is deleted from
|
960 | * key: The property key for the deleted value
|
961 | * deleted: The deleted value
|
962 | * }
|
963 | * ```
|
964 | *
|
965 | * @static
|
966 | * @memberof GQLBase
|
967 | * @method ⌾⠀setupModel
|
968 | *
|
969 | * @param {GQLBase} instance typically `this` as passed in from a call in
|
970 | * the constructor
|
971 | */
|
972 | static setupModel(instance) {
|
973 | const changeHandler = {
|
974 | /**
|
975 | * Proxy set() handler. This is where the change events are fired from
|
976 | *
|
977 | * @method GQLBase~set
|
978 | * @param {Object} target the `GQLBase` model object
|
979 | * @param {string} key the property name
|
980 | * @param {mixed} value the new property value
|
981 | */
|
982 | set(target, key, value) {
|
983 | const old = target[key];
|
984 |
|
985 | target[key] = value;
|
986 | instance.emit(GQLBase.EVENT_MODEL_PROP_CHANGE, {
|
987 | model: target,
|
988 | old,
|
989 | key,
|
990 | value
|
991 | });
|
992 | },
|
993 |
|
994 | /**
|
995 | * Proxy deleteProperty() handler. This is where the delete property
|
996 | * events are fired from
|
997 | *
|
998 | * @method GQLBase~deleteProperty
|
999 | * @param {Object} target the `GQLBase` model object
|
1000 | * @param {string} key the property name
|
1001 | */
|
1002 | deleteProperty(target, key) {
|
1003 | const deleted = target[key];
|
1004 |
|
1005 | delete target[key];
|
1006 | instance.emit(GQLBase.EVENT_MODEL_PROP_DELETE, {
|
1007 | model: target,
|
1008 | key,
|
1009 | deleted
|
1010 | });
|
1011 | }
|
1012 | };
|
1013 |
|
1014 | /**
|
1015 | * 'Publicly' the Symbol for accessing the `GQLBase` model is `MODEL_KEY`.
|
1016 | * In truth it is stored under a Symbol defined in `setupModel` and
|
1017 | * referred to as `_MODEL_KEY` in this code. This is done so a getter and
|
1018 | * setter can be wrapped around the usage of the instance's data model.
|
1019 | *
|
1020 | * When being read, if `Proxy` exists in the node environment and if there
|
1021 | * are any registered `EVENT_MODEL_PROP_CHANGE` or `EVENT_MODEL_PROP_DELETE`
|
1022 | * events, then the returned model is a Proxy around the real model that
|
1023 | * allows us to capture the changes and deletion of keys
|
1024 | *
|
1025 | * When being assigned, the event `EVENT_MODEL_WILL_BE_SET` and the event
|
1026 | * `EVENT_MODEL_HAS_BEEN_SET` are emitted to allow listeners to modify and
|
1027 | * see the final data around the setting of a model object. Both events
|
1028 | * receive an object with two keys
|
1029 | *
|
1030 | * ```
|
1031 | * {
|
1032 | * model: The object being or having been set
|
1033 | * instance: The GQLBase instance receiving the model
|
1034 | * }
|
1035 | * ```
|
1036 | */
|
1037 | (0, _defineProperty2.default)(instance, MODEL_KEY, {
|
1038 | get: function () {
|
1039 | let model = this[_MODEL_KEY];
|
1040 | let hasListeners = this.listenerCount(GQLBase.EVENT_MODEL_PROP_CHANGE) + this.listenerCount(GQLBase.EVENT_MODEL_PROP_DELETE);
|
1041 |
|
1042 | if (hasProxy && hasListeners) {
|
1043 | model = new Proxy(model, changeHandler);
|
1044 | }
|
1045 |
|
1046 | return model;
|
1047 | },
|
1048 |
|
1049 | set: function (model) {
|
1050 | const instance = this;
|
1051 |
|
1052 | this.emit(GQLBase.EVENT_MODEL_WILL_BE_SET, { model, instance });
|
1053 | instance[_MODEL_KEY] = model;
|
1054 | this.emit(GQLBase.EVENT_MODEL_HAS_BEEN_SET, { model, instance });
|
1055 | }
|
1056 | });
|
1057 | }
|
1058 |
|
1059 | /**
|
1060 | * If ES6 Proxies are supported in your execution environment, all GQLBase
|
1061 | * extended classes are also proxies. By default the internal proxy handler
|
1062 | * provides backwards compatibility with the removal of the default getters
|
1063 | * and setters for the 'model' property as long as you do not define a
|
1064 | * top level 'model' property of your own.
|
1065 | *
|
1066 | * @method ⬇︎⠀[_PROXY_HANDLER]
|
1067 | * @memberof GQLBase
|
1068 | * @static
|
1069 | * @const
|
1070 | * @since 2.5.0
|
1071 | *
|
1072 | * @type {Object}
|
1073 | * @ComputedType
|
1074 | */
|
1075 | static get [_PROXY_HANDLER]() {
|
1076 | return {
|
1077 | get(target, key, lastResult) {
|
1078 | const model = target[_MODEL_KEY];
|
1079 |
|
1080 | // Allow backwards compatibility for 'model' property if one is not
|
1081 | // explicitly defined on your instance.
|
1082 | if (notDefined('model', key, target)) {
|
1083 | // Be sure to use the public MODEL_KEY to ensure events fire
|
1084 | return target[MODEL_KEY];
|
1085 | }
|
1086 |
|
1087 | return target[key];
|
1088 | }
|
1089 | };
|
1090 | }
|
1091 |
|
1092 | /**
|
1093 | * Applies the same logic as {@link #[Symbol.toStringTag]} but on a static
|
1094 | * scale. So, if you perform `Object.prototype.toString.call(MyClass)`
|
1095 | * the result would be `[object MyClass]`.
|
1096 | *
|
1097 | * @method ⌾⠀[Symbol.toStringTag]
|
1098 | * @memberof ModuleParser
|
1099 | * @static
|
1100 | *
|
1101 | * @return {string} the name of this class
|
1102 | * @ComputedType
|
1103 | */
|
1104 | static get [_toStringTag2.default]() {
|
1105 | return this.name;
|
1106 | }
|
1107 |
|
1108 | /**
|
1109 | * A constant used to register an event listener for when the internal
|
1110 | * model object is assigned a new value. This event fires before the model
|
1111 | * is set. Changes to the model value at this point will affect the contents
|
1112 | * before the value assignment takes place.
|
1113 | *
|
1114 | * @static
|
1115 | * @memberof GQLBase
|
1116 | * @method ⬇︎⠀EVENT_MODEL_WILL_BE_SET
|
1117 | * @const
|
1118 | *
|
1119 | * @type {string}
|
1120 | */
|
1121 | static get EVENT_MODEL_WILL_BE_SET() {
|
1122 | return 'E: Int. model will be set';
|
1123 | }
|
1124 |
|
1125 | /**
|
1126 | * A constant used to register an event listener for when the internal
|
1127 | * model object is assigned a new value. This event fires after the model
|
1128 | * is set.
|
1129 | *
|
1130 | * @static
|
1131 | * @memberof GQLBase
|
1132 | * @method ⬇︎⠀EVENT_MODEL_HAS_BEEN_SET
|
1133 | * @const
|
1134 | *
|
1135 | * @type {string}
|
1136 | */
|
1137 | static get EVENT_MODEL_HAS_BEEN_SET() {
|
1138 | return 'E: Int. model has been set';
|
1139 | }
|
1140 |
|
1141 | /**
|
1142 | * A constant used to register an event listener for when a property of the
|
1143 | * internal model object is set to a new or intial value.
|
1144 | *
|
1145 | * @static
|
1146 | * @memberof GQLBase
|
1147 | * @method ⬇︎⠀EVENT_MODEL_PROP_CHANGE
|
1148 | * @const
|
1149 | *
|
1150 | * @type {string}
|
1151 | */
|
1152 | static get EVENT_MODEL_PROP_CHANGE() {
|
1153 | return 'E: Int. model prop changed';
|
1154 | }
|
1155 |
|
1156 | /**
|
1157 | * A constant used to register an event listener for when a property of the
|
1158 | * internal model object has been deleted. This event fires after the value
|
1159 | * has been deleted.
|
1160 | *
|
1161 | * @static
|
1162 | * @memberof GQLBase
|
1163 | * @method ⬇︎⠀EVENT_MODEL_PROP_DELETE
|
1164 | * @const
|
1165 | *
|
1166 | * @type {string}
|
1167 | */
|
1168 | static get EVENT_MODEL_PROP_DELETE() {
|
1169 | return 'E: Int. model prop deleted';
|
1170 | }
|
1171 |
|
1172 | /**
|
1173 | * A constant key used to identify a comment for a class description
|
1174 | *
|
1175 | * @static
|
1176 | * @memberof GQLBase
|
1177 | * @method ⬇︎⠀DOC_CLASS
|
1178 | * @const
|
1179 | *
|
1180 | * @type {string}
|
1181 | */
|
1182 | static get DOC_CLASS() {
|
1183 | return 'class';
|
1184 | }
|
1185 |
|
1186 | /**
|
1187 | * A constant key used to identify a comment for a type field description
|
1188 | *
|
1189 | * @static
|
1190 | * @memberof GQLBase
|
1191 | * @method ⬇︎⠀DOC_FIELDS
|
1192 | * @const
|
1193 | *
|
1194 | * @type {string}
|
1195 | */
|
1196 | static get DOC_FIELDS() {
|
1197 | return 'fields';
|
1198 | }
|
1199 |
|
1200 | /**
|
1201 | * A constant key used to identify a comment for the top level query
|
1202 | * description
|
1203 | *
|
1204 | * @static
|
1205 | * @memberof GQLBase
|
1206 | * @method ⬇︎⠀DOC_QUERY
|
1207 | * @const
|
1208 | *
|
1209 | * @type {string}
|
1210 | */
|
1211 | static get DOC_QUERY() {
|
1212 | return 'query';
|
1213 | }
|
1214 |
|
1215 | /**
|
1216 | * A constant key used to identify a comment for a query description
|
1217 | *
|
1218 | * @static
|
1219 | * @memberof GQLBase
|
1220 | * @method ⬇︎⠀DOC_QUERIES
|
1221 | * @const
|
1222 | *
|
1223 | * @type {string}
|
1224 | */
|
1225 | static get DOC_QUERIES() {
|
1226 | return 'queries';
|
1227 | }
|
1228 |
|
1229 | /**
|
1230 | * A constant key used to identify a comment for the top level mutation
|
1231 | * description
|
1232 | *
|
1233 | * @static
|
1234 | * @memberof GQLBase
|
1235 | * @method ⬇︎⠀DOC_MUTATION
|
1236 | * @const
|
1237 | *
|
1238 | * @type {string}
|
1239 | */
|
1240 | static get DOC_MUTATION() {
|
1241 | return 'mutation';
|
1242 | }
|
1243 |
|
1244 | /**
|
1245 | * A constant key used to identify a comment for a mutator description
|
1246 | *
|
1247 | * @static
|
1248 | * @memberof GQLBase
|
1249 | * @method ⬇︎⠀DOC_MUTATORS
|
1250 | * @const
|
1251 | * @deprecated Use `DOC_MUTATIONS` instead
|
1252 | *
|
1253 | * @type {string}
|
1254 | */
|
1255 | static get DOC_MUTATORS() {
|
1256 | return 'mutators';
|
1257 | }
|
1258 |
|
1259 | /**
|
1260 | * A constant key used to identify a comment for a mutator description
|
1261 | *
|
1262 | * @static
|
1263 | * @memberof GQLBase
|
1264 | * @method ⬇︎⠀DOC_MUTATORS
|
1265 | * @const
|
1266 | *
|
1267 | * @type {string}
|
1268 | */
|
1269 | static get DOC_MUTATIONS() {
|
1270 | return 'mutators';
|
1271 | }
|
1272 |
|
1273 | /**
|
1274 | * A constant key used to identify a comment for the top level subscription
|
1275 | * description
|
1276 | *
|
1277 | * @static
|
1278 | * @memberof GQLBase
|
1279 | * @method ⬇︎⠀DOC_SUBSCRIPTION
|
1280 | * @const
|
1281 | *
|
1282 | * @type {string}
|
1283 | */
|
1284 | static get DOC_SUBSCRIPTION() {
|
1285 | return 'subscription';
|
1286 | }
|
1287 |
|
1288 | /**
|
1289 | * A constant key used to identify a comment for a subscription description
|
1290 | *
|
1291 | * @static
|
1292 | * @memberof GQLBase
|
1293 | * @method ⬇︎⠀DOC_SUBSCRIPTIONS
|
1294 | * @const
|
1295 | *
|
1296 | * @type {string}
|
1297 | */
|
1298 | static get DOC_SUBSCRIPTIONS() {
|
1299 | return 'subscriptions';
|
1300 | }
|
1301 |
|
1302 | /**
|
1303 | * A shortcut to the utils/joinLines function to make it easier to get
|
1304 | * the tools to write docs for your types in a friendly fashion.
|
1305 | *
|
1306 | * @memberof GQLBase
|
1307 | * @method ⬇︎⠀joinLines
|
1308 | * @static
|
1309 | * @const
|
1310 | *
|
1311 | * @type {Function}
|
1312 | */
|
1313 | static get joinLines() {
|
1314 | return _utils.joinLines;
|
1315 | }
|
1316 |
|
1317 | /**
|
1318 | * An simple pass-thru method for fetching a types merged root object.
|
1319 | *
|
1320 | * @method ⌾⠀getMergedRoot
|
1321 | * @memberof GQLBase
|
1322 | * @static
|
1323 | *
|
1324 | * @param {Object} requestData an object containing the request data such as
|
1325 | * request, response or graphql context info that should be passed along to
|
1326 | * each of the resolver creators
|
1327 | * @return {Object} the merged root object with all the query, mutation and
|
1328 | * subscription resolvers defined and created within.
|
1329 | */
|
1330 | static getMergedRoot(requestData, separateByType = false) {
|
1331 | var _this4 = this;
|
1332 |
|
1333 | return (0, _asyncToGenerator3.default)(function* () {
|
1334 | const root = {};
|
1335 | const Class = _this4;
|
1336 |
|
1337 | let _ = {
|
1338 | // $FlowFixMe
|
1339 | resolvers: Class[META_KEY].resolvers || [],
|
1340 | // $FlowFixMe
|
1341 | mutators: Class[META_KEY].mutators || [],
|
1342 | // $FlowFixMe
|
1343 | subscriptors: Class[META_KEY].subscriptors || []
|
1344 | };
|
1345 |
|
1346 | let convert = function (f) {
|
1347 | let isFactoryClass = function (c) {
|
1348 | return !!Class[META_KEY][(0, _for2.default)('Factory Class')];
|
1349 | };
|
1350 |
|
1351 | if (isFactoryClass(Class)) {
|
1352 | return {
|
1353 | [f.name]: function (...args) {
|
1354 | return f.apply(Class, [Class, requestData, ...args]);
|
1355 | }
|
1356 | };
|
1357 | } else {
|
1358 | return {
|
1359 | [f.name]: function (...args) {
|
1360 | return f.apply(Class, [requestData, ...args]);
|
1361 | }
|
1362 | };
|
1363 | }
|
1364 | };
|
1365 | let reduce = function (p, c) {
|
1366 | return (0, _lodash.merge)(p, c);
|
1367 | };
|
1368 |
|
1369 | _.resolvers = _.resolvers.map(convert).reduce(reduce, {});
|
1370 | _.mutators = _.mutators.map(convert).reduce(reduce, {});
|
1371 | _.subscriptors = _.subscriptors.map(convert).reduce(reduce, {});
|
1372 |
|
1373 | if (separateByType) {
|
1374 | // Apollo wants all the resolvers to grouped by top level type.
|
1375 | // The field resolvers aren't an issue in Lattice defined types
|
1376 | // but the root types do need to be sorted; so let's do that here
|
1377 | (0, _lodash.merge)(root, { Query: yield Class.RESOLVERS(requestData) }, { Mutation: yield Class.MUTATORS(requestData) }, { Query: _.resolvers }, { Mutation: _.mutators }, { Subscription: _.subscriptors });
|
1378 |
|
1379 | // When using lattice with apollo server, it is quite particular about
|
1380 | // empty Query, Mutation or Subscription resolver maps.
|
1381 | if (!(0, _keys2.default)(root.Query).length) delete root.Query;
|
1382 | if (!(0, _keys2.default)(root.Mutation).length) delete root.Mutation;
|
1383 | if (!(0, _keys2.default)(root.Subscription).length) delete root.Subscription;
|
1384 | } else {
|
1385 | (0, _lodash.merge)(root, (yield Class.RESOLVERS(requestData)), (yield Class.MUTATORS(requestData)), _.resolvers, _.mutators, _.subscriptors);
|
1386 | }
|
1387 |
|
1388 | return root;
|
1389 | })();
|
1390 | }
|
1391 |
|
1392 | /**
|
1393 | * An object used to store data used by decorators and other internal
|
1394 | * proccesses.
|
1395 | * @ComputedType
|
1396 | */
|
1397 | static get [META_KEY]() {
|
1398 | let storage = this[(0, _for2.default)(this.name)];
|
1399 |
|
1400 | if (!storage) {
|
1401 | storage = this[(0, _for2.default)(this.name)] = {};
|
1402 | }
|
1403 |
|
1404 | return storage;
|
1405 | }
|
1406 | };
|
1407 | exports.default = GQLBase;
|
1408 | //# sourceMappingURL=GQLBase.js.map |
\ | No newline at end of file |