graphql#SelectionNode TypeScript Examples

The following examples show how to use graphql#SelectionNode. 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: getTopAttributesFromQuery.ts    From jmix-frontend with Apache License 2.0 7 votes vote down vote up
/**
 * Parses the provided GraphQL query string and returns an array of top-level attributes.
 *
 * @param query
 */
export function getTopAttributesFromQuery(query: string): string[] {
  const documentNode = gql(query);

  if (!('selectionSet' in documentNode.definitions[0])) {
    throw new Error(`DocumentNode built from provided query string does not contain selectionSet. DocumentNode: ${JSON.stringify(documentNode)}`);
  }

  return documentNode
    .definitions[0]
    .selectionSet
    .selections
    .filter((node: SelectionNode) => 'name' in node)
    .map((node: SelectionNode) => {
      if ('name' in node) {
        return node.name.value;
      }
      // Should be unreachable due to .filter, this code is to avoid compilation error
      throw new Error(`Cannot find name in SelectionNode. DocumentNode: ${JSON.stringify(documentNode)}`);
    });
}
Example #2
Source File: CacheResultProcessor.ts    From apollo-cache-policies with Apache License 2.0 6 votes vote down vote up
private getFieldsForQuery(
    options: Cache.ReadOptions<any> | Cache.WriteOptions<any, any>
  ) {
    const operationDefinition = getOperationDefinition(options.query);
    const fragmentMap = createFragmentMap(
      getFragmentDefinitions(options.query)
    );

    return operationDefinition!.selectionSet.selections.reduce<SelectionNode[]>(
      (acc, selection) => {
        if (isField(selection)) {
          acc.push(selection);
          return acc;
        }

        const selections = getFragmentFromSelection(selection, fragmentMap)
          ?.selectionSet?.selections;

        if (selections) {
          acc.push(...selections);
        }

        return acc;
      },
      []
    ) as FieldNode[];
  }
