graphql#isUnionType TypeScript Examples

The following examples show how to use graphql#isUnionType. 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: index.ts    From amplify-codegen with Apache License 2.0 6 votes vote down vote up
addTypeUsed(type: GraphQLType) {
    if (this.typesUsedSet.has(type)) return;

    if (
      isEnumType(type) ||
      isUnionType(type) ||
      isInputObjectType(type) ||
      isInterfaceType(type) ||
      isObjectType(type) ||
      (isScalarType(type) && !isSpecifiedScalarType(type))
    ) {
      this.typesUsedSet.add(type);
    }
    if (isInterfaceType(type) || isUnionType(type)) {
      for (const concreteType of this.schema.getPossibleTypes(type)) {
        this.addTypeUsed(getNamedType(concreteType));
      }
    }
    if (isInputObjectType(type)) {
      for (const field of Object.values(type.getFields())) {
        this.addTypeUsed(getNamedType(field.type));
      }
    }
    if (isObjectType(type)) {
      for (const fieldType of type.getInterfaces()) {
        this.addTypeUsed(getNamedType(fieldType));
      }
      for (const field of Object.values(type.getFields())) {
        this.addTypeUsed(getNamedType(field.type));
      }
    }
  }
Example #2
Source File: serializeToJSON.ts    From amplify-codegen with Apache License 2.0 6 votes vote down vote up
function serializeType(type: GraphQLType) {
  if (isEnumType(type)) {
    return serializeEnumType(type);
  } else if (isUnionType(type)) {
    return serializeUnionType(type);
  } else if (isInputObjectType(type)) {
    return serializeInputObjectType(type);
  } else if (isObjectType(type)) {
    return serializeObjectType(type);
  } else if (isInterfaceType(type)) {
    return serializeInterfaceType(type);
  } else if (isScalarType(type)) {
    return serializeScalarType(type);
  } else {
    throw new Error(`Unexpected GraphQL type: ${type}`);
  }
}
Example #3
Source File: codeGeneration.ts    From amplify-codegen with Apache License 2.0 6 votes vote down vote up
export function typeDeclarationForGraphQLType(generator: CodeGenerator, type: GraphQLType) {
  if (isEnumType(type)) {
    enumerationDeclaration(generator, type);
  } else if (isUnionType(type)) {
    unionDeclaration(generator, type);
  } else if (isInputObjectType(type)) {
    structDeclarationForInputObjectType(generator, type);
  } else if (isObjectType(type)) {
    structDeclarationForObjectType(generator, type);
  } else if (isInterfaceType(type)) {
    structDeclarationForInterfaceType(generator, type);
  }
}
Example #4
Source File: codeGeneration.ts    From amplify-codegen with Apache License 2.0 6 votes vote down vote up
function getObjectTypeName(type: GraphQLType): string {
  if (isListType(type)) {
    return getObjectTypeName(type.ofType);
  }
  if (isNonNullType(type)) {
    return getObjectTypeName(type.ofType);
  }
  if (isObjectType(type)) {
    return `"${type.name}"`;
  }
  if (isUnionType(type)) {
    return type
      .getTypes()
      .map(type => getObjectTypeName(type))
      .join(' | ');
  }
  return `"${type.name}"`;
}
Example #5
Source File: codeGeneration.ts    From amplify-codegen with Apache License 2.0 6 votes vote down vote up
/**
 * This exists only to properly generate types for union/interface typed fields that
 * do not have inline fragments. This currently can happen and the IR does give us
 * a set of fields per type condition unless fragments are used within the selection set.
 */
