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 11419x 92x 81x 1x 172x 92x     19x 92x 92x 276x   174x 364x 364x 364x 364x 174x 82x       108x 16x           190x 364x 92x     19x 19x 19x 19x 19x   61x 61x 66x   61x 55x   6x 7x       5x           16x 16x 16x 15x 7x   8x 8x     8x       30x 3x   27x 27x 25x   2x     80x   80x 80x 80x 80x 31x 31x 31x 31x   31x 124x   31x 5x   31x   31x 30x 30x 14x   14x 14x   16x 16x    
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[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;
  };
}