Example #3
Source File: buildGqlQuery.ts    From ra-data-prisma with MIT License 6 votes vote down vote up
buildFieldsFromFragment = (
  fragment: DocumentNode | string,
  resourceName: string,
  fetchType: string,
): SelectionNode[] => {
  let parsedFragment = {};

  if (
    typeof fragment === "object" &&
    fragment.kind &&
    fragment.kind === "Document"
  ) {
    parsedFragment = fragment;
  }

  if (typeof fragment === "string") {
    if (!fragment.startsWith("fragment")) {
      fragment = `fragment tmp on ${resourceName} ${fragment}`;
    }

    try {
      parsedFragment = parse(fragment);
    } catch (e) {
      throw new Error(
        `Invalid fragment given for resource '${resourceName}' and fetchType '${fetchType}' (${e.message}).`,
      );
    }
  }

  return (parsedFragment as any).definitions?.[0].selectionSet.selections;
}
Example #4
Source File: index.ts    From amplify-codegen with Apache License 2.0 5 votes vote down vote up
function wrapInBooleanConditionsIfNeeded(
  selection: Selection | null,
  selectionNode: SelectionNode,
  possibleTypes: GraphQLObjectType[],
): Selection | null {
  if (!selection) return null;

  if (!selectionNode.directives) return selection;

  for (const directive of selectionNode.directives) {
    const directiveName = directive.name.value;

    if (directiveName === 'skip' || directiveName === 'include') {
      if (!directive.arguments) continue;

      const value = directive.arguments[0].value;

      switch (value.kind) {
        case 'BooleanValue':
          if (directiveName === 'skip') {
            return value.value ? null : selection;
          } else {
            return value.value ? selection : null;
          }
          break;
        case 'Variable':
          selection = {
            kind: 'BooleanCondition',
            variableName: value.name.value,
            inverted: directiveName === 'skip',
            selectionSet: {
              possibleTypes,
              selections: [selection],
            },
          };
          break;
      }
    }
  }

  return selection;
}
Example #5
Source File: gqlTypes.ts    From ra-data-prisma with MIT License 5 votes vote down vote up
selectionSet = (
  selections: SelectionNode[],
): SelectionSetNode => ({
  kind: Kind.SELECTION_SET,
  selections,
})
Example #6
Source File: generate-query.ts    From graphql-query-generator with MIT License 4 votes vote down vote up
function getSelectionSetAndVars(
  schema: GraphQLSchema,
  node: DefinitionNode,
  config: InternalConfiguration,
  depth: number = 0
): {
  selectionSet: SelectionSetNode
  variableDefinitionsMap: {
    [variableName: string]: VariableDefinitionNode
  }
  variableValues: {
    [variableName: string]: any
  }
} {
  let selections: SelectionNode[] = []
  let variableDefinitionsMap: {
    [variableName: string]: VariableDefinitionNode
  } = {}
  let variableValues: { [variableName: string]: any } = {}

  // Abort at leaf nodes:
  if (depth === config.maxDepth) {
    return {
      selectionSet: undefined,
      variableDefinitionsMap,
      variableValues
    }
  }

  if (node.kind === Kind.OBJECT_TYPE_DEFINITION) {
    let fields = getRandomFields(node.fields, config, schema, depth)

    fields.forEach((field) => {
      // Recurse, if field has children:
      const nextNode = schema.getType(getTypeName(field.type)).astNode
      let selectionSet: SelectionSetNode = undefined
      if (typeof nextNode !== 'undefined') {
        const res = getSelectionSetAndVars(schema, nextNode, config, depth + 1)

        // Update counts and nodeFactor:
        config.resolveCount += config.nodeFactor
        config.nodeFactor *= getNextNodefactor(res.variableValues)
        config.typeCount += config.nodeFactor

        selectionSet = res.selectionSet
        variableDefinitionsMap = {
          ...variableDefinitionsMap,
          ...res.variableDefinitionsMap
        }
        variableValues = { ...variableValues, ...res.variableValues }
      }

      const avs = getArgsAndVars(
        field,
        node.name.value,
        config,
        schema,
        variableValues
      )
      variableDefinitionsMap = {
        ...variableDefinitionsMap,
        ...avs.variableDefinitionsMap
      }
      variableValues = { ...variableValues, ...avs.variableValues }

      selections.push({
        kind: Kind.FIELD,
        name: getName(field.name.value),
        selectionSet,
        arguments: avs.args
      })
    })
  } else if (node.kind === Kind.INTERFACE_TYPE_DEFINITION) {
    let fields = getRandomFields(node.fields, config, schema, depth)

    fields.forEach((field) => {
      // Recurse, if field has children:
      const nextNode = schema.getType(getTypeName(field.type)).astNode
      let selectionSet: SelectionSetNode = undefined
      if (typeof nextNode !== 'undefined') {
        const res = getSelectionSetAndVars(schema, nextNode, config, depth + 1)

        // Update counts and nodeFactor:
        config.resolveCount += config.nodeFactor
        config.nodeFactor *= getNextNodefactor(res.variableValues)
        config.typeCount += config.nodeFactor

        selectionSet = res.selectionSet
        variableDefinitionsMap = {
          ...variableDefinitionsMap,
          ...res.variableDefinitionsMap
        }
        variableValues = { ...variableValues, ...res.variableValues }
      }

      const avs = getArgsAndVars(
        field,
        node.name.value,
        config,
        schema,
        variableValues
      )
      variableDefinitionsMap = {
        ...variableDefinitionsMap,
        ...avs.variableDefinitionsMap
      }
      variableValues = { ...variableValues, ...avs.variableValues }

      selections.push({
        kind: Kind.FIELD,
        name: getName(field.name.value),
        selectionSet,
        arguments: avs.args
      })
    })

    // Get all objects that implement an interface
    let objectsImplementingInterface = Object.values(
      schema.getTypeMap()
    ).filter((namedType) => {
      if (
        namedType.astNode &&
        namedType.astNode.kind === 'ObjectTypeDefinition'
      ) {
        let interfaceNames = namedType.astNode.interfaces.map(
          (interfaceNamedType) => {
            return interfaceNamedType.name.value
          }
        )

        if (interfaceNames.includes(node.name.value)) {
          return true
        }
      }

      return false
    })

    // Randomly select named types from the union
    let pickObjectsImplementingInterface = objectsImplementingInterface.filter(
      () => {
        if (typeof config.breadthProbability === 'number') {
          return random(config) <= config.breadthProbability
        } else {
          return random(config) <= config.breadthProbability(depth)
        }
      }
    )

    // If no named types are selected, select any one
    if (pickObjectsImplementingInterface.length === 0) {
      const forcedCleanIndex = Math.floor(
        random(config) * objectsImplementingInterface.length
      )
      pickObjectsImplementingInterface.push(
        objectsImplementingInterface[forcedCleanIndex]
      )
    }

    pickObjectsImplementingInterface.forEach((namedType) => {
      if (namedType.astNode) {
        let type = namedType.astNode

        // Unions can only contain objects
        if (type.kind === Kind.OBJECT_TYPE_DEFINITION) {
          // Get selections
          let selectionSet: SelectionSetNode = undefined
          const res = getSelectionSetAndVars(schema, type, config, depth)
          selectionSet = res.selectionSet
          variableDefinitionsMap = {
            ...variableDefinitionsMap,
            ...res.variableDefinitionsMap
          }
          variableValues = { ...variableValues, ...res.variableValues }

          let fragment: InlineFragmentNode = {
            kind: Kind.INLINE_FRAGMENT,
            typeCondition: {
              kind: Kind.NAMED_TYPE,
              name: {
                kind: Kind.NAME,
                value: type.name.value
              }
            },
            selectionSet: selectionSet
          }

          selections.push(fragment)
        } else {
          throw Error(
            `There should only be object types ` +
              `in the selectionSet but found: ` +
              `"${JSON.stringify(type, null, 2)}"`
          )
        }
      } else {
        selections.push({
          kind: Kind.FIELD,
          name: {
            kind: Kind.NAME,
            value: namedType.name
          }
        })
      }
    })
  } else if (node.kind === Kind.UNION_TYPE_DEFINITION) {
    // Get the named types in the union
    let unionNamedTypes = node.types.map((namedTypeNode) => {
      return schema.getType(namedTypeNode.name.value)
    })

    // Randomly select named types from the union
    let pickUnionNamedTypes = unionNamedTypes.filter(() => {
      if (typeof config.breadthProbability === 'number') {
        return random(config) <= config.breadthProbability
      } else {
        return random(config) <= config.breadthProbability(depth)
      }
    })

    // If no named types are selected, select any one
    if (pickUnionNamedTypes.length === 0) {
      const forcedCleanIndex = Math.floor(
        random(config) * unionNamedTypes.length
      )
      pickUnionNamedTypes.push(unionNamedTypes[forcedCleanIndex])
    }

    pickUnionNamedTypes.forEach((namedType) => {
      if (namedType.astNode) {
        let type = namedType.astNode

        // Unions can only contain objects
        if (type.kind === Kind.OBJECT_TYPE_DEFINITION) {
          // Get selections
          let selectionSet: SelectionSetNode = undefined
          const res = getSelectionSetAndVars(schema, type, config, depth)
          selectionSet = res.selectionSet
          variableDefinitionsMap = {
            ...variableDefinitionsMap,
            ...res.variableDefinitionsMap
          }
          variableValues = { ...variableValues, ...res.variableValues }

          let fragment: InlineFragmentNode = {
            kind: Kind.INLINE_FRAGMENT,
            typeCondition: {
              kind: Kind.NAMED_TYPE,
              name: {
                kind: Kind.NAME,
                value: type.name.value
              }
            },
            selectionSet: selectionSet
          }

          selections.push(fragment)
        } else {
          throw Error(
            `There should only be object types ` +
              `in the selectionSet but found: ` +
              `"${JSON.stringify(type, null, 2)}"`
          )
        }
      } else {
        selections.push({
          kind: Kind.FIELD,
          name: {
            kind: Kind.NAME,
            value: namedType.name
          }
        })
      }
    })
  }

  let aliasIndexes: { [fieldName: string]: number } = {}
  let cleanselections: SelectionNode[] = []

  // Ensure unique field names/aliases
  selections.forEach((selectionNode) => {
    if (selectionNode.kind === Kind.FIELD) {
      let fieldName = selectionNode.name.value
      if (fieldName in aliasIndexes) {
        cleanselections.push({
          ...selectionNode,
          ...{
            alias: {
              kind: Kind.NAME,
              value: `${fieldName}${aliasIndexes[fieldName]++}`
            }
          }
        })
      } else {
        aliasIndexes[fieldName] = 2
        cleanselections.push(selectionNode)
      }
    } else if (selectionNode.kind === Kind.INLINE_FRAGMENT) {
      let cleanFragmentSelections: SelectionNode[] = []
      selectionNode.selectionSet.selections.forEach((fragmentSelectionNode) => {
        if (fragmentSelectionNode.kind === Kind.FIELD) {
          let fieldName = fragmentSelectionNode.name.value
          if (fieldName in aliasIndexes) {
            cleanFragmentSelections.push({
              ...fragmentSelectionNode,
              ...{
                alias: {
                  kind: Kind.NAME,
                  value: `${fieldName}${aliasIndexes[fieldName]++}`
                }
              }
            })
          } else {
            aliasIndexes[fieldName] = 2
            cleanFragmentSelections.push(fragmentSelectionNode)
          }
        }
      })

      selectionNode.selectionSet.selections = cleanFragmentSelections
      cleanselections.push(selectionNode)
    } else {
      throw Error(
        `There should not be any fragment spreads in the selectionNode "${JSON.stringify(
          selectionNode,
          null,
          2
        )}"`
      )
    }
  })

  return {
    selectionSet:
      cleanselections.length > 0
        ? {
            kind: Kind.SELECTION_SET,
            selections: cleanselections
          }
        : undefined,
    variableDefinitionsMap,
    variableValues
  }
}
Example #7
Source File: index.ts    From graphql-mesh with MIT License 4 votes vote down vote up
async getMeshSource(): Promise<MeshSource> {
    if ('sources' in this.config) {
      if (this.config.strategy === 'race') {
        const schemaPromises: Promise<GraphQLSchema>[] = [];

        const executorPromises: Promise<MeshSource['executor']>[] = [];
        let batch = true;
        for (const httpSourceConfig of this.config.sources) {
          if (httpSourceConfig.batch === false) {
            batch = false;
          }
          schemaPromises.push(this.getNonExecutableSchemaForHTTPSource(httpSourceConfig));
          executorPromises.push(this.getExecutorForHTTPSourceConfig(httpSourceConfig));
        }

        const [schema, ...executors] = await Promise.all([Promise.race(schemaPromises), ...executorPromises]);

        const executor = this.getRaceExecutor(executors);

        return {
          schema,
          executor,
          batch,
        };
      } else if (this.config.strategy === 'highestValue') {
        if (this.config.strategyConfig == null) {
          throw new Error(`You must configure 'highestValue' strategy`);
        }
        let schema: GraphQLSchema;
        const executorPromises: Promise<MeshSource['executor']>[] = [];
        let error: Error;
        for (const httpSourceConfig of this.config.sources) {
          executorPromises.push(this.getExecutorForHTTPSourceConfig(httpSourceConfig));
          if (schema == null) {
            try {
              schema = await this.getNonExecutableSchemaForHTTPSource(httpSourceConfig);
            } catch (e) {
              error = e;
            }
          }
        }
        if (schema == null) {
          throw error;
        }

        const executors = await Promise.all(executorPromises);
        const parsedSelectionSet = parseSelectionSet(this.config.strategyConfig.selectionSet);
        const valuePath = this.config.strategyConfig.value;
        const highestValueExecutor = async function highestValueExecutor(executionRequest: ExecutionRequest) {
          const operationAST = getOperationASTFromRequest(executionRequest);
          (operationAST.selectionSet.selections as SelectionNode[]).push(...parsedSelectionSet.selections);
          const results = await Promise.all(executors.map(executor => executor(executionRequest)));
          let highestValue = -Infinity;
          let resultWithHighestResult = results[0];
          for (const result of results) {
            if (isAsyncIterable(result)) {
              console.warn('Incremental delivery is not supported currently');
              return result;
            } else if (result.data != null) {
              const currentValue = lodashGet(result.data, valuePath);
              if (currentValue > highestValue) {
                resultWithHighestResult = result;
                highestValue = currentValue;
              }
            }
          }
          return resultWithHighestResult;
        };

        return {
          schema,
          executor: highestValueExecutor,
          // Batching doesn't make sense with fallback strategy
          batch: false,
        };
      } else {
        let schema: GraphQLSchema;
        const executorPromises: Promise<MeshSource['executor']>[] = [];
        let error: Error;
        for (const httpSourceConfig of this.config.sources) {
          executorPromises.push(this.getExecutorForHTTPSourceConfig(httpSourceConfig));
          if (schema == null) {
            try {
              schema = await this.getNonExecutableSchemaForHTTPSource(httpSourceConfig);
            } catch (e) {
              error = e;
            }
          }
        }
        if (schema == null) {
          throw error;
        }

        const executors = await Promise.all(executorPromises);
        const executor = this.getFallbackExecutor(executors);

        return {
          schema,
          executor,
          // Batching doesn't make sense with fallback strategy
          batch: false,
        };
      }
    } else if ('endpoint' in this.config) {
      const [schemaResult, executorResult] = await Promise.allSettled([
        this.getNonExecutableSchemaForHTTPSource(this.config),
        this.getExecutorForHTTPSourceConfig(this.config),
      ]);
      if (schemaResult.status === 'rejected') {
        throw new Error(
          `Failed to fetch introspection from ${this.config.endpoint}: ${util.inspect(schemaResult.reason)}`
        );
      }
      if (executorResult.status === 'rejected') {
        throw new Error(
          `Failed to create executor for ${this.config.endpoint}: ${util.inspect(executorResult.reason)}`
        );
      }
      return {
        schema: schemaResult.value,
        executor: executorResult.value,
        batch: this.config.batch != null ? this.config.batch : true,
      };
    } else if ('schema' in this.config) {
      return this.getCodeFirstSource(this.config);
    }

    throw new Error(`Unexpected config: ${util.inspect(this.config)}`);
  }
