github.com/99designs/gqlgen@v0.17.45/graphql/context_field.go (about) 1 package graphql 2 3 import ( 4 "context" 5 "time" 6 7 "github.com/vektah/gqlparser/v2/ast" 8 ) 9 10 type key string 11 12 const resolverCtx key = "resolver_context" 13 14 // Deprecated: Use FieldContext instead 15 type ResolverContext = FieldContext 16 17 type FieldContext struct { 18 Parent *FieldContext 19 // The name of the type this field belongs to 20 Object string 21 // These are the args after processing, they can be mutated in middleware to change what the resolver will get. 22 Args map[string]interface{} 23 // The raw field 24 Field CollectedField 25 // The index of array in path. 26 Index *int 27 // The result object of resolver 28 Result interface{} 29 // IsMethod indicates if the resolver is a method 30 IsMethod bool 31 // IsResolver indicates if the field has a user-specified resolver 32 IsResolver bool 33 // Child allows getting a child FieldContext by its field collection description. 34 // Note that, the returned child FieldContext represents the context as it was 35 // before the execution of the field resolver. For example: 36 // 37 // srv.AroundFields(func(ctx context.Context, next graphql.Resolver) (interface{}, error) { 38 // fc := graphql.GetFieldContext(ctx) 39 // op := graphql.GetOperationContext(ctx) 40 // collected := graphql.CollectFields(opCtx, fc.Field.Selections, []string{"User"}) 41 // 42 // child, err := fc.Child(ctx, collected[0]) 43 // if err != nil { 44 // return nil, err 45 // } 46 // fmt.Println("child context %q with args: %v", child.Field.Name, child.Args) 47 // 48 // return next(ctx) 49 // }) 50 // 51 Child func(context.Context, CollectedField) (*FieldContext, error) 52 } 53 54 type FieldStats struct { 55 // When field execution started 56 Started time.Time 57 58 // When argument marshaling finished 59 ArgumentsCompleted time.Time 60 61 // When the field completed running all middleware. Not available inside field middleware! 62 Completed time.Time 63 } 64 65 func (r *FieldContext) Path() ast.Path { 66 var path ast.Path 67 for it := r; it != nil; it = it.Parent { 68 if it.Index != nil { 69 path = append(path, ast.PathIndex(*it.Index)) 70 } else if it.Field.Field != nil { 71 path = append(path, ast.PathName(it.Field.Alias)) 72 } 73 } 74 75 // because we are walking up the chain, all the elements are backwards, do an inplace flip. 76 for i := len(path)/2 - 1; i >= 0; i-- { 77 opp := len(path) - 1 - i 78 path[i], path[opp] = path[opp], path[i] 79 } 80 81 return path 82 } 83 84 // Deprecated: Use GetFieldContext instead 85 func GetResolverContext(ctx context.Context) *ResolverContext { 86 return GetFieldContext(ctx) 87 } 88 89 func GetFieldContext(ctx context.Context) *FieldContext { 90 if val, ok := ctx.Value(resolverCtx).(*FieldContext); ok { 91 return val 92 } 93 return nil 94 } 95 96 func WithFieldContext(ctx context.Context, rc *FieldContext) context.Context { 97 rc.Parent = GetFieldContext(ctx) 98 return context.WithValue(ctx, resolverCtx, rc) 99 } 100 101 func equalPath(a ast.Path, b ast.Path) bool { 102 if len(a) != len(b) { 103 return false 104 } 105 106 for i := 0; i < len(a); i++ { 107 if a[i] != b[i] { 108 return false 109 } 110 } 111 112 return true 113 }