github.com/spread-ai/gqlgen@v0.0.0-20221124102857-a6c8ef538a1d/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  }