Example #8
Source File: index.ts    From amplify-codegen with Apache License 2.0 4 votes vote down vote up
compileSelection(
    selectionNode: SelectionNode,
    parentType: GraphQLCompositeType,
    possibleTypes: GraphQLObjectType[],
    visitedFragments: Set<string>,
  ): Selection | null {
    switch (selectionNode.kind) {
      case Kind.FIELD: {
        const name = selectionNode.name.value;
        const alias = selectionNode.alias ? selectionNode.alias.value : undefined;

        const fieldDef = getFieldDef(this.schema, parentType, selectionNode);
        if (!fieldDef) {
          throw new GraphQLError(`Cannot query field "${name}" on type "${String(parentType)}"`, [selectionNode]);
        }

        const fieldType = fieldDef.type;
        const unmodifiedFieldType = getNamedType(fieldType);

        this.addTypeUsed(unmodifiedFieldType);

        const { description, isDeprecated, deprecationReason } = fieldDef;

        const responseKey = alias || name;

        const args =
          selectionNode.arguments && selectionNode.arguments.length > 0
            ? selectionNode.arguments.map(arg => {
                const name = arg.name.value;
                const argDef = fieldDef.args.find(argDef => argDef.name === arg.name.value);
                return {
                  name,
                  value: valueFromValueNode(arg.value),
                  type: (argDef && argDef.type) || undefined,
                };
              })
            : undefined;

        let field: Field = {
          kind: 'Field',
          responseKey,
          name,
          alias,
          args,
          type: fieldType,
          description: !isMetaFieldName(name) && description ? description : undefined,
          isDeprecated,
          deprecationReason: deprecationReason || undefined,
        };

        if (isCompositeType(unmodifiedFieldType)) {
          const selectionSetNode = selectionNode.selectionSet;
          if (!selectionSetNode) {
            throw new GraphQLError(`Composite field "${name}" on type "${String(parentType)}" requires selection set`, [selectionNode]);
          }

          field.selectionSet = this.compileSelectionSet(selectionNode.selectionSet as SelectionSetNode, unmodifiedFieldType);
        }
        return field;
      }
      case Kind.INLINE_FRAGMENT: {
        const typeNode = selectionNode.typeCondition;
        const type = typeNode ? (typeFromAST(this.schema, typeNode) as GraphQLCompositeType) : parentType;
        const possibleTypesForTypeCondition = this.possibleTypesForType(type).filter(type => possibleTypes.includes(type));
        return {
          kind: 'TypeCondition',
          type,
          selectionSet: this.compileSelectionSet(selectionNode.selectionSet, type, possibleTypesForTypeCondition),
        };
      }
      case Kind.FRAGMENT_SPREAD: {
        const fragmentName = selectionNode.name.value;
        if (visitedFragments.has(fragmentName)) return null;
        visitedFragments.add(fragmentName);

        const fragmentSpread: FragmentSpread = {
          kind: 'FragmentSpread',
          fragmentName,
          selectionSet: {
            possibleTypes,
            selections: [],
          },
        };
        this.unresolvedFragmentSpreads.push(fragmentSpread);
        return fragmentSpread;
      }
    }
  }