Home Reference Source

src/util/graphql.js

import { Kind } from 'graphql';
import includes from 'lodash.includes';

export const SCALAR_TYPE_NAMES = [
  'Int',
  'Float',
  'String',
  'Boolean',
  'ID',
  'ObjID'
];

export function getBaseType(type) {
  if (type.kind === 'ListType' || type.kind === 'NonNullType') {
    return getBaseType(type.type);
  }
  return type;
}

export function argumentsToObject(argumentsAst) {
  const result = {};
  argumentsAst.forEach(argument => {
    result[argument.name.value] = argument.value.value;
  });
  return result;
}

export function isScalarField(field) {
  return includes(SCALAR_TYPE_NAMES, getBaseType(field.type).name.value);
}

export function buildName(name) {
  return { kind: 'Name', value: name };
}

export function buildTypeDefinition(name, fields, kind, values) {
  return {
    kind: kind || 'ObjectTypeDefinition',
    name: buildName(name),
    interfaces: [],
    directives: [],
    fields,
    values: values || []
  };
}

export function buildTypeExtension(type) {
  return {
    kind: Kind.TYPE_EXTENSION_DEFINITION,
    definition: type
  };
}

export function buildTypeReference(name) {
  if (name[name.length - 1] === '!') {
    return {
      kind: 'NonNullType',
      type: buildTypeReference(name.substring(0, name.length - 1))
    };
  }

  if (name[0] === '[' && name[name.length - 1] === ']') {
    return {
      kind: 'ListType',
      type: buildTypeReference(name.substring(1, name.length - 1))
    };
  }

  return {
    kind: 'NamedType',
    name: buildName(name)
  };
}

export function buildField(name, args, typeName) {
  return {
    kind: 'FieldDefinition',
    name: buildName(name),
    arguments: args,
    type: buildTypeReference(typeName)
  };
}

export function buildValue(name, args) {
  return {
    kind: 'EnumValueDefinition',
    name: buildName(name),
    arguments: args
  };
}

export function buildArgument(name, type) {
  return {
    kind: 'InputValueDefinition',
    name: buildName(name),
    type: buildTypeReference(type),
    defaultValue: null,
    directives: []
  };
}

export function addPaginationArguments(field) {
  field.arguments.push(buildArgument('lastCreatedAt', 'Float'));
  field.arguments.push(buildArgument('limit', 'Int'));
}

// Apply all the directives that modify the field's schema. At this stage
// this is simply the pagination directives, which add pagination arguments
// to the field.
export function applyCustomDirectives(field) {
  field.directives.forEach(directive => {
    const directiveName = directive.name.value;
    const isPaginated = includes(
      ['hasMany', 'hasAndBelongsToMany', 'belongsToMany'],
      directiveName
    );
    if (isPaginated) {
      addPaginationArguments(field);
    }
  });
}

export function idArgument() {
  return buildArgument('id', 'ObjID!');
}

export function getType(level) {
  if (level.kind === 'NamedType') {
    return level.name.value;
  }

  if (level.type) {
    return getType(level.type);
  }

  return '';
}