All files / domains/field/compiler resolver.ts

78.91% Statements 101/128
69.79% Branches 67/96
95.83% Functions 23/24
91.76% Lines 78/85

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 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 11520x 104x 93x 1x 196x 104x     20x 104x 104x 312x   198x 416x 416x 416x 416x 198x 94x       124x 20x           218x 416x 104x     20x 20x 20x 20x 20x   69x 69x 74x   69x 63x   6x 7x       5x           20x 20x 20x 18x 10x   8x 8x     8x       34x 3x   31x 31x 29x   2x     85x   85x 85x 85x 85x 35x 35x 35x 35x   35x 144x   35x 6x   35x   35x 34x 34x 14x   14x 14x   20x 20x      
import { GraphQLFieldResolver } from 'graphql';
import {
  InjectorsIndex,
  InjectorResolver,
  injectorRegistry,
} from '~/domains/inject';
import {
  fieldAfterHooksRegistry,
  fieldBeforeHooksRegistry,
  HookExecutor,
} from '~/domains/hooks';
import { getParameterNames } from '~/services/utils';
 
import {I isSchemaRoot, getSchemaRootInstance } from '~/domains/schema';
 
interface ArIgsMap {
  [argName: Istring]: any;
}
 
interface ComputeArgsOptions {
  args: ArgsMap;
  injectors: InjectorsIndex;
  injectorToValueMapper: (injector: InjectorResolver) => any;
}
E
async function performHooksExecution(
  hooks: HookExecutor[],
  source: any,
  args: any,
  context: any,
  info: any,
) {
  if (!hooks) {
    return;
  }
  // all hooks are executed in parrell instead of sequence. We wait for them all to be resolved before we continue
  return await Promise.all(
    hooks.map(hook => {
      return hook({ source, args, context, info });
    }),
  );
}
 
function computeFinalArgs(
  func: Function,
  { args, injectors, injectorToValueMapper }: ComputeArgsOptions,
) {
  const paramNames = getParameterNames(func);
  return paramNames.map((paramName, index) => {
    if (args && args.hasOwnProperty(paramName)) {
      return args[paramName];
    }
 
    const injector = injectors[index];
 
    if (!injector) {
      return null;
    }
 
    return injectorToValueMapper(injector);
  });
}
 
function getFieldOfTarget(instance: any, prototype: any, fieldName: string) {
  if (!instance) {
    return prototype[fieldName];
  }I

  const instanceField = instance[fieldName];
 
  if (instanceField !== undefined) {
    return instanceField;
  }
 
  return prototype[fieldName];
}
 
export function compileFieldResolver(
  target: Function,
  fieldName: string,
): GraphQLFieldResolver<any, any> {
  // const config = fieldsRegistry.get(target, fieldName);
  const injectors = injectorRegistry.getAll(target)[fieldName];
  const beforeHooks = fieldBeforeHooksRegistry.get(target, fieldName);
  const afterHooks = fieldAfterHooksRegistry.get(target, fieldName);
 
  return async (source: any, args = null, context = null, info = null) => {
    if (isSchemaRoot(target)) {
      source = getSchemaRootInstance(target);
    }I
 
    awaiIt performHooksExecution(beforeHooks, source, args, context, info);
    const instanceField = getFieldOfTarget(source, target.prototype, fieldName);
 
    if (typeof instanceField !== 'function') {
      await performHooksExecution(afterHooks, source, args, context, info);
      return instanceField;
    }
 
    const instanceFieldFunc = instanceField as Function;
 
    const params = computeFinalArgs(instanceFieldFunc, {
      args: args || {},
      injectors: injectors || {},
      injectorToValueMapper: injector =>
        injector.apply(source, [{ source, args, context, info }]),
    });
 
    const result = await instanceFieldFunc.apply(source, params);
 
    await performHooksExecution(afterHooks, source, args, context, info); // TODO: Consider adding resolve return to hook callback
    return result;
  };
}