func collectFields()

in graphql/executable_schema.go [25:109]


func collectFields(reqCtx *OperationContext, selSet ast.SelectionSet, satisfies []string, visited map[string]bool) []CollectedField {
	groupedFields := make([]CollectedField, 0, len(selSet))

	for _, sel := range selSet {
		switch sel := sel.(type) {
		case *ast.Field:
			if !shouldIncludeNode(sel.Directives, reqCtx.Variables) {
				continue
			}
			f := getOrCreateAndAppendField(&groupedFields, sel.Name, sel.Alias, sel.ObjectDefinition, func() CollectedField {
				return CollectedField{Field: sel}
			})

			f.Selections = append(f.Selections, sel.SelectionSet...)

		case *ast.InlineFragment:
			// To allow simplified "collect all" types behavior, pass an empty list
			// of types that the type condition must satisfy: we will apply the
			// fragment regardless of type condition.
			//
			// When the type condition is not set (... { field }) we will apply the
			// fragment to any satisfying types.
			//
			// We will only NOT apply the fragment when we have at least one type in
			// the list we must satisfy and a type condition to compare them to.
			if len(satisfies) > 0 && sel.TypeCondition != "" && !instanceOf(sel.TypeCondition, satisfies) {
				continue
			}

			if !shouldIncludeNode(sel.Directives, reqCtx.Variables) {
				continue
			}
			shouldDefer, label := deferrable(sel.Directives, reqCtx.Variables)

			for _, childField := range collectFields(reqCtx, sel.SelectionSet, satisfies, visited) {
				f := getOrCreateAndAppendField(
					&groupedFields, childField.Name, childField.Alias, childField.ObjectDefinition,
					func() CollectedField { return childField })
				f.Selections = append(f.Selections, childField.Selections...)
				if shouldDefer {
					f.Deferrable = &Deferrable{
						Label: label,
					}
				}
			}

		case *ast.FragmentSpread:
			fragmentName := sel.Name
			if _, seen := visited[fragmentName]; seen {
				continue
			}
			visited[fragmentName] = true

			fragment := reqCtx.Doc.Fragments.ForName(fragmentName)
			if fragment == nil {
				// should never happen, validator has already run
				panic(fmt.Errorf("missing fragment %s", fragmentName))
			}

			if len(satisfies) > 0 && !instanceOf(fragment.TypeCondition, satisfies) {
				continue
			}

			if !shouldIncludeNode(sel.Directives, reqCtx.Variables) {
				continue
			}
			shouldDefer, label := deferrable(sel.Directives, reqCtx.Variables)

			for _, childField := range collectFields(reqCtx, fragment.SelectionSet, satisfies, visited) {
				f := getOrCreateAndAppendField(&groupedFields,
					childField.Name, childField.Alias, childField.ObjectDefinition,
					func() CollectedField { return childField })
				f.Selections = append(f.Selections, childField.Selections...)
				if shouldDefer {
					f.Deferrable = &Deferrable{Label: label}
				}
			}

		default:
			panic(fmt.Errorf("unsupported %T", sel))
		}
	}

	return groupedFields
}