github.com/spread-ai/gqlgen@v0.0.0-20221124102857-a6c8ef538a1d/graphql/executor/extensions.go (about)

     1  package executor
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/spread-ai/gqlgen/graphql"
     8  )
     9  
    10  // Use adds the given extension to this Executor.
    11  func (e *Executor) Use(extension graphql.HandlerExtension) {
    12  	if err := extension.Validate(e.es); err != nil {
    13  		panic(err)
    14  	}
    15  
    16  	switch extension.(type) {
    17  	case graphql.OperationParameterMutator,
    18  		graphql.OperationContextMutator,
    19  		graphql.OperationInterceptor,
    20  		graphql.RootFieldInterceptor,
    21  		graphql.FieldInterceptor,
    22  		graphql.ResponseInterceptor:
    23  		e.extensions = append(e.extensions, extension)
    24  		e.ext = processExtensions(e.extensions)
    25  
    26  	default:
    27  		panic(fmt.Errorf("cannot Use %T as a gqlgen handler extension because it does not implement any extension hooks", extension))
    28  	}
    29  }
    30  
    31  // AroundFields is a convenience method for creating an extension that only implements field middleware
    32  func (e *Executor) AroundFields(f graphql.FieldMiddleware) {
    33  	e.Use(aroundFieldFunc(f))
    34  }
    35  
    36  // AroundRootFields is a convenience method for creating an extension that only implements root field middleware
    37  func (e *Executor) AroundRootFields(f graphql.RootFieldMiddleware) {
    38  	e.Use(aroundRootFieldFunc(f))
    39  }
    40  
    41  // AroundOperations is a convenience method for creating an extension that only implements operation middleware
    42  func (e *Executor) AroundOperations(f graphql.OperationMiddleware) {
    43  	e.Use(aroundOpFunc(f))
    44  }
    45  
    46  // AroundResponses is a convenience method for creating an extension that only implements response middleware
    47  func (e *Executor) AroundResponses(f graphql.ResponseMiddleware) {
    48  	e.Use(aroundRespFunc(f))
    49  }
    50  
    51  type extensions struct {
    52  	operationMiddleware        graphql.OperationMiddleware
    53  	responseMiddleware         graphql.ResponseMiddleware
    54  	rootFieldMiddleware        graphql.RootFieldMiddleware
    55  	fieldMiddleware            graphql.FieldMiddleware
    56  	operationParameterMutators []graphql.OperationParameterMutator
    57  	operationContextMutators   []graphql.OperationContextMutator
    58  }
    59  
    60  func processExtensions(exts []graphql.HandlerExtension) extensions {
    61  	e := extensions{
    62  		operationMiddleware: func(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler {
    63  			return next(ctx)
    64  		},
    65  		responseMiddleware: func(ctx context.Context, next graphql.ResponseHandler) *graphql.Response {
    66  			return next(ctx)
    67  		},
    68  		rootFieldMiddleware: func(ctx context.Context, next graphql.RootResolver) graphql.Marshaler {
    69  			return next(ctx)
    70  		},
    71  		fieldMiddleware: func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) {
    72  			return next(ctx)
    73  		},
    74  	}
    75  
    76  	// this loop goes backwards so the first extension is the outer most middleware and runs first.
    77  	for i := len(exts) - 1; i >= 0; i-- {
    78  		p := exts[i]
    79  		if p, ok := p.(graphql.OperationInterceptor); ok {
    80  			previous := e.operationMiddleware
    81  			e.operationMiddleware = func(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler {
    82  				return p.InterceptOperation(ctx, func(ctx context.Context) graphql.ResponseHandler {
    83  					return previous(ctx, next)
    84  				})
    85  			}
    86  		}
    87  
    88  		if p, ok := p.(graphql.ResponseInterceptor); ok {
    89  			previous := e.responseMiddleware
    90  			e.responseMiddleware = func(ctx context.Context, next graphql.ResponseHandler) *graphql.Response {
    91  				return p.InterceptResponse(ctx, func(ctx context.Context) *graphql.Response {
    92  					return previous(ctx, next)
    93  				})
    94  			}
    95  		}
    96  
    97  		if p, ok := p.(graphql.RootFieldInterceptor); ok {
    98  			previous := e.rootFieldMiddleware
    99  			e.rootFieldMiddleware = func(ctx context.Context, next graphql.RootResolver) graphql.Marshaler {
   100  				return p.InterceptRootField(ctx, func(ctx context.Context) graphql.Marshaler {
   101  					return previous(ctx, next)
   102  				})
   103  			}
   104  		}
   105  
   106  		if p, ok := p.(graphql.FieldInterceptor); ok {
   107  			previous := e.fieldMiddleware
   108  			e.fieldMiddleware = func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) {
   109  				return p.InterceptField(ctx, func(ctx context.Context) (res interface{}, err error) {
   110  					return previous(ctx, next)
   111  				})
   112  			}
   113  		}
   114  	}
   115  
   116  	for _, p := range exts {
   117  		if p, ok := p.(graphql.OperationParameterMutator); ok {
   118  			e.operationParameterMutators = append(e.operationParameterMutators, p)
   119  		}
   120  
   121  		if p, ok := p.(graphql.OperationContextMutator); ok {
   122  			e.operationContextMutators = append(e.operationContextMutators, p)
   123  		}
   124  	}
   125  
   126  	return e
   127  }
   128  
   129  type aroundOpFunc func(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler
   130  
   131  func (r aroundOpFunc) ExtensionName() string {
   132  	return "InlineOperationFunc"
   133  }
   134  
   135  func (r aroundOpFunc) Validate(schema graphql.ExecutableSchema) error {
   136  	if r == nil {
   137  		return fmt.Errorf("OperationFunc can not be nil")
   138  	}
   139  	return nil
   140  }
   141  
   142  func (r aroundOpFunc) InterceptOperation(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler {
   143  	return r(ctx, next)
   144  }
   145  
   146  type aroundRespFunc func(ctx context.Context, next graphql.ResponseHandler) *graphql.Response
   147  
   148  func (r aroundRespFunc) ExtensionName() string {
   149  	return "InlineResponseFunc"
   150  }
   151  
   152  func (r aroundRespFunc) Validate(schema graphql.ExecutableSchema) error {
   153  	if r == nil {
   154  		return fmt.Errorf("ResponseFunc can not be nil")
   155  	}
   156  	return nil
   157  }
   158  
   159  func (r aroundRespFunc) InterceptResponse(ctx context.Context, next graphql.ResponseHandler) *graphql.Response {
   160  	return r(ctx, next)
   161  }
   162  
   163  type aroundFieldFunc func(ctx context.Context, next graphql.Resolver) (res interface{}, err error)
   164  
   165  func (f aroundFieldFunc) ExtensionName() string {
   166  	return "InlineFieldFunc"
   167  }
   168  
   169  func (f aroundFieldFunc) Validate(schema graphql.ExecutableSchema) error {
   170  	if f == nil {
   171  		return fmt.Errorf("FieldFunc can not be nil")
   172  	}
   173  	return nil
   174  }
   175  
   176  func (f aroundFieldFunc) InterceptField(ctx context.Context, next graphql.Resolver) (res interface{}, err error) {
   177  	return f(ctx, next)
   178  }
   179  
   180  type aroundRootFieldFunc func(ctx context.Context, next graphql.RootResolver) graphql.Marshaler
   181  
   182  func (f aroundRootFieldFunc) ExtensionName() string {
   183  	return "InlineRootFieldFunc"
   184  }
   185  
   186  func (f aroundRootFieldFunc) Validate(schema graphql.ExecutableSchema) error {
   187  	if f == nil {
   188  		return fmt.Errorf("RootFieldFunc can not be nil")
   189  	}
   190  	return nil
   191  }
   192  
   193  func (f aroundRootFieldFunc) InterceptRootField(ctx context.Context, next graphql.RootResolver) graphql.Marshaler {
   194  	return f(ctx, next)
   195  }