1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
|
package graphql
import (
"context"
"sort"
"github.com/graph-gophers/graphql-go/internal/exec/selections"
)
// SelectedFieldNames returns the set of selected field paths underneath the
// current resolver. Paths are dot-delimited for nested structures (e.g. "products",
// "products.id", "products.category.id"). Immediate child field names are always
// present (even when they have further children). Order preserves the first
// appearance in the query after fragment flattening, performing a depth-first
// traversal.
// It returns an empty slice when the current field's return type is a leaf
// (scalar / enum) or when DisableFieldSelections was used at schema creation.
// The returned slice is a copy safe for caller modification.
//
// Notes:
// - Fragment spreads & inline fragments are flattened.
// - Field aliases are ignored; original schema field names are used.
// - Meta fields beginning with "__" (including __typename) are excluded.
// - Duplicate paths are removed, preserving the earliest occurrence.
func SelectedFieldNames(ctx context.Context) []string {
// If no selection info is present (leaf field or no child selections), return empty slice.
lazy := selections.FromContext(ctx)
if lazy == nil {
return []string{}
}
return lazy.Names()
}
// HasSelectedField returns true if the child selection list contains the provided
// (possibly nested) path (case sensitive). It returns false for leaf resolvers
// and when DisableFieldSelections was used.
func HasSelectedField(ctx context.Context, name string) bool {
lazy := selections.FromContext(ctx)
if lazy == nil {
return false
}
return lazy.Has(name)
}
// SortedSelectedFieldNames returns the same data as SelectedFieldNames but
// sorted lexicographically for deterministic ordering scenarios (e.g. cache
// key generation). It will also return an empty slice when selections are
// disabled.
func SortedSelectedFieldNames(ctx context.Context) []string {
names := SelectedFieldNames(ctx)
if len(names) <= 1 {
return names
}
out := make([]string, len(names))
copy(out, names)
sort.Strings(out)
return out
}
// DecodeSelectedFieldArgs decodes the argument map for the given path into dst.
// It returns ok=false if the path or its arguments are absent. Results are cached per
// (path, concrete struct type) to avoid repeated reflection cost; repeated successful decodes
// copy a previously cached value into dst.
//
// Example:
//
// type BooksArgs struct { Top int32 }
// var args BooksArgs
// ok, err := graphql.DecodeSelectedFieldArgs(ctx, "books", &args)
// if ok { /* use args.Top */ }
func DecodeSelectedFieldArgs(ctx context.Context, path string, dst interface{}) (bool, error) {
if dst == nil {
return false, nil
}
lazy := selections.FromContext(ctx)
if lazy == nil {
return false, nil
}
return lazy.DecodeArgsInto(path, dst)
}
|