All files dependingResolvers.js

100% Statements 17/17
100% Branches 5/5
100% Functions 10/10
100% Lines 15/15

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 89 90 91 92 93 94 95 96 97 98 99                        1x     21x                           50x 23x               100x           20x                         1x 100x                 16x   16x 14x 12x     16x                                     1x 25x        
import { push } from 'object-path'
import deepEqual from 'deep-equal'
 
import { nextTick, skip } from './utils'
import { allResolvers } from './allResolvers'
import { pipeResolvers } from './pipeResolvers'
import { combineResolvers } from './combineResolvers'
import { contextMustBeObject } from './miscResolvers'
 
/**
 * Piping resolver to save current value and reference to dependees cache.
 */
const saveDependee = combineResolvers(
  contextMustBeObject,
  (value, args, context, info) => (
    push(context, '_dependees', { path: info.path, value }), value
  )
)
 
/**
 * Identify a resolver as being a dependee, so other sibling
 * field resolvers might depend on the value resolved by this one.
 *
 * Basically, it will polute "info" during resolving
 * to insert the resolved value and path to this resolver.
 *
 * @param {Function} resolver Resolver implementation.
 * @return {Promise}.
 */
export const isDependee = resolver => (root, ...args) =>
  saveDependee(resolver(root, ...args), ...args)
 
/**
 * Make sure the field name exists on the parent type.
 *
 * @param {String} dependeeName The name of the dependee to check the parent against
 * @return {Function} Resolver to error when no dependee is found.
 */
const dependeeExists = dependeeName => (
  root,
  args,
  context,
  { fieldName, parentType: { _fields, name: parent } }
) =>
  !_fields[dependeeName]
    ? new Error(
        `Cannot get dependee "${dependeeName}" from field "${fieldName}" on type "${parent}"`
      )
    : skip
 
/**
 * Resolver implementation to retrieve the resolved value of a dependee sibling field.
 *
 * @param {String} dependeeName The name of the dependee this resolver depends on.
 * @param {Function} resolver Resolver implemenatation.
 * @return {Function} dependee resolver.
 */
export const resolveDependee = dependeeName =>
  combineResolvers(
    contextMustBeObject,
    dependeeExists(dependeeName),
    pipeResolvers(
      // Make sure dependent resolvers occur after
      // dependees have been initialized.
      nextTick,
 
      (root, args, context, info) => {
        const { _dependees = [] } = context
        // Find any currently resolved dependee.
        const resolved = _dependees
          .filter(({ path: { prev } }) => deepEqual(prev, info.path.prev))
          .find(({ path: { key } }) => key === dependeeName)
 
        // Run field resolution, if resolved value was not found.
        return resolved === skip
          ? info.parentType._fields[dependeeName].resolve(
              root,
              args,
              context,
              info
            )
          : resolved.value
      }
    )
  )
 
/**
 * Resolver implementation to retrieve the resolved value of multiple dependee sibling fields.
 *
 * @param {[String]} dependeeNames Array of names of the dependees this resolver depends on.
 * @param {Function} resolver Resolver implemenatation.
 * @return {Function} dependee resolver.
 */
export const resolveDependees = dependeeNames =>
  combineResolvers(
    contextMustBeObject,
    allResolvers(dependeeNames.map(resolveDependee))
  )