graphql#GraphQLNonNull TypeScript Examples

The following examples show how to use graphql#GraphQLNonNull. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: utils.ts    From tql with MIT License 7 votes vote down vote up
export function listType(type: GraphQLOutputType | GraphQLInputType): boolean {
  if (type instanceof GraphQLNonNull) {
    return listType(type.ofType);
  } else if (type instanceof GraphQLList) {
    return true;
  } else {
    return false;
  }
}
Example #2
Source File: Utils.ts    From graphql-ts-client with MIT License 6 votes vote down vote up
export function targetTypeOf(type: GraphQLType): GraphQLObjectType | GraphQLInterfaceType | GraphQLUnionType | undefined {
    if (type instanceof GraphQLNonNull) {
        return targetTypeOf(type.ofType);
    }
    if (type instanceof GraphQLList) {
        return targetTypeOf(type.ofType);
    }
    if (type instanceof GraphQLObjectType || type instanceof GraphQLInterfaceType || type instanceof GraphQLUnionType) {
        return type;
    }
    return undefined;
}
Example #3
Source File: types.ts    From tql with MIT License 6 votes vote down vote up
printField = (field: GraphQLField<any, any, any>): string => {
  const { args } = field;

  const isList = listType(field.type);
  const isNonNull = field.type instanceof GraphQLNonNull;
  const type = outputType(field.type);

  const printVariables = () => {
    return args.length > 0
      ? `(variables: { ${args.map(printVariable).join(", ")} })`
      : "";
  };

  if (type instanceof GraphQLScalarType) {
    return (
      `${args.length > 0 ? "" : "readonly"} ${field.name}${printVariables()}: ${
        isList ? `ReadonlyArray<${toPrimitive(type)}>` : `${toPrimitive(type)}`
      }` + (isNonNull ? "" : " | null")
    );
  } else if (type instanceof GraphQLEnumType) {
    return (
      `${args.length > 0 ? "" : "readonly"} ${field.name}${printVariables()}: ${
        isList ? `ReadonlyArray<${type.name}>` : `${type.name}`
      }` + (isNonNull ? "" : " | null")
    );
  } else if (
    type instanceof GraphQLInterfaceType ||
    type instanceof GraphQLUnionType ||
    type instanceof GraphQLObjectType
  ) {
    return (
      `${args.length > 0 ? "" : "readonly"} ${field.name}${printVariables()}: ${
        isList ? `ReadonlyArray<I${type.name}>` : `I${type.name}`
      }` + (isNonNull ? "" : " | null")
    );
  } else {
    throw new Error("Unable to print field.");
  }
}
Example #4
Source File: schema.ts    From squid with GNU General Public License v3.0 6 votes vote down vote up
function unwrapList(type: GraphQLOutputType): DeepList {
    let nulls: boolean[] = []
    while (type instanceof GraphQLList) {
        type = type.ofType
        if (type instanceof GraphQLNonNull) {
            nulls.push(false)
            type = type.ofType
        } else {
            nulls.push(true)
        }
    }
    return {item: type, nulls}
}
Example #5
Source File: withNullableType.ts    From payload with MIT License 6 votes vote down vote up
withNullableType = (field: NonPresentationalField, type: GraphQLType, forceNullable = false): GraphQLType => {
  const hasReadAccessControl = field.access && field.access.read;
  const condition = field.admin && field.admin.condition;

  if (!forceNullable && field.required && !field.localized && !condition && !hasReadAccessControl) {
    return new GraphQLNonNull(type);
  }

  return type;
}
Example #6
Source File: Writer.ts    From graphql-ts-client with MIT License 6 votes vote down vote up
protected gqlTypeRef(type: GraphQLType) {
        if (type instanceof GraphQLNonNull) {
            this.gqlTypeRef(type.ofType);
            this.text("!");
        } else if (type instanceof GraphQLList) {
            this.text("[");
            this.gqlTypeRef(type.ofType);
            this.text("]");
        } else if (type instanceof GraphQLUnionType) {
            this.enter("BLANK");
            for (const itemType of type.getTypes()) {
                this.separator(" | ");
                this.text(itemType.name);
            }
            this.leave();
        } else {
            this.text(type.name);
        }
    }
Example #7
Source File: helpers.ts    From amplify-codegen with Apache License 2.0 6 votes vote down vote up
propertyFromInputField(field: GraphQLInputField) {
    return Object.assign(
      {},
      {
        propertyName: camelCase(field.name),
        typeName: this.typeNameFromGraphQLType(field.type),
        isOptional: !(field.type instanceof GraphQLNonNull),
        description: field.description || null,
        name: field.name,
      }
    );
  }
Example #8
Source File: schema.ts    From apollo-server-vercel with MIT License 6 votes vote down vote up
mutationType = new GraphQLObjectType({
  name: `MutationType`,
  fields: {
    testMutation: {
      type: GraphQLString,
      args: { echo: { type: GraphQLString } },
      resolve(_, { echo }): string {
        return `not really a mutation, but who cares: ${String(echo)}`;
      }
    },
    testPerson: {
      type: personType,
      args: {
        firstName: {
          type: new GraphQLNonNull(GraphQLString)
        },
        lastName: {
          type: new GraphQLNonNull(GraphQLString)
        }
      },
      resolve(_, args): typeof args {
        return args;
      }
    },
    testRootValue: {
      type: GraphQLString,
      resolve(rootValue): typeof rootValue {
        return rootValue;
      }
    }
  }
})
Example #9
Source File: getType.test.ts    From amplify-codegen with Apache License 2.0 6 votes vote down vote up
describe('getType', () => {
  const testObj = new GraphQLObjectType({
    name: 'Address',
    fields: {
      street: { type: GraphQLString },
      number: { type: GraphQLInt },
      requiredInt: { type: new GraphQLNonNull(GraphQLInt) },
      listOfInt: { type: new GraphQLList(GraphQLInt) },
      listOfNonNullInt: { type: new GraphQLNonNull(new GraphQLList(GraphQLInt)) },
    },
  });

  it('should return string type for street', () => {
    expect(getType(testObj.getFields().street.type)).toEqual(GraphQLString);
  });

  it('should return integer type for number', () => {
    expect(getType(testObj.getFields().number.type)).toEqual(GraphQLInt);
  });

  it('should return integer type for a Non-Null integer', () => {
    expect(getType(testObj.getFields().requiredInt.type)).toEqual(GraphQLInt);
  });

  it('should return integer type for list of integer type', () => {
    expect(getType(testObj.getFields().listOfInt.type)).toEqual(GraphQLInt);
  });

  it('should return integer type for a list of non null integer type', () => {
    expect(getType(testObj.getFields().listOfNonNullInt.type)).toEqual(GraphQLInt);
  });
});
Example #10
Source File: buildPoliciesType.ts    From payload with MIT License 5 votes vote down vote up
buildFields = (label, fieldsToBuild) => fieldsToBuild.reduce((builtFields, field) => {
  if (!field.hidden) {
    if (field.name) {
      const fieldName = formatName(field.name);

      const objectTypeFields: ObjectTypeFields = ['create', 'read', 'update', 'delete'].reduce((operations, operation) => {
        const capitalizedOperation = operation.charAt(0).toUpperCase() + operation.slice(1);

        return {
          ...operations,
          [operation]: {
            type: new GraphQLObjectType({
              name: `${label}_${fieldName}_${capitalizedOperation}`,
              fields: {
                permission: {
                  type: new GraphQLNonNull(GraphQLBoolean),
                },
              },
            }),
          },
        };
      }, {});

      if (field.fields) {
        objectTypeFields.fields = {
          type: new GraphQLObjectType({
            name: `${label}_${fieldName}_Fields`,
            fields: buildFields(`${label}_${fieldName}`, field.fields),
          }),
        };
      }

      return {
        ...builtFields,
        [field.name]: {
          type: new GraphQLObjectType({
            name: `${label}_${fieldName}`,
            fields: objectTypeFields,
          }),
        },
      };
    }

    if (!field.name && field.fields) {
      const subFields = buildFields(label, field.fields);

      return {
        ...builtFields,
        ...subFields,
      };
    }
  }
  return builtFields;
}, {})
Example #11
Source File: renderTyping.ts    From genql with MIT License 5 votes vote down vote up
render = (
  type: GraphQLOutputType | GraphQLInputType,
  nonNull: boolean,
  root: boolean,
  undefinableValues: boolean,
  undefinableFields: boolean,
  wrap: (x: string) => string = x => x
): string => {
    
  if (root) {
    if (undefinableFields) {
      if (isNonNullType(type)) {
        return `: ${render(type.ofType, true, false, undefinableValues, undefinableFields, wrap)}`
      } else {
        const rendered = render(type, true, false, undefinableValues, undefinableFields, wrap)
        return undefinableValues ? `?: ${rendered}` : `?: (${rendered} | null)`
      }
    } else {
      return `: ${render(type, false, false, undefinableValues, undefinableFields, wrap)}`
    }
  }

  if (isNamedType(type)) {
    let typeName = type.name

    // if is a scalar use the scalar interface to not expose reserved words
    if (isScalarType(type)) {
      typeName = `Scalars['${typeName}']`
    }

    const typing = wrap(typeName)

    if (undefinableValues) {
      return nonNull ? typing : `(${typing} | undefined)`
    } else {
      return nonNull ? typing : `(${typing} | null)`
    }
  }

  if (isListType(type)) {
    const typing = `${render(type.ofType, false, false, undefinableValues, undefinableFields, wrap)}[]`

    if (undefinableValues) {
      return nonNull ? typing : `(${typing} | undefined)`
    } else {
      return nonNull ? typing : `(${typing} | null)`
    }
  }

  return render((<GraphQLNonNull<any>>type).ofType, true, false, undefinableValues, undefinableFields, wrap)
}
Example #12
Source File: schema.ts    From squid with GNU General Public License v3.0 5 votes vote down vote up
function asNonNull(f: GraphQLField<any, any>): GraphQLOutputType {
    let type = f.type
    if (type instanceof GraphQLNonNull) {
        type = type.ofType
    }
    return type
}
Example #13
Source File: simple.ts    From graphql-sse with MIT License 5 votes vote down vote up
schemaConfig: GraphQLSchemaConfig = {
  query: new GraphQLObjectType({
    name: 'Query',
    fields: {
      getValue: {
        type: new GraphQLNonNull(GraphQLString),
        resolve: () => 'value',
      },
    },
  }),
  subscription: new GraphQLObjectType({
    name: 'Subscription',
    fields: {
      greetings: {
        type: new GraphQLNonNull(GraphQLString),
        subscribe: async function* () {
          for (const hi of ['Hi', 'Bonjour', 'Hola', 'Ciao', 'Zdravo']) {
            yield { greetings: hi };
          }
        },
      },
      ping: {
        type: new GraphQLNonNull(GraphQLString),
        args: {
          key: {
            type: GraphQLString,
          },
        },
        subscribe: function (_src, args) {
          const key = args.key ? args.key : 'global';
          return {
            [Symbol.asyncIterator]() {
              return this;
            },
            async next() {
              if ((pendingPongs[key] ?? 0) > 0) {
                // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
                pendingPongs[key]!--;
                return { value: { ping: 'pong' } };
              }
              if (
                await new Promise((resolve) => (pongListeners[key] = resolve))
              )
                return { done: true };
              return { value: { ping: 'pong' } };
            },
            async return() {
              pongListeners[key]?.(true);
              delete pongListeners[key];
              return { done: true };
            },
            async throw() {
              throw new Error('Ping no gusta');
            },
          };
        },
      },
    },
  }),
}
Example #14
Source File: GraphQLStateFetcherWriter.ts    From graphql-ts-client with MIT License 5 votes vote down vote up
private writeFlatType() {

        const t = this.text.bind(this);

        t(`\nexport interface ${this.modelType.name}FlatType`);
        
        const superTypes = this.ctx.inheritanceInfo.upcastTypeMap.get(this.modelType);
        if (superTypes !== undefined) {
            const arr = Array.from(superTypes).filter(it => this.ctx.triggerableTypes.has(it));
            if (arr.length !== 0) {
                t(' extends ');
                this.scope({type: "BLANK"}, () => {
                    for (const superType of arr) {
                        this.separator(", ");
                        t(`${superType.name}FlatType`);
                    }
                });
            }
        }

        this.scope({type: "BLOCK", multiLines: true, prefix: " ", suffix: "\n"}, () => {
            if (this.modelType instanceof GraphQLObjectType || this.modelType instanceof GraphQLInterfaceType) {
                const fieldMap = this.modelType.getFields();
                for (const fieldName of this.declaredFieldNames) {
                    const field = fieldMap[fieldName]!;
                    const category = this.fieldCategoryMap.get(fieldName);
                    const targetType = targetTypeOf(field.type);
                    if (category === "SCALAR") {
                        t("readonly ");
                        t(fieldName);
                        if (!(field.type instanceof GraphQLNonNull)) {
                            t("?");
                        }
                        t(": ");
                        this.typeRef(field.type);
                        t(";\n");
                    } else if (targetType !== undefined && category !== "SCALAR") {
                        let nodeType = this.ctx.connections.get(targetType)?.nodeType ?? targetType;
                        const idField = this.ctx.idFieldMap.get(nodeType);
                        if (idField === undefined) {
                            throw new Error(`${nodeType.name} does not has id field`);
                        }
                        t("readonly ");
                        t(fieldName);
                        if (!(field.type instanceof GraphQLNonNull)) {
                            t("?");
                        }
                        t(": ");
                        this.typeRef(field.type, (type, field) => {
                            if (type === nodeType) {
                                return field.name === idField.name;
                            }
                            return true;
                        });
                        t(";\n");
                    }
                }
            }            
        });
    }