function getPossibleTypeNames(generator: CodeGenerator<LegacyCompilerContext>, property: Property) {
  const type = getNamedType(property.fieldType || property.type!);

  if (isUnionType(type) || isInterfaceType(type)) {
    return generator.context.schema.getPossibleTypes(type).map(type => type.name);
  }

  return [];
}
Example #6
Source File: renderRequestTypes.ts    From genql with MIT License 6 votes vote down vote up
renderRequestTypes = (
    schema: GraphQLSchema,
    ctx: RenderContext,
) => {
    let typeMap = schema.getTypeMap()

    if (ctx.config?.sortProperties) {
        typeMap = sortKeys(typeMap)
    }

    for (const name in typeMap) {
        if (excludedTypes.includes(name)) continue

        const type = typeMap[name]

        if (isObjectType(type) || isInterfaceType(type)) objectType(type, ctx)
        if (isInputObjectType(type)) inputObjectType(type, ctx)
        if (isUnionType(type)) unionType(type, ctx)
    }

    const aliases = [
        { type: schema.getQueryType(), name: 'QueryRequest' },
        { type: schema.getMutationType(), name: 'MutationRequest' },
        { type: schema.getSubscriptionType(), name: 'SubscriptionRequest' },
    ]
        .map(renderAlias)
        .filter(Boolean)
        .join('\n')

    ctx.addCodeBlock(aliases)
}
Example #7
Source File: renderResponseTypes.ts    From genql with MIT License 6 votes vote down vote up
renderResponseTypes = (
    schema: GraphQLSchema,
    ctx: RenderContext,
) => {
    let typeMap = schema.getTypeMap()
    if (ctx.config?.sortProperties) {
        typeMap = sortKeys(typeMap)
    }
    ctx.addCodeBlock(
        renderScalarTypes(
            ctx,
            Object.values(typeMap).filter((type): type is GraphQLScalarType =>
                isScalarType(type),
            ),
        ),
    )
    for (const name in typeMap) {
        if (excludedTypes.includes(name)) continue

        const type = typeMap[name]

        if (isEnumType(type)) enumType(type, ctx)
        if (isUnionType(type)) unionType(type, ctx)
        if (isObjectType(type)) objectType(type, ctx)
        if (isInterfaceType(type)) interfaceType(type, ctx)
    }

    const aliases = [
        { type: schema.getQueryType(), name: 'Query' },
        { type: schema.getMutationType(), name: 'Mutation' },
        { type: schema.getSubscriptionType(), name: 'Subscription' },
    ]
        .map(renderAlias)
        .filter(Boolean)
        .join('\n')
    ctx.addCodeBlock(aliases)
}
Example #8
Source File: renderTypeGuards.ts    From genql with MIT License 6 votes vote down vote up
renderTypeGuards = (
    schema: GraphQLSchema,
    ctx: RenderContext,
    isJs: 'ts' | 'esm' | 'cjs' = 'ts',
) => {
    const typeMap = schema.getTypeMap()
    for (const name in typeMap) {
        if (excludedTypes.includes(name)) continue

        const type = typeMap[name]

        if (isUnionType(type)) {
            const types = type.getTypes().map((t) => t.name)
            ctx.addCodeBlock(renderTypeGuard(type.name, types, isJs))
        } else if (isInterfaceType(type)) {
            const types = schema.getPossibleTypes(type).map((t) => t.name)
            ctx.addCodeBlock(renderTypeGuard(type.name, types, isJs))
        } else if (isObjectType(type)) {
            ctx.addCodeBlock(renderTypeGuard(type.name, [type.name], isJs))
        }
    }
}
Example #9
Source File: getFields.ts    From amplify-codegen with Apache License 2.0 5 votes vote down vote up
export default function getFields(
  field: GraphQLField<any, any>,
  schema: GraphQLSchema,
  depth: number = 2,
  options: GQLDocsGenOptions
): GQLTemplateField {
  const fieldType: GQLConcreteType = getType(field.type);
  const renderS3FieldFragment = options.useExternalFragmentForS3Object && isS3Object(fieldType);
  const subFields = !renderS3FieldFragment && (isObjectType(fieldType) || isInterfaceType(fieldType)) ? fieldType.getFields() : [];

  const subFragments: any = isInterfaceType(fieldType) || isUnionType(fieldType) ? schema.getPossibleTypes(fieldType) : {};

  if (depth < 1 && !(isScalarType(fieldType) || isEnumType(fieldType))) {
    return;
  }

  const fields: Array<GQLTemplateField> = Object.keys(subFields)
    .map(fieldName => {
      const subField = subFields[fieldName];
      return getFields(subField, schema, adjustDepth(subField, depth), options);
    })
    .filter(f => f);
  const fragments: Array<GQLTemplateFragment> = Object.keys(subFragments)
    .map(fragment => getFragment(subFragments[fragment], schema, depth, fields, null, false, options))
    .filter(f => f);

  // Special treatment for S3 input
  // Swift SDK needs S3 Object to have fragment
  if (renderS3FieldFragment) {
    fragments.push(getFragment(fieldType as GraphQLObjectType, schema, depth, [], 'S3Object', true, options));
  }

  // if the current field is an object and none of the subfields are included, don't include the field itself
  if (!(isScalarType(fieldType) || isEnumType(fieldType)) && fields.length === 0 && fragments.length === 0 && !renderS3FieldFragment) {
    return;
  }

  return {
    name: field.name,
    fields,
    fragments,
    hasBody: !!(fields.length || fragments.length),
  };
}
Example #10
Source File: objectType.ts    From genql with MIT License 5 votes vote down vote up
objectType = (
    type: GraphQLObjectType | GraphQLInterfaceType,
    ctx: RenderContext,
    wrapper: 'Promise' | 'Observable',
) => {
    // console.log(Object.keys(type.getFields()))
    const fieldsMap: GraphQLFieldMap<any, any> = ctx.config?.sortProperties
        ? sortKeys(type.getFields())
        : type.getFields()

    const fieldStrings = Object.keys(fieldsMap).map((fieldName) => {
        const field = fieldsMap[fieldName]
        const resolvedType = getNamedType(field.type)
        // leaf type, obly has.get() method
        const stopChain =
            isListType(field.type) ||
            (isNonNullType(field.type) && isListType(field.type.ofType)) ||
            isUnionType(resolvedType)
        // non leaf type, has .get method
        const resolvable = !(
            isEnumType(resolvedType) || isScalarType(resolvedType)
        )
        const argsPresent = field.args.length > 0
        const argsOptional = !field.args.find((a) => isNonNullType(a.type))
        const argsString = toArgsString(field)

        const executeReturnType = renderTyping(field.type, true, false, false)
        const executeReturnTypeWithTypeMap = renderTyping(
            field.type,
            true,
            false,
            false,
            (x: string) => `FieldsSelection<${x}, R>`,
        )

        //     get: <R extends RepositoryRequest>(
        //         request: R,
        //         defaultValue?: Repository,
        //     ) => Promise<FieldsSelection<Repository, R>>
        // }

        const getFnType = `{get: <R extends ${requestTypeName(
            resolvedType,
        )}>(request: R, defaultValue?: ${executeReturnTypeWithTypeMap}) => ${wrapper}<${executeReturnTypeWithTypeMap}>}`
        const fieldType = resolvable
            ? stopChain
                ? getFnType
                : `${chainTypeName(resolvedType, wrapper)} & ${getFnType}`
            : `{get: (request?: boolean|number, defaultValue?: ${executeReturnType}) => ${wrapper}<${executeReturnType}>}`

        const result: string[] = []

        if (argsPresent) {
            result.push(
                `((args${
                    argsOptional ? '?' : ''
                }: ${argsString}) => ${fieldType})`,
            )
        }

        if (!argsPresent || argsOptional) {
            result.push(`(${fieldType})`)
        }

        return `${fieldComment(field)}${field.name}: ${result.join('&')}`
    })

    ctx.addImport(RUNTIME_LIB_NAME, false, 'FieldsSelection', true, true)

    if (wrapper === 'Observable') {
        ctx.addImport(RUNTIME_LIB_NAME, false, 'Observable', true, true)
    }

    ctx.addCodeBlock(
        `${typeComment(type)}export interface ${chainTypeName(
            type,
            wrapper,
        )}{\n    ${fieldStrings.join(',\n    ')}\n}`,
    )
}
Example #11
Source File: renderTypeMap.ts    From genql with MIT License 5 votes vote down vote up
renderTypeMap = (schema: GraphQLSchema, ctx: RenderContext) => {
    // remove fields key,
    // remove the Type.type and Type.args, replace with [type, args]
    // reverse args.{name}
    // Args type is deduced and added only when the concrete type is different from type name, remove the scalar field and replace with a top level scalars array field.
    const result: TypeMap<string> = {
        scalars: [],
        types: {},
    }

    Object.keys(schema.getTypeMap())
        .filter((t) => !excludedTypes.includes(t))
        .map((t) => schema.getTypeMap()[t])
        .map((t) => {
            if (isObjectType(t) || isInterfaceType(t) || isInputObjectType(t))
                result.types[t.name] = objectType(t, ctx)
            else if (isUnionType(t)) result.types[t.name] = unionType(t, ctx)
            else if (isScalarType(t) || isEnumType(t)) {
                result.scalars.push(t.name)
                result.types[t.name] = {}
            }
        })

    // change names of query, mutation on schemas that chose different names (hasura)
    const q = schema.getQueryType()
    if (q?.name && q?.name !== 'Query') {
        delete result.types[q.name]
        result.types.Query = objectType(q, ctx)
        // result.Query.name = 'Query'
    }

    const m = schema.getMutationType()
    if (m?.name && m.name !== 'Mutation') {
        delete result.types[m.name]
        result.types.Mutation = objectType(m, ctx)
        // result.Mutation.name = 'Mutation'
    }

    const s = schema.getSubscriptionType()
    if (s?.name && s.name !== 'Subscription') {
        delete result.types[s.name]
        result.types.Subscription = objectType(s, ctx)
        // result.Subscription.name = 'Subscription'
    }

    ctx.addCodeBlock(
        JSON.stringify(replaceTypeNamesWithIndexes(result), null, 4),
    )
    


}
Example #12
Source File: addExecutionLogicToComposer.ts    From graphql-mesh with MIT License 4 votes vote down vote up
export async function addExecutionLogicToComposer(
  schemaComposer: SchemaComposer,
  {
    fetch: globalFetch,
    logger,
    operations,
    operationHeaders,
    baseUrl,
    pubsub: globalPubsub,
    queryParams,
  }: AddExecutionLogicToComposerOptions
) {
  logger.debug(`Attaching execution logic to the schema`);
  for (const operationConfig of operations) {
    const { httpMethod, rootTypeName, fieldName } = getOperationMetadata(operationConfig);
    const operationLogger = logger.child(`${rootTypeName}.${fieldName}`);

    const interpolationStrings: string[] = [
      ...Object.values(operationHeaders || {}),
      ...Object.values(queryParams || {}),
      baseUrl,
    ];

    const rootTypeComposer = schemaComposer[rootTypeName];

    const field = rootTypeComposer.getField(fieldName);

    if (isPubSubOperationConfig(operationConfig)) {
      field.description = operationConfig.description || `PubSub Topic: ${operationConfig.pubsubTopic}`;
      field.subscribe = (root, args, context, info) => {
        const pubsub = context?.pubsub || globalPubsub;
        if (!pubsub) {
          return new GraphQLError(`You should have PubSub defined in either the config or the context!`);
        }
        const interpolationData = { root, args, context, info, env: process.env };
        const pubsubTopic = stringInterpolator.parse(operationConfig.pubsubTopic, interpolationData);
        operationLogger.debug(`=> Subscribing to pubSubTopic: ${pubsubTopic}`);
        return pubsub.asyncIterator(pubsubTopic);
      };
      field.resolve = root => {
        operationLogger.debug('Received ', root, ' from ', operationConfig.pubsubTopic);
        return root;
      };
      interpolationStrings.push(operationConfig.pubsubTopic);
    } else if (operationConfig.path) {
      if (process.env.DEBUG) {
        field.description = `
    ***Original Description***: ${operationConfig.description || '(none)'}
    ***Method***: ${operationConfig.method}
    ***Base URL***: ${baseUrl}
    ***Path***: ${operationConfig.path}
`;
      } else {
        field.description = operationConfig.description;
      }
      field.resolve = async (root, args, context) => {
        operationLogger.debug(`=> Resolving`);
        const interpolationData = { root, args, context, env: process.env };
        const interpolatedBaseUrl = stringInterpolator.parse(baseUrl, interpolationData);
        const interpolatedPath = stringInterpolator.parse(operationConfig.path, interpolationData);
        let fullPath = urlJoin(interpolatedBaseUrl, interpolatedPath);
        const headers = {
          ...operationHeaders,
          ...operationConfig?.headers,
        };
        for (const headerName in headers) {
          headers[headerName] = stringInterpolator.parse(headers[headerName], interpolationData);
        }
        const requestInit: RequestInit = {
          method: httpMethod,
          headers,
        };
        if (queryParams) {
          const interpolatedQueryParams: Record<string, any> = {};
          for (const queryParamName in queryParams) {
            interpolatedQueryParams[queryParamName] = stringInterpolator.parse(
              queryParams[queryParamName],
              interpolationData
            );
          }
          const queryParamsString = qsStringify(interpolatedQueryParams, { indices: false });
          fullPath += fullPath.includes('?') ? '&' : '?';
          fullPath += queryParamsString;
        }
        // Handle binary data
        if ('binary' in operationConfig) {
          const binaryUpload = await args.input;
          if (isFileUpload(binaryUpload)) {
            const readable = binaryUpload.createReadStream();
            const chunks: number[] = [];
            for await (const chunk of readable) {
              for (const byte of chunk) {
                chunks.push(byte);
              }
            }
            requestInit.body = new Uint8Array(chunks);

            const [, contentType] = Object.entries(headers).find(([key]) => key.toLowerCase() === 'content-type') || [];
            if (!contentType) {
              headers['content-type'] = binaryUpload.mimetype;
            }
          }
          requestInit.body = binaryUpload;
        } else {
          if (operationConfig.requestBaseBody != null) {
            args.input = args.input || {};
            for (const key in operationConfig.requestBaseBody) {
              const configValue = operationConfig.requestBaseBody[key];
              if (typeof configValue === 'string') {
                const value = stringInterpolator.parse(configValue, interpolationData);
                lodashSet(args.input, key, value);
              } else {
                args.input[key] = configValue;
              }
            }
          }
          // Resolve union input
          const input = (args.input = resolveDataByUnionInputType(
            cleanObject(args.input),
            field.args?.input?.type?.getType(),
            schemaComposer
          ));
          if (input != null) {
            switch (httpMethod) {
              case 'GET':
              case 'HEAD':
              case 'CONNECT':
              case 'OPTIONS':
              case 'TRACE': {
                fullPath += fullPath.includes('?') ? '&' : '?';
                fullPath += qsStringify(input, { indices: false });
                break;
              }
              case 'POST':
              case 'PUT':
              case 'PATCH':
              case 'DELETE': {
                const [, contentType] =
                  Object.entries(headers).find(([key]) => key.toLowerCase() === 'content-type') || [];
                if (contentType?.startsWith('application/x-www-form-urlencoded')) {
                  requestInit.body = qsStringify(input, { indices: false });
                } else {
                  requestInit.body = JSON.stringify(input);
                }
                break;
              }
              default:
                return createError(`Unknown HTTP Method: ${httpMethod}`, {
                  url: fullPath,
                  method: httpMethod,
                });
            }
          }
        }

        // Delete unused queryparams
        const [actualPath, queryString] = fullPath.split('?');
        if (queryString) {
          const queryParams = qsParse(queryString);
          const cleanedQueryParams = cleanObject(queryParams);
          fullPath = actualPath + '?' + qsStringify(cleanedQueryParams, { indices: false });
        }

        operationLogger.debug(`=> Fetching `, fullPath, `=>`, requestInit);
        const fetch: typeof globalFetch = context?.fetch || globalFetch;
        if (!fetch) {
          return createError(`You should have fetch defined in either the config or the context!`, {
            url: fullPath,
            method: httpMethod,
          });
        }
        const response = await fetch(fullPath, requestInit);
        // If return type is a file
        if (field.type.getTypeName() === 'File') {
          return response.blob();
        }
        const responseText = await response.text();
        operationLogger.debug(`=> Received`, {
          headers: response.headers,
          text: responseText,
        });
        let responseJson: any;
        try {
          responseJson = JSON.parse(responseText);
        } catch (error) {
          const returnNamedGraphQLType = getNamedType(field.type.getType());
          // The result might be defined as scalar
          if (isScalarType(returnNamedGraphQLType)) {
            operationLogger.debug(` => Return type is not a JSON so returning ${responseText}`);
            return responseText;
          } else if (response.status === 204) {
            responseJson = {};
          } else {
            return createError(`Unexpected response`, {
              url: fullPath,
              method: httpMethod,
              responseText,
              error,
            });
          }
        }

        if (!response.status.toString().startsWith('2')) {
          const returnNamedGraphQLType = getNamedType(field.type.getType());
          if (!isUnionType(returnNamedGraphQLType)) {
            return createError(`HTTP Error: ${response.status}`, {
              url: fullPath,
              method: httpMethod,
              ...(response.statusText ? { status: response.statusText } : {}),
              responseJson,
            });
          }
        }

        operationLogger.debug(`Returning `, responseJson);
        // Sometimes API returns an array but the return type is not an array
        const isListReturnType = isListTypeOrNonNullListType(field.type.getType());
        const isArrayResponse = Array.isArray(responseJson);
        if (isListReturnType && !isArrayResponse) {
          operationLogger.debug(`Response is not array but return type is list. Normalizing the response`);
          responseJson = [responseJson];
        }
        if (!isListReturnType && isArrayResponse) {
          operationLogger.debug(`Response is array but return type is not list. Normalizing the response`);
          responseJson = responseJson[0];
        }

        const addResponseMetadata = (obj: any) => {
          return {
            ...obj,
            $url: fullPath,
            $method: httpMethod,
            $request: {
              query: {
                ...obj,
                ...args,
                ...args.input,
              },
              path: {
                ...obj,
                ...args,
              },
              header: requestInit.headers,
            },
            $response: {
              url: fullPath,
              method: httpMethod,
              status: response.status,
              statusText: response.statusText,
              body: obj,
            },
          };
        };
        operationLogger.debug(`Adding response metadata to the response object`);
        return Array.isArray(responseJson)
          ? responseJson.map(obj => addResponseMetadata(obj))
          : addResponseMetadata(responseJson);
      };
      interpolationStrings.push(...Object.values(operationConfig.headers || {}));
      interpolationStrings.push(operationConfig.path);

      if ('links' in operationConfig) {
        for (const linkName in operationConfig.links) {
          const linkObj = operationConfig.links[linkName];
          const typeTC = schemaComposer.getOTC(field.type.getTypeName());
          typeTC.addFields({
            [linkName]: () => {
              const targetField = schemaComposer.Query.getField(linkObj.fieldName);
              return {
                ...targetField,
                args: {},
                description: linkObj.description || targetField.description,
                resolve: (root, args, context, info) =>
                  linkResolver(linkObj.args, targetField.resolve, root, args, context, info),
              };
            },
          });
        }
      } else if ('responseByStatusCode' in operationConfig) {
        const unionOrSingleTC = schemaComposer.getAnyTC(getNamedType(field.type.getType()));
        const types = 'getTypes' in unionOrSingleTC ? unionOrSingleTC.getTypes() : [unionOrSingleTC];
        const statusCodeOneOfIndexMap =
          (unionOrSingleTC.getExtension('statusCodeOneOfIndexMap') as Record<string, number>) || {};
        for (const statusCode in operationConfig.responseByStatusCode) {
          const responseConfig = operationConfig.responseByStatusCode[statusCode];
          for (const linkName in responseConfig.links) {
            const typeTCThunked = types[statusCodeOneOfIndexMap[statusCode] || 0];
            const typeTC = schemaComposer.getOTC(typeTCThunked.getTypeName());
            typeTC.addFields({
              [linkName]: () => {
                const linkObj = responseConfig.links[linkName];
                const targetField = schemaComposer.Query.getField(linkObj.fieldName);
                return {
                  ...targetField,
                  args: {},
                  description: linkObj.description || targetField.description,
                  resolve: (root, args, context, info) =>
                    linkResolver(linkObj.args, targetField.resolve, root, args, context, info),
                };
              },
            });
          }
        }
      }
    }
    const { args: globalArgs } = parseInterpolationStrings(interpolationStrings, operationConfig.argTypeMap);
    rootTypeComposer.addFieldArgs(fieldName, globalArgs);
  }

  logger.debug(`Building the executable schema.`);
  return schemaComposer;
}