Example #15
Source File: auth_builder.ts    From graphql-mesh with MIT License 5 votes vote down vote up
/**
 * Gets the viewer Object, resolve function, and arguments
 */
function getViewerOT<TSource, TContext, TArgs>(
  name: string,
  protocolName: string,
  securityType: string,
  queryFields: GraphQLFieldConfigMap<any, any>,
  data: PreprocessingData<TSource, TContext, TArgs>,
  logger: Logger
): Viewer<TSource, TContext, TArgs> {
  const scheme: ProcessedSecurityScheme = data.security[protocolName];

  // Resolve function:
  const resolve = (root: any, args: any, context: any) => {
    const security = {};
    const saneProtocolName = Oas3Tools.sanitize(protocolName, Oas3Tools.CaseStyle.camelCase);
    security[Oas3Tools.storeSaneName(saneProtocolName, protocolName, data.saneMap, logger)] = args;

    /**
     * Viewers are always root, so we can instantiate _openAPIToGraphQL here without
     * previously checking for its existence
     */
    return {
      _openAPIToGraphQL: {
        security,
      },
    };
  };

  // Arguments:
  /**
   * Do not sort because they are already "sorted" in preprocessing.
   * Otherwise, for basic auth, "password" will appear before "username"
   */
  const args = {};
  if (typeof scheme === 'object') {
    for (const parameterName in scheme.parameters) {
      args[parameterName] = { type: new GraphQLNonNull(GraphQLString) };
    }
  }

  let typeDescription = `A viewer for security scheme '${protocolName}'`;
  /**
   * HTTP authentication uses different schemes. It is not sufficient to name
   * only the security type
   */
  let description =
    securityType === 'http'
      ? `A viewer that wraps all operations authenticated via security scheme ` +
        `'${protocolName}', which is of type 'http' '${scheme.def.scheme}'`
      : `A viewer that wraps all operations authenticated via security scheme ` +
        `'${protocolName}', which is of type '${securityType}'`;

  if (data.oass.length !== 1) {
    typeDescription += ` in OAS '${scheme.oas.info?.title}'`;
    description = `, in OAS '${scheme.oas.info?.title}`;
  }

  return {
    type: new GraphQLObjectType({
      name: Oas3Tools.capitalize(name), // Should already be sanitized and in camelCase
      description: typeDescription,
      fields: () => queryFields,
    }),
    resolve,
    args,
    description,
  };
}
Example #16
Source File: Writer.ts    From graphql-ts-client with MIT License 5 votes vote down vote up
protected typeRef(
        type: GraphQLType,
        objectRender?: string | ((type: GraphQLObjectType | GraphQLInterfaceType, field: GraphQLField<any, any>) => boolean)
    ) {
        if (type instanceof GraphQLScalarType) {
            const mappedType = 
                (this.config.scalarTypeMap ?? EMPTY_MAP)[type.name] 
                ?? SCALAR_MAP[type.name];
            if (mappedType === undefined) {
                throw new Error(`Unknown scalar type ${type.name}`);
            }
            if (typeof mappedType === 'string') {
                this.text(mappedType);
            } else {
                this.text(mappedType.typeName);
            }
        } else if (type instanceof GraphQLObjectType || 
            type instanceof GraphQLInterfaceType ||
            type instanceof GraphQLUnionType
        ) {
            if (typeof objectRender === "string") {
                this.text(objectRender);
            } else if (type instanceof GraphQLUnionType) {
                this.enter("BLANK");
                for (const itemType of type.getTypes()) {
                    this.separator(" | ");
                    this.text(itemType.name);    
                }
                this.leave();
            } else if (typeof objectRender === 'function') {
                this.scope({type: "BLOCK", multiLines: true}, () => {
                    const fieldMap = type.getFields();
                    for (const fieldName in fieldMap) {
                        const field = fieldMap[fieldName];
                        if (objectRender(type, field)) {
                            this.separator(", ");
                            this.text("readonly ");
                            this.text(fieldName);
                            this.text(": ");
                            this.typeRef(field.type, objectRender);
                        }
                    }
                });
            } else {
                this.text(type.name);
            }
        } else if (type instanceof GraphQLEnumType || type instanceof GraphQLInputObjectType) {
            this.text(type.name);
        } else if (type instanceof GraphQLNonNull) {
            this.typeRef(type.ofType, objectRender);
        } else if (type instanceof GraphQLList) {
            if (type.ofType instanceof GraphQLNonNull) {
                if (!this.config.arrayEditable) {
                    this.text("readonly ");
                }
                this.typeRef(type.ofType, objectRender);
                this.text("[]");
            } else {
                if (!this.config.arrayEditable) {
                    this.text("Readonly");
                }
                this.text("Array<");
                this.typeRef(type.ofType, objectRender);
                this.text(" | undefined>");
            }
        }
    }
Example #17
Source File: selectors.ts    From tql with MIT License 5 votes vote down vote up
printVariable = (arg: GraphQLArgument): string => {
  return `${arg.name}${
    arg.type instanceof GraphQLNonNull ? "" : "?"
  }: Variable<string> | ${printInputType(arg.type)}`;
}
Example #18
Source File: Generator.ts    From graphql-ts-client with MIT License 5 votes vote down vote up
function connectionTypeTuple(
    type: GraphQLObjectType | GraphQLInterfaceType
): [
    GraphQLObjectType | GraphQLInterfaceType, 
    GraphQLObjectType | GraphQLInterfaceType,
    GraphQLObjectType | GraphQLInterfaceType | GraphQLUnionType
] | undefined {
    const edges = type.getFields()["edges"];
    if (edges !== undefined) {
        const listType = 
            edges.type instanceof GraphQLNonNull ?
            edges.type.ofType : 
            edges.type;
        if (listType instanceof GraphQLList) {
            const edgeType = 
                listType.ofType instanceof GraphQLNonNull ?
                listType.ofType.ofType :
                listType.ofType;
            if (edgeType instanceof GraphQLObjectType) {
                const node = edgeType.getFields()["node"];
                if (node !== undefined) {
                    if (!(edges.type instanceof GraphQLNonNull)) {
                        waring(
                            `The type "${type.name}" is connection, its field "edges" must be not-null list`
                        );
                    }
                    if (!(listType.ofType instanceof GraphQLNonNull)) {
                        waring(
                            `The type "${type.name}" is connection, element of  its field "edges" must be not-null`
                        );
                    }
                    let nodeType: GraphQLType;
                    if (node.type instanceof GraphQLNonNull) {
                        nodeType = node.type.ofType;
                    } else {
                        waring(
                            `The type "${edgeType}" is edge, its field "node" must be non-null`
                        );
                        nodeType = node.type;
                    }
                    if (!(nodeType instanceof GraphQLObjectType) && !(nodeType instanceof GraphQLInterfaceType) && !(nodeType instanceof GraphQLUnionType)) {
                        throw new Error(
                            `The type "${edgeType}" is edge, its field "node" must be object, interface, union or their non-null wrappers`
                        );
                    }
                    const cursor = edgeType.getFields()["cursor"];
                    if (cursor === undefined) {
                        waring(
                            `The type "${edgeType}" is edge, it must defined a field named "cursor"`
                        );
                    } else {
                        const cursorType = 
                            cursor.type instanceof GraphQLNonNull ?
                            cursor.type.ofType :
                            cursor.type;
                        if (cursorType !== GraphQLString) {
                            throw new Error(
                                `The type "${edgeType}" is edge, its field "cursor" must be string`
                            );
                        }
                    }
                    return [type, edgeType, nodeType];
                }
            }
        }
    }
    return undefined;
}
Example #19
Source File: schema.ts    From apollo-server-vercel with MIT License 5 votes vote down vote up
queryType = new GraphQLObjectType({
  name: `QueryType`,
  fields: {
    testString: {
      type: GraphQLString,
      resolve(): string {
        return `it works`;
      }
    },
    testPerson: {
      type: personType,
      resolve(): { firstName: string; lastName: string } {
        return { firstName: `Jane`, lastName: `Doe` };
      }
    },
    testStringWithDelay: {
      type: GraphQLString,
      args: {
        delay: { type: new GraphQLNonNull(GraphQLInt) }
      },
      async resolve(_, args): Promise<string> {
        return new Promise((resolve) => {
          setTimeout(() => resolve(`it works`), args.delay);
        });
      }
    },
    testContext: {
      type: GraphQLString,
      resolve(_parent, _args, context): string {
        if (context.otherField) {
          return `unexpected`;
        }
        context.otherField = true;
        return context.testField;
      }
    },
    testRootValue: {
      type: GraphQLString,
      resolve(rootValue): typeof rootValue {
        return rootValue;
      }
    },
    testArgument: {
      type: GraphQLString,
      args: { echo: { type: GraphQLString } },
      resolve(_, { echo }): string {
        return `hello ${String(echo)}`;
      }
    },
    testError: {
      type: GraphQLString,
      resolve(): void {
        throw new Error(`Secret error message`);
      }
    }
  }
})
Example #20
Source File: typeNameFromGraphQLType.ts    From amplify-codegen with Apache License 2.0 5 votes vote down vote up
describe('Swift code generation: Types', () => {
  let helpers: Helpers;

  beforeEach(() => {
    helpers = new Helpers({});
  });

  describe('#typeNameFromGraphQLType()', () => {
    it('should return String? for GraphQLString', () => {
      expect(helpers.typeNameFromGraphQLType(GraphQLString)).toBe('String?');
    });

    it('should return String for GraphQLNonNull(GraphQLString)', () => {
      expect(helpers.typeNameFromGraphQLType(new GraphQLNonNull(GraphQLString))).toBe('String');
    });

    it('should return [String?]? for GraphQLList(GraphQLString)', () => {
      expect(helpers.typeNameFromGraphQLType(new GraphQLList(GraphQLString))).toBe('[String?]?');
    });

    it('should return [String?] for GraphQLNonNull(GraphQLList(GraphQLString))', () => {
      expect(helpers.typeNameFromGraphQLType(new GraphQLNonNull(new GraphQLList(GraphQLString)))).toBe('[String?]');
    });

    it('should return [String]? for GraphQLList(GraphQLNonNull(GraphQLString))', () => {
      expect(helpers.typeNameFromGraphQLType(new GraphQLList(new GraphQLNonNull(GraphQLString)))).toBe('[String]?');
    });

    it('should return [String] for GraphQLNonNull(GraphQLList(GraphQLNonNull(GraphQLString)))', () => {
      expect(helpers.typeNameFromGraphQLType(new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(GraphQLString))))).toBe('[String]');
    });

    it('should return [[String?]?]? for GraphQLList(GraphQLList(GraphQLString))', () => {
      expect(helpers.typeNameFromGraphQLType(new GraphQLList(new GraphQLList(GraphQLString)))).toBe('[[String?]?]?');
    });

    it('should return [[String?]]? for GraphQLList(GraphQLNonNull(GraphQLList(GraphQLString)))', () => {
      expect(helpers.typeNameFromGraphQLType(new GraphQLList(new GraphQLNonNull(new GraphQLList(GraphQLString))))).toBe('[[String?]]?');
    });

    it('should return Int? for GraphQLInt', () => {
      expect(helpers.typeNameFromGraphQLType(GraphQLInt)).toBe('Int?');
    });

    it('should return Double? for GraphQLFloat', () => {
      expect(helpers.typeNameFromGraphQLType(GraphQLFloat)).toBe('Double?');
    });

    it('should return Bool? for GraphQLBoolean', () => {
      expect(helpers.typeNameFromGraphQLType(GraphQLBoolean)).toBe('Bool?');
    });

    it('should return GraphQLID? for GraphQLID', () => {
      expect(helpers.typeNameFromGraphQLType(GraphQLID)).toBe('GraphQLID?');
    });

    it('should return String? for a custom scalar type', () => {
      expect(helpers.typeNameFromGraphQLType(new GraphQLScalarType({ name: 'CustomScalarType', serialize: String }))).toBe('String?');
    });

    it('should return a passed through custom scalar type with the passthroughCustomScalars option', () => {
      helpers.options.passthroughCustomScalars = true;
      helpers.options.customScalarsPrefix = '';

      expect(helpers.typeNameFromGraphQLType(new GraphQLScalarType({ name: 'CustomScalarType', serialize: String }))).toBe(
        'CustomScalarType?'
      );
    });

    it('should return a passed through custom scalar type with a prefix with the customScalarsPrefix option', () => {
      helpers.options.passthroughCustomScalars = true;
      helpers.options.customScalarsPrefix = 'My';

      expect(helpers.typeNameFromGraphQLType(new GraphQLScalarType({ name: 'CustomScalarType', serialize: String }))).toBe(
        'MyCustomScalarType?'
      );
    });
  });
});
Example #21
Source File: schema.ts    From squid with GNU General Public License v3.0 4 votes vote down vote up
function addEntityOrJsonObjectOrInterface(model: Model, type: GraphQLObjectType | GraphQLInterfaceType): void {
    if (model[type.name]) return

    let kind: 'entity' | 'object' | 'interface' = isEntityType(type)
        ? 'entity'
        :  type instanceof GraphQLInterfaceType ? 'interface' : 'object'

    let properties: Record<string, Prop> = {}
    let interfaces: string[] = []
    let indexes: Index[] = type instanceof GraphQLObjectType ? checkEntityIndexes(type) : []
    let description = type.description || undefined

    switch(kind) {
        case 'entity':
            model[type.name] = {kind, properties, description, interfaces, indexes}
            break
        case 'object':
            model[type.name] = {kind, properties, description, interfaces}
            break
        case 'interface':
            model[type.name] = {kind, properties, description}
            break
        default:
            throw unexpectedCase(kind)
    }

    let fields = type.getFields()
    if (kind == 'entity') {
        if (fields.id == null) {
            properties.id = {
                type: {kind: 'scalar', name: 'ID'},
                nullable: false
            }
        } else {
            let correctIdType = fields.id.type instanceof GraphQLNonNull
                && fields.id.type.ofType instanceof GraphQLScalarType
                && fields.id.type.ofType.name === 'ID'
            if (!correctIdType) {
                throw unsupportedFieldTypeError(type.name + '.id')
            }
        }
    }

    for (let key in fields) {
        let f: GraphQLField<any, any> = fields[key]

        handleFulltextDirective(model, type, f)

        let propName = `${type.name}.${f.name}`
        let fieldType = f.type
        let nullable = true
        let description = f.description || undefined
        let derivedFrom = checkDerivedFrom(type, f)
        let index = checkFieldIndex(type, f)
        let unique = index?.unique || false

        if (index) {
            indexes.push(index)
        }

        if (fieldType instanceof GraphQLNonNull) {
            nullable = false
            fieldType = fieldType.ofType
        }

        let list = unwrapList(fieldType)
        fieldType = list.item

        if (fieldType instanceof GraphQLScalarType) {
            properties[key] = {
                type: wrapWithList(list.nulls, {
                    kind: 'scalar',
                    name: fieldType.name
                }),
                nullable,
                description
            }
        } else if (fieldType instanceof GraphQLEnumType) {
            addEnum(model, fieldType)
            properties[key] = {
                type: wrapWithList(list.nulls, {
                    kind: 'enum',
                    name: fieldType.name
                }),
                nullable,
                description
            }
        } else if (fieldType instanceof GraphQLUnionType) {
            addUnion(model, fieldType)
            properties[key] = {
                type: wrapWithList(list.nulls, {
                    kind: 'union',
                    name: fieldType.name
                }),
                nullable,
                description
            }
        } else if (fieldType instanceof GraphQLObjectType) {
            if (isEntityType(fieldType)) {
                switch(list.nulls.length) {
                    case 0:
                        if (derivedFrom) {
                            if (!nullable) {
                                throw new SchemaError(`Property ${propName} must be nullable`)
                            }
                            properties[key] = {
                                type: {
                                    kind: 'lookup',
                                    entity: fieldType.name,
                                    field: derivedFrom.field
                                },
                                nullable,
                                description
                            }
                        } else {
                            if (unique && nullable) {
                                throw new SchemaError(`Unique property ${propName} must be non-nullable`)
                            }
                            properties[key] = {
                                type: {
                                    kind: 'fk',
                                    foreignEntity: fieldType.name
                                },
                                nullable,
                                unique,
                                description
                            }
                        }
                        break
                    case 1:
                        if (derivedFrom == null) {
                            throw new SchemaError(`@derivedFrom directive is required on ${propName} declaration`)
                        }
                        properties[key] = {
                            type: {
                                kind: 'list-lookup',
                                entity: fieldType.name,
                                field: derivedFrom.field
                            },
                            nullable: false,
                            description
                        }
                        break
                    default:
                        throw unsupportedFieldTypeError(propName)
                }
            } else {
                addEntityOrJsonObjectOrInterface(model, fieldType)
                properties[key] = {
                    type: wrapWithList(list.nulls, {
                        kind: 'object',
                        name: fieldType.name
                    }),
                    nullable,
                    description
                }
            }
        } else {
            throw unsupportedFieldTypeError(propName)
        }
    }

    if (kind != 'interface') {
        type.getInterfaces().forEach(i => {
            addEntityOrJsonObjectOrInterface(model, i)
            interfaces.push(i.name)
        })
    }
}
Example #22
Source File: helpers.ts    From amplify-codegen with Apache License 2.0 4 votes vote down vote up
describe('Flow typeAnnotationFromGraphQLType', () => {
  test('String', () => {
    expect(typeAnnotationFromGraphQLType(GraphQLString)).toMatchObject(t.nullableTypeAnnotation(t.stringTypeAnnotation()));
  });

  test('Int', () => {
    expect(typeAnnotationFromGraphQLType(GraphQLInt)).toMatchObject(t.nullableTypeAnnotation(t.numberTypeAnnotation()));
  });

  test('Float', () => {
    expect(typeAnnotationFromGraphQLType(GraphQLFloat)).toMatchObject(t.nullableTypeAnnotation(t.numberTypeAnnotation()));
  });

  test('Boolean', () => {
    expect(typeAnnotationFromGraphQLType(GraphQLBoolean)).toMatchObject(t.nullableTypeAnnotation(t.booleanTypeAnnotation()));
  });

  test('ID', () => {
    expect(typeAnnotationFromGraphQLType(GraphQLID)).toMatchObject(t.nullableTypeAnnotation(t.stringTypeAnnotation()));
  });

  test('String!', () => {
    expect(typeAnnotationFromGraphQLType(new GraphQLNonNull(GraphQLString))).toMatchObject(t.stringTypeAnnotation());
  });

  test('Int!', () => {
    expect(typeAnnotationFromGraphQLType(new GraphQLNonNull(GraphQLInt))).toMatchObject(t.numberTypeAnnotation());
  });

  test('Float!', () => {
    expect(typeAnnotationFromGraphQLType(new GraphQLNonNull(GraphQLFloat))).toMatchObject(t.numberTypeAnnotation());
  });

  test('Boolean!', () => {
    expect(typeAnnotationFromGraphQLType(new GraphQLNonNull(GraphQLBoolean))).toMatchObject(t.booleanTypeAnnotation());
  });

  test('ID!', () => {
    expect(typeAnnotationFromGraphQLType(new GraphQLNonNull(GraphQLID))).toMatchObject(t.stringTypeAnnotation());
  });

  // TODO: Test GenericTypeAnnotation

  test('[String]', () => {
    expect(typeAnnotationFromGraphQLType(new GraphQLList(GraphQLString))).toMatchObject(
      t.nullableTypeAnnotation(t.arrayTypeAnnotation(t.nullableTypeAnnotation(t.stringTypeAnnotation())))
    );
  });

  test('[Int]', () => {
    expect(typeAnnotationFromGraphQLType(new GraphQLList(GraphQLInt))).toMatchObject(
      t.nullableTypeAnnotation(t.arrayTypeAnnotation(t.nullableTypeAnnotation(t.numberTypeAnnotation())))
    );
  });

  test('[Float]', () => {
    expect(typeAnnotationFromGraphQLType(new GraphQLList(GraphQLFloat))).toMatchObject(
      t.nullableTypeAnnotation(t.arrayTypeAnnotation(t.nullableTypeAnnotation(t.numberTypeAnnotation())))
    );
  });

  test('[Boolean]', () => {
    expect(typeAnnotationFromGraphQLType(new GraphQLList(GraphQLBoolean))).toMatchObject(
      t.nullableTypeAnnotation(t.arrayTypeAnnotation(t.nullableTypeAnnotation(t.booleanTypeAnnotation())))
    );
  });

  test('[ID]', () => {
    expect(typeAnnotationFromGraphQLType(new GraphQLList(GraphQLID))).toMatchObject(
      t.nullableTypeAnnotation(t.arrayTypeAnnotation(t.nullableTypeAnnotation(t.stringTypeAnnotation())))
    );
  });

  test('[String]!', () => {
    expect(typeAnnotationFromGraphQLType(new GraphQLNonNull(new GraphQLList(GraphQLString)))).toMatchObject(
      t.arrayTypeAnnotation(t.nullableTypeAnnotation(t.stringTypeAnnotation()))
    );
  });

  test('[Int]!', () => {
    expect(typeAnnotationFromGraphQLType(new GraphQLNonNull(new GraphQLList(GraphQLInt)))).toMatchObject(
      t.arrayTypeAnnotation(t.nullableTypeAnnotation(t.numberTypeAnnotation()))
    );
  });
  test('[Float]!', () => {
    expect(typeAnnotationFromGraphQLType(new GraphQLNonNull(new GraphQLList(GraphQLFloat)))).toMatchObject(
      t.arrayTypeAnnotation(t.nullableTypeAnnotation(t.numberTypeAnnotation()))
    );
  });

  test('[Boolean]!', () => {
    expect(typeAnnotationFromGraphQLType(new GraphQLNonNull(new GraphQLList(GraphQLBoolean)))).toMatchObject(
      t.arrayTypeAnnotation(t.nullableTypeAnnotation(t.booleanTypeAnnotation()))
    );
  });

  test('[ID]!', () => {
    expect(typeAnnotationFromGraphQLType(new GraphQLNonNull(new GraphQLList(GraphQLID)))).toMatchObject(
      t.arrayTypeAnnotation(t.nullableTypeAnnotation(t.stringTypeAnnotation()))
    );
  });

  test('[String!]', () => {
    expect(typeAnnotationFromGraphQLType(new GraphQLList(new GraphQLNonNull(GraphQLString)))).toMatchObject(
      t.nullableTypeAnnotation(t.arrayTypeAnnotation(t.stringTypeAnnotation()))
    );
  });

  test('[Int!]', () => {
    expect(typeAnnotationFromGraphQLType(new GraphQLList(new GraphQLNonNull(GraphQLInt)))).toMatchObject(
      t.nullableTypeAnnotation(t.arrayTypeAnnotation(t.numberTypeAnnotation()))
    );
  });

  test('[Float!]', () => {
    expect(typeAnnotationFromGraphQLType(new GraphQLList(new GraphQLNonNull(GraphQLFloat)))).toMatchObject(
      t.nullableTypeAnnotation(t.arrayTypeAnnotation(t.numberTypeAnnotation()))
    );
  });

  test('[Boolean!]', () => {
    expect(typeAnnotationFromGraphQLType(new GraphQLList(new GraphQLNonNull(GraphQLBoolean)))).toMatchObject(
      t.nullableTypeAnnotation(t.arrayTypeAnnotation(t.booleanTypeAnnotation()))
    );
  });

  test('[ID!]', () => {
    expect(typeAnnotationFromGraphQLType(new GraphQLList(new GraphQLNonNull(GraphQLID)))).toMatchObject(
      t.nullableTypeAnnotation(t.arrayTypeAnnotation(t.stringTypeAnnotation()))
    );
  });

  test('[String!]!', () => {
    expect(typeAnnotationFromGraphQLType(new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(GraphQLString))))).toMatchObject(
      t.arrayTypeAnnotation(t.stringTypeAnnotation())
    );
  });

  test('[Int!]!', () => {
    expect(typeAnnotationFromGraphQLType(new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(GraphQLInt))))).toMatchObject(
      t.arrayTypeAnnotation(t.numberTypeAnnotation())
    );
  });

  test('[Float!]!', () => {
    expect(typeAnnotationFromGraphQLType(new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(GraphQLFloat))))).toMatchObject(
      t.arrayTypeAnnotation(t.numberTypeAnnotation())
    );
  });

  test('[Boolean!]!', () => {
    expect(typeAnnotationFromGraphQLType(new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(GraphQLBoolean))))).toMatchObject(
      t.arrayTypeAnnotation(t.booleanTypeAnnotation())
    );
  });

  test('[ID!]!', () => {
    expect(typeAnnotationFromGraphQLType(new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(GraphQLID))))).toMatchObject(
      t.arrayTypeAnnotation(t.stringTypeAnnotation())
    );
  });

  test('[[String]]', () => {
    expect(typeAnnotationFromGraphQLType(new GraphQLList(new GraphQLList(GraphQLString)))).toMatchObject(
      t.nullableTypeAnnotation(
        t.arrayTypeAnnotation(t.nullableTypeAnnotation(t.arrayTypeAnnotation(t.nullableTypeAnnotation(t.stringTypeAnnotation()))))
      )
    );
  });

  test('[[String]]!', () => {
    expect(typeAnnotationFromGraphQLType(new GraphQLNonNull(new GraphQLList(new GraphQLList(GraphQLString))))).toMatchObject(
      t.arrayTypeAnnotation(t.nullableTypeAnnotation(t.arrayTypeAnnotation(t.nullableTypeAnnotation(t.stringTypeAnnotation()))))
    );
  });

  test('Custom Scalar', () => {
    const OddType = new GraphQLScalarType({
      name: 'Odd',
      serialize(value) {
        return value % 2 === 1 ? value : null;
      },
    });

    expect(typeAnnotationFromGraphQLType(OddType)).toMatchObject(t.nullableTypeAnnotation(t.genericTypeAnnotation(t.identifier('Odd'))));
  });
});
Example #23
Source File: schema_builder.ts    From graphql-mesh with MIT License 4 votes vote down vote up
/**
 * Creates the fields object to be used by an (input) object type
 */
function createFields<TSource, TContext, TArgs>({
  def,
  links,
  operation,
  data,
  iteration,
  isInputObjectType,
  includeHttpDetails,
  logger,
}: CreateFieldsParams<TSource, TContext, TArgs>): GraphQLFieldConfigMap<any, any> | GraphQLInputFieldConfigMap {
  const translationLogger = logger.child('translation');

  let fields: GraphQLFieldConfigMap<any, any> = {};

  if (includeHttpDetails && !isInputObjectType) {
    fields.httpDetails = {
      type: GraphQLJSON,
      resolve: root => root?._openAPIToGraphQL?.data,
    };
  }

  const fieldTypeDefinitions = def.subDefinitions as {
    [fieldName: string]: DataDefinition;
  };

  // Create fields for properties
  for (const fieldTypeKey in fieldTypeDefinitions) {
    const fieldTypeDefinition = fieldTypeDefinitions[fieldTypeKey];
    const fieldSchema = fieldTypeDefinition.schema;

    // Get object type describing the property
    const objectType = getGraphQLType({
      def: fieldTypeDefinition,
      operation,
      data,
      iteration: iteration + 1,
      isInputObjectType,
      includeHttpDetails,
      logger,
    });

    const requiredProperty =
      typeof def.required === 'object' && def.required.includes(fieldTypeKey) && !fieldTypeDefinition.schema.nullable;

    // Finally, add the object type to the fields (using sanitized field name)
    if (objectType) {
      const saneFieldTypeKey = Oas3Tools.sanitize(
        fieldTypeKey,
        !data.options.simpleNames ? Oas3Tools.CaseStyle.camelCase : Oas3Tools.CaseStyle.simple
      );

      const sanePropName = Oas3Tools.storeSaneName(saneFieldTypeKey, fieldTypeKey, data.saneMap, logger);

      fields[sanePropName] = {
        type: (requiredProperty ? new GraphQLNonNull(objectType) : objectType) as GraphQLOutputType,

        description: typeof fieldSchema === 'object' ? fieldSchema.description : null,
      };
    } else {
      handleWarning({
        mitigationType: MitigationTypes.CANNOT_GET_FIELD_TYPE,
        message:
          `Cannot obtain GraphQL type for field '${fieldTypeKey}' in ` +
          `GraphQL type '${JSON.stringify(def.schema)}'.`,
        data,
        logger: translationLogger,
      });
    }
  }

  if (
    typeof links === 'object' && // Links are present
    !isInputObjectType // Only object type (input object types cannot make use of links)
  ) {
    for (const saneLinkKey in links) {
      translationLogger.debug(`Create link '${saneLinkKey}'...`);

      // Check if key is already in fields
      if (saneLinkKey in fields) {
        handleWarning({
          mitigationType: MitigationTypes.LINK_NAME_COLLISION,
          message:
            `Cannot create link '${saneLinkKey}' because parent ` +
            `object type already contains a field with the same (sanitized) name.`,
          data,
          logger: translationLogger,
        });
      } else {
        const link = links[saneLinkKey];

        // Get linked operation
        let linkedOpId;
        // TODO: href is yet another alternative to operationRef and operationId
        if (typeof link.operationId === 'string') {
          linkedOpId = link.operationId;
        } else if (typeof link.operationRef === 'string') {
          linkedOpId = linkOpRefToOpId({
            links,
            linkKey: saneLinkKey,
            operation,
            data,
            logger,
          });
        }

        /**
         * linkedOpId may not be initialized because operationRef may lead to an
         * operation object that does not have an operationId
         */
        if (typeof linkedOpId === 'string' && linkedOpId in data.operations) {
          const linkedOp = data.operations[linkedOpId];

          // Determine parameters provided via link
          const argsFromLink = link.parameters;

          // Get arguments that are not provided by the linked operation
          let dynamicParams = linkedOp.parameters;
          if (typeof argsFromLink === 'object') {
            dynamicParams = dynamicParams.filter(param => {
              return typeof argsFromLink[param.name] === 'undefined';
            });
          }

          // Get resolve function for link
          const linkResolver = data.options.resolverMiddleware(
            () => ({
              operation: linkedOp,
              argsFromLink: argsFromLink as { [key: string]: string },
              data,
              baseUrl: data.options.baseUrl,
              requestOptions: data.options.requestOptions,
              logger,
            }),
            getResolver
          );

          // Get arguments for link
          const args = getArgs({
            parameters: dynamicParams,
            operation: linkedOp,
            data,
            includeHttpDetails,
            logger,
          });

          // Get response object type
          const resObjectType =
            linkedOp.responseDefinition.graphQLType !== undefined
              ? linkedOp.responseDefinition.graphQLType
              : getGraphQLType({
                  def: linkedOp.responseDefinition,
                  operation,
                  data,
                  iteration: iteration + 1,
                  isInputObjectType: false,
                  includeHttpDetails,
                  logger,
                });

          let description = link.description;

          if (data.options.equivalentToMessages && description) {
            description += `\n\nEquivalent to ${linkedOp.operationString}`;
          }

          // Finally, add the object type to the fields (using sanitized field name)
          // TODO: check if fields already has this field name
          fields[saneLinkKey] = {
            type: resObjectType as GraphQLOutputType,
            resolve: linkResolver,
            args,
            description,
          };
        } else {
          handleWarning({
            mitigationType: MitigationTypes.UNRESOLVABLE_LINK,
            message: `Cannot resolve target of link '${saneLinkKey}'`,
            data,
            logger: translationLogger,
          });
        }
      }
    }
  }

  fields = sortObject(fields);
  return fields;
}
Example #24
Source File: generateSchema.ts    From davinci with MIT License 4 votes vote down vote up
generateGQLSchema = ({
	type,
	parentType,
	key,
	schemas = {},
	isInput = false,
	operationType,
	resolverMetadata,
	partial,
	transformMetadata = _.identity
}: IGenerateGQLSchemaArgs) => {
	// grab meta infos
	// maybe it's a decorated class, let's try to get the fields metadata
	const parentFieldsMetadata: IFieldDecoratorMetadata[] = parentType?.prototype
		? getFieldsMetadata(parentType.prototype.constructor, isInput, operationType, resolverMetadata)
		: [];
	const meta = _fp.find({ key }, parentFieldsMetadata) || ({} as IFieldDecoratorMetadata);
	const metadata = transformMetadata(meta, { isInput, type, parentType, schemas });
	const isRequired = !partial && metadata.opts?.required;

	// it's a primitive type, simple case
	if ([String, Number, Boolean, Date, Object].includes(type)) {
		const gqlType = scalarDict[type.name.toLowerCase()];
		const schema = isRequired ? new GraphQLNonNull(gqlType) : gqlType;
		return { schema, schemas };
	}

	// it's an array => recursively call makeSchema on the first array element
	if (Array.isArray(type)) {
		const gqlSchema = generateGQLSchema({
			type: type[0],
			parentType,
			schemas,
			key,
			isInput,
			operationType,
			resolverMetadata,
			partial,
			transformMetadata
		});
		const gqlType = new GraphQLList(gqlSchema.schema);
		const schema = isRequired ? new GraphQLNonNull(gqlType) : gqlType;

		return { schema, schemas: _.merge(schemas, gqlSchema.schemas) };
	}

	// it's a complex type => create nested types
	if (typeof type === 'function' || typeof type === 'object') {
		const suffix = isInput
			? _.compact([partial && 'Partial', _.upperFirst(operationType || ''), 'Input']).join('')
			: '';
		const typeMetadata = Reflector.getMetadata('davinci:graphql:types', type) || {};
		const name = `${typeMetadata.name || type.name || key}${suffix}`;

		// existing type, let's return it
		if (schemas[name]) {
			return { schema: schemas[name], schemas };
		}

		if (type instanceof UnionType) {
			const types = Array.isArray(type.types)
				? type.types.map(
					t =>
						generateGQLSchema({
							type: t,
							parentType,
							schemas,
							key,
							isInput,
							operationType,
							resolverMetadata,
							partial,
							transformMetadata
						}).schema
				  )
				: type.types;

			const unionTypeConfig = {
				..._.omit(metadata.opts, ['type']),
				name,
				types,
				resolveType: type.resolveType
			};

			schemas[name] = isRequired
				? new GraphQLNonNull(new GraphQLUnionType(unionTypeConfig))
				: new GraphQLUnionType(unionTypeConfig);
		} else {
			const objTypeConfig: any = {
				...metadata.opts,
				name,

				// eslint-disable-next-line no-use-before-define
				fields: createObjectFields({
					parentType: type,
					schemas,
					isInput,
					operationType,
					resolverMetadata,
					partial,
					transformMetadata
				})
			};

			const ObjectType = isInput ? GraphQLInputObjectType : GraphQLObjectType;
			schemas[name] = isRequired
				? new GraphQLNonNull(new ObjectType(objTypeConfig))
				: new ObjectType(objTypeConfig);
		}

		return { schema: schemas[name], schemas };
	}

	return null;
}
Example #25
Source File: buildMutationInputType.ts    From payload with MIT License 4 votes vote down vote up
function buildMutationInputType(name: string, fields: Field[], parentName: string, forceNullable = false): GraphQLInputObjectType {
  const fieldToSchemaMap = {
    number: (field: NumberField) => {
      const type = field.name === 'id' ? GraphQLInt : GraphQLFloat;
      return { type: withNullableType(field, type, forceNullable) };
    },
    text: (field: TextField) => ({ type: withNullableType(field, GraphQLString, forceNullable) }),
    email: (field: EmailField) => ({ type: withNullableType(field, GraphQLString, forceNullable) }),
    textarea: (field: TextareaField) => ({ type: withNullableType(field, GraphQLString, forceNullable) }),
    richText: (field: RichTextField) => ({ type: withNullableType(field, GraphQLJSON, forceNullable) }),
    code: (field: CodeField) => ({ type: withNullableType(field, GraphQLString, forceNullable) }),
    date: (field: DateField) => ({ type: withNullableType(field, GraphQLString, forceNullable) }),
    upload: (field: UploadField) => ({ type: withNullableType(field, GraphQLString, forceNullable) }),
    radio: (field: RadioField) => ({ type: withNullableType(field, GraphQLString, forceNullable) }),
    point: (field: PointField) => ({ type: withNullableType(field, GraphQLList(GraphQLFloat), forceNullable) }),
    checkbox: () => ({ type: GraphQLBoolean }),
    select: (field: SelectField) => {
      const formattedName = `${combineParentName(parentName, field.name)}_MutationInput`;
      let type: GraphQLType = new GraphQLEnumType({
        name: formattedName,
        values: field.options.reduce((values, option) => {
          if (typeof option === 'object' && option.value) {
            return {
              ...values,
              [formatName(option.value)]: {
                value: option.value,
              },
            };
          }

          if (typeof option === 'string') {
            return {
              ...values,
              [option]: {
                value: option,
              },
            };
          }

          return values;
        }, {}),
      });

      type = field.hasMany ? new GraphQLList(type) : type;
      type = withNullableType(field, type, forceNullable);

      return { type };
    },
    relationship: (field: RelationshipField) => {
      const { relationTo } = field;
      type PayloadGraphQLRelationshipType = GraphQLScalarType | GraphQLList<GraphQLScalarType> | GraphQLInputObjectType;
      let type: PayloadGraphQLRelationshipType;

      if (Array.isArray(relationTo)) {
        const fullName = `${combineParentName(parentName, field.label === false ? toWords(field.name, true) : field.label)}RelationshipInput`;
        type = new GraphQLInputObjectType({
          name: fullName,
          fields: {
            relationTo: {
              type: new GraphQLEnumType({
                name: `${fullName}RelationTo`,
                values: relationTo.reduce((values, option) => ({
                  ...values,
                  [formatName(option)]: {
                    value: option,
                  },
                }), {}),
              }),
            },
            value: { type: GraphQLJSON },
          },
        });
      } else {
        type = getCollectionIDType(payload.collections[relationTo].config);
      }

      return { type: field.hasMany ? new GraphQLList(type) : type };
    },
    array: (field: ArrayField) => {
      const fullName = combineParentName(parentName, field.label === false ? toWords(field.name, true) : field.label);
      let type: GraphQLType | GraphQLList<GraphQLType> = buildMutationInputType(fullName, field.fields, fullName);
      type = new GraphQLList(withNullableType(field, type, forceNullable));
      return { type };
    },
    group: (field: GroupField) => {
      const requiresAtLeastOneField = field.fields.some((subField) => (!fieldIsPresentationalOnly(subField) && subField.required && !subField.localized));
      const fullName = combineParentName(parentName, field.label === false ? toWords(field.name, true) : field.label);
      let type: GraphQLType = buildMutationInputType(fullName, field.fields, fullName);
      if (requiresAtLeastOneField) type = new GraphQLNonNull(type);
      return { type };
    },
    blocks: () => ({ type: GraphQLJSON }),
    row: (field: RowField) => field.fields.reduce((acc, rowField: RowField) => {
      const getFieldSchema = fieldToSchemaMap[rowField.type];

      if (getFieldSchema) {
        const fieldSchema = getFieldSchema(rowField);

        return [
          ...acc,
          fieldSchema,
        ];
      }

      return acc;
    }, []),
  };

  const fieldTypes = fields.reduce((schema, field: Field) => {
    if (!fieldIsPresentationalOnly(field) && !field.hidden) {
      const getFieldSchema: (field: Field) => { type: GraphQLType } = fieldToSchemaMap[field.type];

      if (getFieldSchema) {
        const fieldSchema = getFieldSchema(field);

        if (fieldHasSubFields(field) && Array.isArray(fieldSchema)) {
          return fieldSchema.reduce((acc, subField, i) => {
            const currentSubField = field.fields[i];
            if (fieldAffectsData(currentSubField)) {
              return {
                ...acc,
                [currentSubField.name]: subField,
              };
            }

            return {
              ...acc,
              ...fieldSchema,
            };
          }, schema);
        }

        if (fieldAffectsData(field)) {
          return {
            ...schema,
            [field.name]: fieldSchema,
          };
        }

        return {
          ...schema,
          ...fieldSchema,
        };
      }
    }

    return schema;
  }, {});

  const fieldName = formatName(name);

  return new GraphQLInputObjectType({
    name: `mutation${fieldName}Input`,
    fields: {
      ...fieldTypes,
    },
  });
}
Example #26
Source File: schema.ts    From Deep-Lynx with MIT License 4 votes vote down vote up
// generate requires a containerID because the schema it generates is based on a user's ontology and ontologies are
    // separated by containers
    async ForContainer(containerID: string, options: ResolverOptions): Promise<Result<GraphQLSchema>> {
        // fetch the currently published ontology if the versionID wasn't provided
        if (!options.ontologyVersionID) {
            const ontResults = await this.#ontologyRepo
                .where()
                .containerID('eq', containerID)
                .and()
                .status('eq', 'published')
                .list({sortBy: 'id', sortDesc: true});
            if (ontResults.isError || ontResults.value.length === 0) {
                Logger.error('unable to fetch current ontology, or no currently published ontology');
            } else {
                options.ontologyVersionID = ontResults.value[0].id;
            }
        }

        // fetch all metatypes for the container, with their keys - the single most expensive call of this function
        const metatypeResults = await this.#metatypeRepo
            .where()
            .containerID('eq', containerID)
            .and()
            .ontologyVersion('eq', options.ontologyVersionID)
            .list(true);
        if (metatypeResults.isError) {
            return Promise.resolve(Result.Pass(metatypeResults));
        }

        // fetch all metatype relationship pairs - used for _relationship queries.
        const metatypePairResults = await this.#metatypePairRepo
            .where()
            .containerID('eq', containerID)
            .and()
            .ontologyVersion('eq', options.ontologyVersionID)
            .list();
        if (metatypePairResults.isError) {
            return Promise.resolve(Result.Pass(metatypePairResults));
        }

        // fetch all relationship types. Used for relationship wrapper queries.
        const relationshipResults = await this.#relationshipRepo
            .where()
            .containerID('eq', containerID)
            .and()
            .ontologyVersion('eq', options.ontologyVersionID)
            .list(true);
        if (relationshipResults.isError) {
            return Promise.resolve(Result.Pass(relationshipResults));
        }

        // used for querying edges based on node (see input._relationship resolver)
        const metatypePairObjects: {[key: string]: any} = {};
        metatypePairResults.value.forEach((pair) => {
            const origin = stringToValidPropertyName(pair.origin_metatype_name!);
            const rel = stringToValidPropertyName(pair.relationship_name!);
            const dest = stringToValidPropertyName(pair.destination_metatype_name!);
            // populate list for forward searching
            if (!(origin in metatypePairObjects)) {
                metatypePairObjects[origin] = {};
            }
            if (!(rel in metatypePairObjects[origin])) {
                metatypePairObjects[origin][rel] = {};
            }
            if (!(dest in metatypePairObjects[origin][rel])) {
                metatypePairObjects[origin][rel][dest] = {type: GraphQLString};
            }
        });

        const metatypeGraphQLObjects: {[key: string]: any} = {};

        // we must declare the metadata input object beforehand so we can include it in the final schema entry for each
        // metatype
        const recordInputType = new GraphQLInputObjectType({
            name: 'record_input',
            fields: {
                id: {type: GraphQLString},
                data_source_id: {type: GraphQLString},
                original_id: {type: GraphQLJSON}, // since the original ID might be a number, treat it as valid JSON
                import_id: {type: GraphQLString},
                limit: {type: GraphQLInt, defaultValue: 10000},
                page: {type: GraphQLInt, defaultValue: 1},
            },
        });

        const recordInfo = new GraphQLObjectType({
            name: 'recordInfo',
            fields: {
                id: {type: GraphQLString},
                data_source_id: {type: GraphQLString},
                original_id: {type: GraphQLJSON}, // since the original ID might be a number, treat it as valid JSON
                import_id: {type: GraphQLString},
                metatype_id: {type: GraphQLString},
                metatype_name: {type: GraphQLString},
                created_at: {type: GraphQLString},
                created_by: {type: GraphQLString},
                modified_at: {type: GraphQLString},
                modified_by: {type: GraphQLString},
                metadata: {type: GraphQLJSON},
                count: {type: GraphQLInt},
                page: {type: GraphQLInt},
            },
        });

        // needed when a user decides they want the results as a file vs. a raw return
        const fileInfo = new GraphQLObjectType({
            name: 'fileInfo',
            fields: {
                id: {type: GraphQLString},
                file_name: {type: GraphQLString},
                file_size: {type: GraphQLFloat},
                md5hash: {type: GraphQLString},
                metadata: {type: GraphQLJSON},
                url: {type: GraphQLString},
            },
        });

        metatypeResults.value.forEach((metatype) => {
            if (!metatype.keys || metatype.keys.length === 0) return;

            // the following 4 input/object types are used for querying or introspection on _relationship
            const destinationInputType = new GraphQLInputObjectType({
                name: `${stringToValidPropertyName(metatype.name)}_destination_input`,
                // needed because the return type accepts an object, but throws a fit about it
                // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                // @ts-ignore
                fields: () => {
                    const fields: {[key: string]: {[key: string]: any}} = {};
                    if (metatypePairObjects[stringToValidPropertyName(metatype.name)]) {
                        Object.keys(metatypePairObjects[stringToValidPropertyName(metatype.name)]).forEach((pair) => {
                            Object.keys(metatypePairObjects[stringToValidPropertyName(metatype.name)][pair]).forEach((dest) => {
                                fields[dest] = {type: GraphQLBoolean};
                            });
                        });
                    }
                    return fields;
                },
            });

            const relationshipInputType = new GraphQLInputObjectType({
                name: `${stringToValidPropertyName(metatype.name)}_relationship_input`,
                // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                // @ts-ignore
                fields: () => {
                    const fields: {[key: string]: {[key: string]: GraphQLNamedType | GraphQLList<any>}} = {};
                    if (metatypePairObjects[metatype.name]) {
                        Object.keys(metatypePairObjects[metatype.name]).forEach((rel) => {
                            fields[rel] = {type: new GraphQLList(destinationInputType)};
                        });
                    } else {
                        // if no relationships exists, set relationship to _none: true
                        fields._none = {type: GraphQLBoolean};
                    }
                    return fields;
                },
            });

            const destinationInfo = new GraphQLObjectType({
                name: `${stringToValidPropertyName(metatype.name)}_destinationInfo`,
                // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                // @ts-ignore
                fields: () => {
                    const fields: {[key: string]: any} = {};
                    if (metatypePairObjects[metatype.name]) {
                        Object.keys(metatypePairObjects[metatype.name]).forEach((pair) => {
                            Object.keys(metatypePairObjects[metatype.name][pair]).forEach((dest) => {
                                fields[dest] = {type: GraphQLString};
                            });
                        });
                    }
                    return fields;
                },
            });

            const relationshipInfo = new GraphQLObjectType({
                name: `${stringToValidPropertyName(metatype.name)}_relationshipInfo`,
                // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                // @ts-ignore
                fields: () => {
                    const fields: {[key: string]: any} = {};
                    if (metatypePairObjects[metatype.name]) {
                        Object.keys(metatypePairObjects[metatype.name]).forEach((pair) => {
                            fields[pair] = {type: destinationInfo};
                        });
                    } else {
                        // if no relationships exists, set relationship to _none: true
                        fields._none = {type: GraphQLBoolean};
                    }
                    return fields;
                },
            });

            metatypeGraphQLObjects[stringToValidPropertyName(metatype.name)] = {
                args: {
                    ...this.inputFieldsForMetatype(metatype),
                    _record: {type: recordInputType},
                    _relationship: {type: relationshipInputType},
                },
                description: metatype.description,
                type: options.returnFile
                    ? fileInfo
                    : new GraphQLList(
                        new GraphQLObjectType({
                            name: stringToValidPropertyName(metatype.name),
                            // needed because the return type accepts an object, but throws a fit about it
                            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                            // @ts-ignore
                            fields: () => {
                                const output: {[key: string]: {[key: string]: GraphQLNamedType | GraphQLList<any>}} = {};
                                output._record = {type: recordInfo};
                                output._relationship = {type: relationshipInfo};
                                output._file = {type: fileInfo};

                                metatype.keys?.forEach((metatypeKey) => {
                                    // keys must match the regex format of /^[_a-zA-Z][_a-zA-Z0-9]*$/ in order to be considered
                                    // valid graphql property names. While we force the user to meet these requirements at key
                                    // creation, we can't guarantee that legacy data will conform to these standards
                                    const propertyName = stringToValidPropertyName(metatypeKey.property_name);

                                    switch (metatypeKey.data_type) {
                                        // because we have no specification on our internal number type, we
                                        // must set this as a float for now
                                        case 'number': {
                                            output[propertyName] = {
                                                type: GraphQLFloat,
                                            };
                                            break;
                                        }

                                        case 'boolean': {
                                            output[propertyName] = {
                                                type: GraphQLBoolean,
                                            };
                                            break;
                                        }

                                        case 'string' || 'date' || 'file': {
                                            output[propertyName] = {
                                                type: GraphQLString,
                                            };
                                            break;
                                        }

                                        case 'list': {
                                            output[propertyName] = {
                                                type: new GraphQLList(GraphQLJSON),
                                            };
                                            break;
                                        }

                                        case 'enumeration': {
                                            const enumMap: {[key: string]: GraphQLEnumValueConfig} = {};

                                            if (metatypeKey.options) {
                                                metatypeKey.options.forEach((option) => {
                                                    enumMap[option] = {
                                                        value: option,
                                                    };
                                                });
                                            }

                                            output[propertyName] = {
                                                type: new GraphQLEnumType({
                                                    name: stringToValidPropertyName(`${metatype.name}_${metatypeKey.name}_Enum_TypeA`),
                                                    values: enumMap,
                                                }),
                                            };
                                            break;
                                        }

                                        default: {
                                            output[propertyName] = {
                                                type: GraphQLString,
                                            };
                                        }
                                    }
                                });

                                return output;
                            },
                        }),
                    ),
                resolve: this.resolverForMetatype(containerID, metatype, options),
            };
        });

        const relationshipGraphQLObjects: {[key: string]: any} = {};

        // metadata objects for edges (metatype relationships)
        const edgeRecordInputType = new GraphQLInputObjectType({
            name: 'edge_record_input',
            fields: {
                id: {type: GraphQLString},
                pair_id: {type: GraphQLString},
                data_source_id: {type: GraphQLString},
                import_id: {type: GraphQLString},
                origin_id: {type: GraphQLString},
                destination_id: {type: GraphQLString},
                limit: {type: GraphQLInt, defaultValue: 10000},
                page: {type: GraphQLInt, defaultValue: 1},
            },
        });

        const edgeRecordInfo = new GraphQLObjectType({
            name: 'edge_recordInfo',
            fields: {
                id: {type: GraphQLString},
                pair_id: {type: GraphQLString},
                data_source_id: {type: GraphQLString},
                import_id: {type: GraphQLString},
                origin_id: {type: GraphQLString},
                origin_metatype_id: {type: GraphQLString},
                destination_id: {type: GraphQLString},
                destination_metatype_id: {type: GraphQLString},
                relationship_name: {type: GraphQLString},
                created_at: {type: GraphQLString},
                created_by: {type: GraphQLString},
                modified_at: {type: GraphQLString},
                modified_by: {type: GraphQLString},
                metadata: {type: GraphQLJSON},
                count: {type: GraphQLInt},
                page: {type: GraphQLInt},
            },
        });

        relationshipResults.value.forEach((relationship) => {
            relationshipGraphQLObjects[stringToValidPropertyName(relationship.name)] = {
                args: {
                    ...this.inputFieldsForRelationship(relationship),
                    _record: {type: edgeRecordInputType},
                },
                description: relationship.description,
                type: (options.returnFile) ? fileInfo : new GraphQLList(
                    new GraphQLObjectType({
                        name: stringToValidPropertyName(relationship.name),
                        // needed because the return type accepts an object, but throws a fit about it
                        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                        // @ts-ignore
                        fields: () => {
                            const output: {[key: string]: {[key: string]: GraphQLNamedType | GraphQLList<any>}} = {};
                            output._record = {type: edgeRecordInfo};

                            relationship.keys?.forEach((relationshipKey) => {
                                const propertyName = stringToValidPropertyName(relationshipKey.property_name);

                                switch (relationshipKey.data_type) {
                                    // because we have no specification on our internal number type, we
                                    // must set this as a float for now
                                    case 'number': {
                                        output[propertyName] = {
                                            type: GraphQLFloat,
                                        };
                                        break;
                                    }

                                    case 'boolean': {
                                        output[propertyName] = {
                                            type: GraphQLBoolean,
                                        };
                                        break;
                                    }

                                    case 'string' || 'date' || 'file': {
                                        output[propertyName] = {
                                            type: GraphQLString,
                                        };
                                        break;
                                    }

                                    case 'list': {
                                        output[propertyName] = {
                                            type: new GraphQLList(GraphQLJSON),
                                        };
                                        break;
                                    }

                                    case 'enumeration': {
                                        const enumMap: {[key: string]: GraphQLEnumValueConfig} = {};

                                        if (relationshipKey.options) {
                                            relationshipKey.options.forEach((option) => {
                                                enumMap[option] = {
                                                    value: option,
                                                };
                                            });
                                        }

                                        output[propertyName] = {
                                            type: new GraphQLEnumType({
                                                name: stringToValidPropertyName(`${relationship.name}_${relationshipKey.name}_Enum_TypeA`),
                                                values: enumMap,
                                            }),
                                        };
                                        break;
                                    }

                                    default: {
                                        output[propertyName] = {
                                            type: GraphQLString,
                                        };
                                    }
                                }
                            });
                            return output;
                        },
                    }),
                ),
                resolve: this.resolverForRelationships(containerID, relationship, options),
            };
        });

        const metatypeObjects = new GraphQLObjectType({
            name: 'metatypes',
            fields: metatypeGraphQLObjects,
        });

        const relationshipObjects = new GraphQLObjectType({
            name: 'relationships',
            fields: relationshipGraphQLObjects,
        });

        // nodeType and edgeType for flexibility in filtering graph return
        const nodeInputType = new GraphQLInputObjectType({
            name: 'node_input',
            fields: {
                name: {type: GraphQLString},
                id: {type: GraphQLString},
                origin_name: {type: GraphQLString},
                origin_id: {type: GraphQLString},
                destination_name: {type: GraphQLString},
                destination_id: {type: GraphQLString},
            },
        });

        const edgeInputType = new GraphQLInputObjectType({
            name: 'edge_input',
            fields: {
                name: {type: GraphQLString},
                id: {type: GraphQLString},
            },
        });

        // the fields on which a user can filter the graph return
        const graphInput: {[key: string]: any} = {
            root_node: {type: new GraphQLNonNull(GraphQLString)}, // root node must be specified
            node_type: {type: nodeInputType},
            edge_type: {type: edgeInputType},
            depth: {type: new GraphQLNonNull(GraphQLString)}, // depth must be specified
        };

        const graphType = new GraphQLList(
            new GraphQLObjectType({
                name: 'graph_type',
                fields: {
                    // For more advanced querying these may become an Object type of their own
                    // to retrieve only specific properties from origin, edge and destination.
                    // For now json will do.
                    origin_properties: {type: GraphQLJSON},
                    edge_properties: {type: GraphQLJSON},
                    destination_properties: {type: GraphQLJSON},
                    // origin data
                    origin_id: {type: GraphQLString},
                    origin_metatype_name: {type: GraphQLString},
                    origin_metatype_id: {type: GraphQLString},
                    origin_data_source: {type: GraphQLString},
                    origin_metadata: {type: GraphQLJSON},
                    origin_created_by: {type: GraphQLString},
                    origin_created_at: {type: GraphQLString},
                    origin_modified_by: {type: GraphQLString},
                    origin_modified_at: {type: GraphQLString},
                    // edge data
                    edge_id: {type: GraphQLString},
                    relationship_name: {type: GraphQLString},
                    relationship_pair_id: {type: GraphQLString},
                    relationship_id: {type: GraphQLString},
                    edge_data_source: {type: GraphQLString},
                    edge_metadata: {type: GraphQLJSON},
                    edge_created_by: {type: GraphQLString},
                    edge_created_at: {type: GraphQLString},
                    edge_modified_by: {type: GraphQLString},
                    edge_modified_at: {type: GraphQLString},
                    // destination data
                    destination_id: {type: GraphQLString},
                    destination_metatype_name: {type: GraphQLString},
                    destination_metatype_id: {type: GraphQLString},
                    destination_data_source: {type: GraphQLString},
                    destination_metadata: {type: GraphQLJSON},
                    destination_created_by: {type: GraphQLString},
                    destination_created_at: {type: GraphQLString},
                    destination_modified_by: {type: GraphQLString},
                    destination_modified_at: {type: GraphQLString},
                    // graph metadata
                    depth: {type: GraphQLInt},
                    path: {type: GraphQLList(GraphQLString)},
                },
            }),
        );

        const fields: {[key: string]: any} = {};

        if (Object.keys(metatypeGraphQLObjects).length > 0) {
            fields.metatypes = {
                type: metatypeObjects,
                resolve: () => {
                    return metatypeGraphQLObjects;
                },
            };
        }

        if (Object.keys(relationshipGraphQLObjects).length > 0) {
            fields.relationships = {
                type: relationshipObjects,
                resolve: () => {
                    return relationshipGraphQLObjects;
                },
            };
        }

        fields.graph = {
            args: {...graphInput},
            type: (options.returnFile) ? fileInfo : graphType,
            resolve: this.resolverForGraph(containerID, options) as any,
        };

        return Promise.resolve(
            Result.Success(
                new GraphQLSchema({
                    query: new GraphQLObjectType({
                        name: 'Query',
                        fields,
                    }),
                }),
            ),
        );
    }
Example #27
Source File: schema.ts    From peterportal-public-api with MIT License 4 votes vote down vote up
queryType: GraphQLObjectType = new GraphQLObjectType({
  name: 'Query',
  fields: () =>  ({

    // query course by ID
    course: {
      type: courseType,

      // specify args to query by
      args: {
        id: { type: new GraphQLNonNull(GraphQLString), description: "Course Department concatenated with Course Number. Ex: COMPSCI161" }
      },

      // define function to get a course
      resolve: (_, {id}) => {
        return getCourse(id);
      },

      // documentation
      description: "Search courses by their course id. Ex: COMPSCI161"
    },

    // get instructor by ucinetid
    instructor: {
      type: instructorType,

      // specify args to query by (ucinetid)
      args: {
        ucinetid: { type: new GraphQLNonNull(GraphQLString), description: "ucinetid of a specific instructor. Ex: mikes"}
      },

      // define function to get a instructor
      resolve: (_, {ucinetid}) => {
        return getInstructor(ucinetid);
      },

      // documentation for instructor
      description: "Search instructors by their ucinetid"
    },

    // return all courses
    allCourses: {
      type: new GraphQLList(courseType),

      // get all courses from courses cache
      resolve: () => {
        return getAllCourses()
      },

      // documentation for all courses
      description: "Return all courses. Takes no arguments"
    },

    // return all instructor
    allInstructors: {
      type: new GraphQLList(instructorType),

      // get all instructors from cache
      resolve: () => {
        return getAllInstructors();
      },

      // documentation for all instructors
      description: "Return all instructors. Takes no arguments"
    },

    schedule: {
      type: new GraphQLList(courseOfferingType),

      args: {
        year: { type: new GraphQLNonNull(GraphQLFloat), description: "Year of the term. Required." },
        quarter: { type: new GraphQLNonNull(GraphQLString), description: "Quarter of the term. ['Fall'|'Winter'|'Spring'|'Summer1'|'Summer2'|'Summer10wk']. Required." },
        ge: { type: GraphQLString, description: "GE type. ['ANY'|'GE-1A'|'GE-1B'|'GE-2'|'GE-3'|'GE-4'|'GE-5A'|'GE-5B'|'GE-6'|'GE-7'|'GE-8']." },
        department: { type: GraphQLString, description: "Department Code." },
        course_number: { type: GraphQLString, description: "Course number or range. Ex: '32A' or '31-33'." },
        division: { type: GraphQLString, description: "Division level of a course. ['ALL'|'LowerDiv'|'UpperDiv'|'Graduate']. Default: 'ALL'." },
        section_codes: { type: GraphQLString, description: "5-digit course code or range. Ex: '36531' or '36520-36536'." },
        instructor: { type: GraphQLString, description: "Instructor last name or part of last name." },
        course_title: { type: GraphQLString, description: "Title of a course." },
        section_type: { type: GraphQLString, description: "Type of section. ['ALL'|'ACT'|'COL'|'DIS'|'FLD'|'LAB'|'LEC'|'QIZ'|'RES'|'SEM'|'STU'|'TAP'|'TUT']. Default: 'ALL'." },
        units: { type: GraphQLString, description: "Unit count of a course. Ex: '4' or '1.3'. Use 'VAR' to look for variable unit classes." },
        days: { type: GraphQLString, description: "Days that a course is offered. Any combination of ['Su'|'M'|'T'|'W'|'Th'|'F'|'Sa']. Ex: 'MWF'." },
        start_time: { type: GraphQLString, description: "Start time of a couse in 12 hour format. Ex: '10:00AM' or '5:00PM'" },
        end_time: { type: GraphQLString, description: "End time of a couse in 12 hour format. Ex: '10:00AM' or '5:00PM'" },
        max_capacity: { type: GraphQLString, description: "Maximum enrollment capacity of a choice. Specify a " },
        full_courses: { type: GraphQLString, description: "Status of a course's enrollment state. ['ANY'|'SkipFullWaitlist'|'FullOnly'|'OverEnrolled']. Default: 'ANY'." },
        cancelled_courses: { type: GraphQLString, description: "Indicate whether to ['Exclude'|'Include'|'Only'] cancelled courses. Default: 'EXCLUDE'." },
        building: { type: GraphQLString, description: "Building code found on https://www.reg.uci.edu/addl/campus/." },
        room: { type: GraphQLString, description: "Room number in a building. Must also specify a building code." }
      },

      resolve: async (_, args) => {
        validateScheduleArgs(args);
        const query = scheduleArgsToQuery(args);
        const results: CourseOffering[] = await getCourseSchedules(query);
        return results;
      },

      description: "Return schedule from websoc."
    },

    // return week of 'date' argument or current week if 'date' is empty.
    week: {
      type: weekType,
      //date argument
      args: {
        year: { type: GraphQLString, description: "Must be in ISO 8601 extended format `YYYY`. "},
        month: { type: GraphQLString, description: "Must be in ISO 8601 extended format `MM`. "},
        day: { type: GraphQLString, description: "Must be in ISO 8601 extended format `DD`. "}
      },

      //calls getWeek(), fetching from UCI's academic calendar
      resolve: async (_, {year, month, day}) => {
        try{
          return await getWeek(year, month, day);
        }
        catch(e) {
          throw new ValidationError("Invalid year, month or day. Must include all year, month and day or none.")
        }
      },
      description: "Returns the week and quarter, given a specific date. No parameters given uses today's date. Must include all year, month and day or none. "
    },

    grades: {
      type: gradeDistributionCollectionType,

      args: {
        year: { type: GraphQLString, description: "Must be <START_YEAR>-<END_YEAR>. Ex. 2020-2021. Multiple values in the arguments can be included by using ; as a separator."},
        quarter: { type: GraphQLString, description: "Fall | Winter | Spring | Summer Multiple values in the arguments can be included by using ; as a separator."},
        instructor: { type: GraphQLString, description: "Instructor, must following the format (<last_name>, <first_initial>.) Multiple values in the arguments can be included by using ; as a separator."},
        department: { type: GraphQLString, description: "Department short-hand. Ex. COMPSCI. Multiple values in the arguments can be included by using ; as a separator."},
        number: { type: GraphQLString, description: "Course number. Multiple values in the arguments can be included by using ; as a separator."},
        code: { type: GraphQLString, description: "5-digit course code on WebSoC. Multiple values in the arguments can be included by using ; as a separator." }, 
        division: { type: GraphQLString, description: "Filter by Course Level ('LowerDiv'|'UpperDiv')"},
        excludePNP: { type: GraphQLBoolean, description: "Exclude P/NP Only courses" }
      },

      resolve: (_, args, __, info) => {
        // Get the fields requested in the query
        // This allows us to only fetch what the client wants from sql
        const requestedFields : string[] = Object.keys(parseResolveInfo(info).fieldsByTypeName.GradeDistributionCollection)
      
        // Construct a WHERE clause from the arguments
        const where : WhereParams = parseGradesParamsToSQL(args);
        
        // If requested, retrieve the grade distributions
        let grade_distributions: GradeGQLData[];
        let rawGrades : GradeRawData = undefined;
        if (requestedFields.includes('grade_distributions')) {
          rawGrades = fetchGrades(where)

          // Format the results to GraphQL
          grade_distributions = rawGrades.map(result => {
            return {
              grade_a_count: result.gradeACount,
              grade_b_count: result.gradeBCount,
              grade_c_count: result.gradeCCount,
              grade_d_count: result.gradeDCount,
              grade_f_count: result.gradeFCount,
              grade_p_count: result.gradePCount,
              grade_np_count: result.gradeNPCount,
              grade_w_count: result.gradeWCount,
              average_gpa: result.averageGPA ?? null,
              course_offering: {
                year: result.year,
                quarter: result.quarter,
                section: {
                  code: result.code,
                  number: result.section,
                  type: result.type,
                },
                instructors: [result.instructor],
                course: {
                  id: result.department.replace(/\s/g, '')+result.number,
                  department: result.department,
                  number: result.number,
                  department_name: result.department_name,
                  title: result.title
                }
              }
            }
          })
        }
        
        // If requested, retrieve the aggregate
        let aggregate : GradeDistAggregate = undefined;
        if (requestedFields.includes('aggregate')) {
          const aggregateResult = fetchAggregatedGrades(where)
      
          // Format results to GraphQL
          aggregate = {
            sum_grade_a_count: aggregateResult['sum_grade_a_count'],
            sum_grade_b_count: aggregateResult['sum_grade_b_count'],
            sum_grade_c_count: aggregateResult['sum_grade_c_count'],
            sum_grade_d_count: aggregateResult['sum_grade_d_count'],
            sum_grade_f_count: aggregateResult['sum_grade_f_count'],
            sum_grade_p_count: aggregateResult['sum_grade_p_count'],
            sum_grade_np_count: aggregateResult['sum_grade_np_count'],
            sum_grade_w_count: aggregateResult['sum_grade_w_count'],
            average_gpa: aggregateResult['average_gpa'],
            count: aggregateResult['count']
          }
        }

        // If requested, retrieve the instructors
        let instructors : string[] = undefined;
        if (requestedFields.includes('instructors')) {
          if (rawGrades) {
            // If the grade results exist, we can get the instructors from there
            instructors = [...new Set(rawGrades.map(result => result.instructor))]
          } else {
            // Else query sql for the instructors
            instructors = fetchInstructors(where)
          }
        }
        
        // Return results
        return {
          aggregate,
          grade_distributions,
          instructors
        }
      },

      description: "Search for grade distributions. Multiple values in the arguments can be included by using ; as a separator. "
    }
  })
})
Example #28
Source File: index.test.ts    From hono with MIT License 4 votes vote down vote up
describe('Error handling functionality', () => {
  const app = new Hono()
  app.use(
    '/graphql',
    graphqlServer({
      schema: TestSchema,
    })
  )

  it('Handles query errors from non-null top field errors', async () => {
    const schema = new GraphQLSchema({
      query: new GraphQLObjectType({
        name: 'Query',
        fields: {
          test: {
            type: new GraphQLNonNull(GraphQLString),
            resolve() {
              throw new Error('Throws!')
            },
          },
        },
      }),
    })
    const app = new Hono()

    app.use('/graphql', graphqlServer({ schema }))

    const res = await app.request(
      urlString({
        query: '{ test }',
      })
    )

    expect(res.status).toBe(500)
  })

  it('Handles syntax errors caught by GraphQL', async () => {
    const res = await app.request(
      urlString({
        query: 'syntax_error',
      }),
      {
        method: 'GET',
      }
    )

    expect(res.status).toBe(400)
  })

  it('Handles errors caused by a lack of query', async () => {
    const res = await app.request(urlString(), {
      method: 'GET',
    })

    expect(res.status).toBe(400)
  })

  it('Handles invalid JSON bodies', async () => {
    const res = await app.request(urlString(), {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify([]),
    })

    expect(res.status).toBe(400)
  })

  it('Handles incomplete JSON bodies', async () => {
    const res = await app.request(urlString(), {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: '{"query":',
    })
    expect(res.status).toBe(400)
  })

  it('Handles plain POST text', async () => {
    const res = await app.request(
      urlString({
        variables: JSON.stringify({ who: 'Dolly' }),
      }),
      {
        method: 'POST',
        headers: {
          'Content-Type': 'text/plain',
        },
        body: 'query helloWho($who: String){ test(who: $who) }',
      }
    )
    expect(res.status).toBe(400)
  })

  it('Handles poorly formed variables', async () => {
    const res = await app.request(
      urlString({
        variables: 'who:You',
        query: 'query helloWho($who: String){ test(who: $who) }',
      }),
      {
        method: 'GET',
      }
    )
    expect(res.status).toBe(400)
  })

  it('Handles invalid variables', async () => {
    const res = await app.request(urlString(), {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        query: 'query helloWho($who: String){ test(who: $who) }',
        variables: { who: ['John', 'Jane'] },
      }),
    })
    expect(res.status).toBe(500)
  })

  it('Handles unsupported HTTP methods', async () => {
    const res = await app.request(urlString({ query: '{test}' }), {
      method: 'PUT',
    })

    expect(res.status).toBe(405)
    expect(res.headers.get('allow')).toBe('GET, POST')
    expect(await res.json()).toEqual({
      errors: [{ message: 'GraphQL only supports GET and POST requests.' }],
    })
  })
})
Example #29
Source File: index.ts    From graphql-mesh with MIT License 4 votes vote down vote up
async getMeshSource() {
    const { schemaHeaders, serviceName, operationHeaders } = this.config;

    const thriftAST = await this.idl.getWithSet(async () => {
      const rawThrift = await readFileOrUrl<string>(this.config.idl, {
        allowUnknownExtensions: true,
        cwd: this.baseDir,
        headers: schemaHeaders,
      });
      const parseResult = parse(rawThrift, { organize: false });
      if (parseResult.type === SyntaxType.ThriftErrors) {
        throw new AggregateError(parseResult.errors);
      }
      return parseResult;
    });

    const enumTypeMap = new Map<string, GraphQLEnumType>();
    const outputTypeMap = new Map<string, GraphQLOutputType>();
    const inputTypeMap = new Map<string, GraphQLInputType>();
    const rootFields: GraphQLFieldConfigMap<any, any> = {};
    const annotations: IThriftAnnotations = {};
    const methodAnnotations: IMethodAnnotations = {};
    const methodNames: string[] = [];
    const methodParameters: {
      [methodName: string]: number;
    } = {};

    type TypeVal = BaseTypeVal | ListTypeVal | SetTypeVal | MapTypeVal | EnumTypeVal | StructTypeVal | VoidTypeVal;
    type BaseTypeVal = {
      id?: number;
      type: TType.BOOL | TType.BYTE | TType.DOUBLE | TType.I16 | TType.I32 | TType.I64 | TType.STRING;
    };
    type ListTypeVal = { id?: number; type: TType.LIST; elementType: TypeVal };
    type SetTypeVal = { id?: number; type: TType.SET; elementType: TypeVal };
    type MapTypeVal = { id?: number; type: TType.MAP; keyType: TypeVal; valType: TypeVal };
    type EnumTypeVal = { id?: number; type: TType.ENUM };
    type StructTypeVal = { id?: number; type: TType.STRUCT; name: string; fields: TypeMap };
    type VoidTypeVal = { id?: number; type: TType.VOID };
    type TypeMap = Record<string, TypeVal>;
    const topTypeMap: TypeMap = {};

    class MeshThriftClient<Context = any> extends ThriftClient<Context> {
      public static readonly serviceName: string = serviceName;
      public static readonly annotations: IThriftAnnotations = annotations;
      public static readonly methodAnnotations: IMethodAnnotations = methodAnnotations;
      public static readonly methodNames: Array<string> = methodNames;
      public readonly _serviceName: string = serviceName;
      public readonly _annotations: IThriftAnnotations = annotations;
      public readonly _methodAnnotations: IMethodAnnotations = methodAnnotations;
      public readonly _methodNames: Array<string> = methodNames;
      public readonly _methodParameters?: {
        [methodName: string]: number;
      } = methodParameters;

      writeType(typeVal: TypeVal, value: any, output: TProtocol) {
        switch (typeVal.type) {
          case TType.BOOL:
            output.writeBool(value);
            break;
          case TType.BYTE:
            output.writeByte(value);
            break;
          case TType.DOUBLE:
            output.writeDouble(value);
            break;
          case TType.I16:
            output.writeI16(value);
            break;
          case TType.I32:
            output.writeI32(value);
            break;
          case TType.I64:
            output.writeI64(value.toString());
            break;
          case TType.STRING:
            output.writeString(value);
            break;
          case TType.STRUCT: {
            output.writeStructBegin(typeVal.name);
            const typeMap = typeVal.fields;
            for (const argName in value) {
              const argType = typeMap[argName];
              const argVal = value[argName];
              if (argType) {
                output.writeFieldBegin(argName, argType.type, argType.id);
                this.writeType(argType, argVal, output);
                output.writeFieldEnd();
              }
            }
            output.writeFieldStop();
            output.writeStructEnd();
            break;
          }
          case TType.ENUM:
            // TODO: A
            break;
          case TType.MAP: {
            const keys = Object.keys(value);
            output.writeMapBegin(typeVal.keyType.type, typeVal.valType.type, keys.length);
            for (const key of keys) {
              this.writeType(typeVal.keyType, key, output);
              const val = value[key];
              this.writeType(typeVal.valType, val, output);
            }
            output.writeMapEnd();
            break;
          }
          case TType.LIST:
            output.writeListBegin(typeVal.elementType.type, value.length);
            for (const element of value) {
              this.writeType(typeVal.elementType, element, output);
            }
            output.writeListEnd();
            break;
          case TType.SET:
            output.writeSetBegin(typeVal.elementType.type, value.length);
            for (const element of value) {
              this.writeType(typeVal.elementType, element, output);
            }
            output.writeSetEnd();
            break;
        }
      }

      readType(type: TType, input: TProtocol): any {
        switch (type) {
          case TType.BOOL:
            return input.readBool();
          case TType.BYTE:
            return input.readByte();
          case TType.DOUBLE:
            return input.readDouble();
          case TType.I16:
            return input.readI16();
          case TType.I32:
            return input.readI32();
          case TType.I64:
            return BigInt(input.readI64().toString());
          case TType.STRING:
            return input.readString();
          case TType.STRUCT: {
            const result: any = {};
            input.readStructBegin();
            while (true) {
              const field: IThriftField = input.readFieldBegin();
              const fieldType = field.fieldType;
              const fieldName = field.fieldName || 'success';
              if (fieldType === TType.STOP) {
                break;
              }
              result[fieldName] = this.readType(fieldType, input);
              input.readFieldEnd();
            }
            input.readStructEnd();
            return result;
          }
          case TType.ENUM:
            // TODO: A
            break;
          case TType.MAP: {
            const result: any = {};
            const map = input.readMapBegin();
            for (let i = 0; i < map.size; i++) {
              const key = this.readType(map.keyType, input);
              const value = this.readType(map.valueType, input);
              result[key] = value;
            }
            input.readMapEnd();
            return result;
          }
          case TType.LIST: {
            const result: any[] = [];
            const list = input.readListBegin();
            for (let i = 0; i < list.size; i++) {
              const element = this.readType(list.elementType, input);
              result.push(element);
            }
            input.readListEnd();
            return result;
          }
          case TType.SET: {
            const result: any[] = [];
            const list = input.readSetBegin();
            for (let i = 0; i < list.size; i++) {
              const element = this.readType(list.elementType, input);
              result.push(element);
            }
            input.readSetEnd();
            return result;
          }
        }
      }

      async doRequest(methodName: string, args: any, fields: TypeMap, context?: any) {
        const Transport = this.transport;
        const Protocol = this.protocol;
        const writer: TTransport = new Transport();
        const output: TProtocol = new Protocol(writer);
        const id = this.incrementRequestId();
        output.writeMessageBegin(methodName, MessageType.CALL, id);
        this.writeType(
          {
            name: pascalCase(methodName) + '__Args',
            type: TType.STRUCT,
            fields,
            id,
          },
          args,
          output
        );
        output.writeMessageEnd();
        const data: Buffer = await this.connection.send(writer.flush(), context);
        const reader: TTransport = this.transport.receiver(data);
        const input: TProtocol = new Protocol(reader);
        const { fieldName, messageType }: IThriftMessage = input.readMessageBegin();
        if (fieldName === methodName) {
          if (messageType === MessageType.EXCEPTION) {
            const err: TApplicationException = TApplicationExceptionCodec.decode(input);
            input.readMessageEnd();
            return Promise.reject(err);
          } else {
            const result = this.readType(TType.STRUCT, input);
            input.readMessageEnd();
            if (result.success != null) {
              return result.success;
            } else {
              throw new TApplicationException(
                TApplicationExceptionType.UNKNOWN,
                methodName + ' failed: unknown result'
              );
            }
          }
        } else {
          throw new TApplicationException(
            TApplicationExceptionType.WRONG_METHOD_NAME,
            'Received a response to an unknown RPC function: ' + fieldName
          );
        }
      }
    }
    const thriftHttpClient = createHttpClient(MeshThriftClient, {
      ...this.config,
      requestOptions: {
        headers: operationHeaders,
      },
    });

    function processComments(comments: Comment[]) {
      return comments.map(comment => comment.value).join('\n');
    }

    function getGraphQLFunctionType(
      functionType: FunctionType,
      id = Math.random()
    ): { outputType: GraphQLOutputType; inputType: GraphQLInputType; typeVal: TypeVal } {
      let inputType: GraphQLInputType;
      let outputType: GraphQLOutputType;
      let typeVal: TypeVal;
      switch (functionType.type) {
        case SyntaxType.BinaryKeyword:
        case SyntaxType.StringKeyword:
          inputType = GraphQLString;
          outputType = GraphQLString;
          break;
        case SyntaxType.DoubleKeyword:
          inputType = GraphQLFloat;
          outputType = GraphQLFloat;
          typeVal = typeVal! || { type: TType.DOUBLE };
          break;
        case SyntaxType.VoidKeyword:
          typeVal = typeVal! || { type: TType.VOID };
          inputType = GraphQLVoid;
          outputType = GraphQLVoid;
          break;
        case SyntaxType.BoolKeyword:
          typeVal = typeVal! || { type: TType.BOOL };
          inputType = GraphQLBoolean;
          outputType = GraphQLBoolean;
          break;
        case SyntaxType.I8Keyword:
          inputType = GraphQLInt;
          outputType = GraphQLInt;
          typeVal = typeVal! || { type: TType.I08 };
          break;
        case SyntaxType.I16Keyword:
          inputType = GraphQLInt;
          outputType = GraphQLInt;
          typeVal = typeVal! || { type: TType.I16 };
          break;
        case SyntaxType.I32Keyword:
          inputType = GraphQLInt;
          outputType = GraphQLInt;
          typeVal = typeVal! || { type: TType.I32 };
          break;
        case SyntaxType.ByteKeyword:
          inputType = GraphQLByte;
          outputType = GraphQLByte;
          typeVal = typeVal! || { type: TType.BYTE };
          break;
        case SyntaxType.I64Keyword:
          inputType = GraphQLBigInt;
          outputType = GraphQLBigInt;
          typeVal = typeVal! || { type: TType.I64 };
          break;
        case SyntaxType.ListType: {
          const ofTypeList = getGraphQLFunctionType(functionType.valueType, id);
          inputType = new GraphQLList(ofTypeList.inputType);
          outputType = new GraphQLList(ofTypeList.outputType);
          typeVal = typeVal! || { type: TType.LIST, elementType: ofTypeList.typeVal };
          break;
        }
        case SyntaxType.SetType: {
          const ofSetType = getGraphQLFunctionType(functionType.valueType, id);
          inputType = new GraphQLList(ofSetType.inputType);
          outputType = new GraphQLList(ofSetType.outputType);
          typeVal = typeVal! || { type: TType.SET, elementType: ofSetType.typeVal };
          break;
        }
        case SyntaxType.MapType: {
          inputType = GraphQLJSON;
          outputType = GraphQLJSON;
          const ofTypeKey = getGraphQLFunctionType(functionType.keyType, id);
          const ofTypeValue = getGraphQLFunctionType(functionType.valueType, id);
          typeVal = typeVal! || { type: TType.MAP, keyType: ofTypeKey.typeVal, valType: ofTypeValue.typeVal };
          break;
        }
        case SyntaxType.Identifier: {
          const typeName = functionType.value;
          if (enumTypeMap.has(typeName)) {
            const enumType = enumTypeMap.get(typeName)!;
            inputType = enumType;
            outputType = enumType;
          }
          if (inputTypeMap.has(typeName)) {
            inputType = inputTypeMap.get(typeName)!;
          }
          if (outputTypeMap.has(typeName)) {
            outputType = outputTypeMap.get(typeName)!;
          }
          typeVal = topTypeMap[typeName];
          break;
        }
        default:
          throw new Error(`Unknown function type: ${util.inspect(functionType)}!`);
      }
      return {
        inputType: inputType!,
        outputType: outputType!,
        typeVal: {
          ...typeVal!,
          id,
        },
      };
    }

    const { args: commonArgs, contextVariables } = parseInterpolationStrings(Object.values(operationHeaders || {}));

    const headersFactory = getInterpolatedHeadersFactory(operationHeaders);

    for (const statement of thriftAST.body) {
      switch (statement.type) {
        case SyntaxType.EnumDefinition:
          enumTypeMap.set(
            statement.name.value,
            new GraphQLEnumType({
              name: statement.name.value,
              description: processComments(statement.comments),
              values: statement.members.reduce(
                (prev, curr) => ({
                  ...prev,
                  [curr.name.value]: {
                    description: processComments(curr.comments),
                    value: curr.name.value,
                  },
                }),
                {} as GraphQLEnumValueConfigMap
              ),
            })
          );
          break;
        case SyntaxType.StructDefinition: {
          const structName = statement.name.value;
          const description = processComments(statement.comments);
          const objectFields: GraphQLFieldConfigMap<any, any> = {};
          const inputObjectFields: GraphQLInputFieldConfigMap = {};
          const structTypeVal: StructTypeVal = {
            id: Math.random(),
            name: structName,
            type: TType.STRUCT,
            fields: {},
          };
          topTypeMap[structName] = structTypeVal;
          const structFieldTypeMap = structTypeVal.fields;
          for (const field of statement.fields) {
            const fieldName = field.name.value;
            let fieldOutputType: GraphQLOutputType;
            let fieldInputType: GraphQLInputType;
            const description = processComments(field.comments);
            const processedFieldTypes = getGraphQLFunctionType(field.fieldType, field.fieldID?.value);
            fieldOutputType = processedFieldTypes.outputType;
            fieldInputType = processedFieldTypes.inputType;

            if (field.requiredness === 'required') {
              fieldOutputType = new GraphQLNonNull(fieldOutputType);
              fieldInputType = new GraphQLNonNull(fieldInputType);
            }

            objectFields[fieldName] = {
              type: fieldOutputType,
              description,
            };
            inputObjectFields[fieldName] = {
              type: fieldInputType,
              description,
            };
            structFieldTypeMap[fieldName] = processedFieldTypes.typeVal;
          }
          outputTypeMap.set(
            structName,
            new GraphQLObjectType({
              name: structName,
              description,
              fields: objectFields,
            })
          );
          inputTypeMap.set(
            structName,
            new GraphQLInputObjectType({
              name: structName + 'Input',
              description,
              fields: inputObjectFields,
            })
          );
          break;
        }
        case SyntaxType.ServiceDefinition:
          for (const fnIndex in statement.functions) {
            const fn = statement.functions[fnIndex];
            const fnName = fn.name.value;
            const description = processComments(fn.comments);
            const { outputType: returnType } = getGraphQLFunctionType(fn.returnType, Number(fnIndex) + 1);
            const args: GraphQLFieldConfigArgumentMap = {};
            for (const argName in commonArgs) {
              const typeNameOrType = commonArgs[argName].type;
              args[argName] = {
                type:
                  typeof typeNameOrType === 'string' ? inputTypeMap.get(typeNameOrType) : typeNameOrType || GraphQLID,
              };
            }
            const fieldTypeMap: TypeMap = {};
            for (const field of fn.fields) {
              const fieldName = field.name.value;
              const fieldDescription = processComments(field.comments);
              let { inputType: fieldType, typeVal } = getGraphQLFunctionType(field.fieldType, field.fieldID?.value);
              if (field.requiredness === 'required') {
                fieldType = new GraphQLNonNull(fieldType);
              }
              args[fieldName] = {
                type: fieldType,
                description: fieldDescription,
              };
              fieldTypeMap[fieldName] = typeVal;
            }
            rootFields[fnName] = {
              type: returnType,
              description,
              args,
              resolve: async (root, args, context, info) =>
                thriftHttpClient.doRequest(fnName, args, fieldTypeMap, {
                  headers: headersFactory({ root, args, context, info, env: process.env }),
                }),
            };
            methodNames.push(fnName);
            methodAnnotations[fnName] = { annotations: {}, fieldAnnotations: {} };
            methodParameters[fnName] = fn.fields.length + 1;
          }
          break;
        case SyntaxType.TypedefDefinition: {
          const { inputType, outputType } = getGraphQLFunctionType(statement.definitionType, Math.random());
          const typeName = statement.name.value;
          inputTypeMap.set(typeName, inputType);
          outputTypeMap.set(typeName, outputType);
          break;
        }
      }
    }

    const queryObjectType = new GraphQLObjectType({
      name: 'Query',
      fields: rootFields,
    });

    const schema = new GraphQLSchema({
      query: queryObjectType,
    });

    return {
      schema,
      contextVariables,
    };
  }