mirror of
https://github.com/stashapp/stash.git
synced 2025-12-06 16:34:02 +01:00
* Upgrade gqlgen to v0.17.2 This enables builds on Go 1.18. github.com/vektah/gqlparser is upgraded to the newest version too. Getting this to work is a bit of a hazzle. I had to first remove vendoring from the repository, perform the upgrade and then re-introduce the vendor directory. I think gqlgens analysis went wrong for some reason on the upgrade. It would seem a clean-room installation fixed it. * Bump project to 1.18 * Update all packages, address gqlgenc breaking changes * Let `go mod tidy` handle the go.mod file * Upgrade linter to 1.45.2 * Introduce v1.45.2 of the linter The linter now correctly warns on `strings.Title` because it isn't unicode-aware. Fix this by using the suggested fix from x/text/cases to produce unicode-aware strings. The mapping isn't entirely 1-1 as this new approach has a larger iface: it spans all of unicode rather than just ASCII. It coincides for ASCII however, so things should be largely the same. * Ready ourselves for errchkjson and contextcheck. * Revert dockerfile golang version changes for now Co-authored-by: Kermie <kermie@isinthe.house> Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
153 lines
3.4 KiB
Go
153 lines
3.4 KiB
Go
package graphql
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sync"
|
|
|
|
"github.com/vektah/gqlparser/v2/gqlerror"
|
|
)
|
|
|
|
type responseContext struct {
|
|
errorPresenter ErrorPresenterFunc
|
|
recover RecoverFunc
|
|
|
|
errors gqlerror.List
|
|
errorsMu sync.Mutex
|
|
|
|
extensions map[string]interface{}
|
|
extensionsMu sync.Mutex
|
|
}
|
|
|
|
const resultCtx key = "result_context"
|
|
|
|
func getResponseContext(ctx context.Context) *responseContext {
|
|
val, ok := ctx.Value(resultCtx).(*responseContext)
|
|
if !ok {
|
|
panic("missing response context")
|
|
}
|
|
return val
|
|
}
|
|
|
|
func WithResponseContext(ctx context.Context, presenterFunc ErrorPresenterFunc, recoverFunc RecoverFunc) context.Context {
|
|
return context.WithValue(ctx, resultCtx, &responseContext{
|
|
errorPresenter: presenterFunc,
|
|
recover: recoverFunc,
|
|
})
|
|
}
|
|
|
|
// AddErrorf writes a formatted error to the client, first passing it through the error presenter.
|
|
func AddErrorf(ctx context.Context, format string, args ...interface{}) {
|
|
AddError(ctx, fmt.Errorf(format, args...))
|
|
}
|
|
|
|
// AddError sends an error to the client, first passing it through the error presenter.
|
|
func AddError(ctx context.Context, err error) {
|
|
c := getResponseContext(ctx)
|
|
|
|
presentedError := c.errorPresenter(ctx, ErrorOnPath(ctx, err))
|
|
|
|
c.errorsMu.Lock()
|
|
defer c.errorsMu.Unlock()
|
|
c.errors = append(c.errors, presentedError)
|
|
}
|
|
|
|
func Recover(ctx context.Context, err interface{}) (userMessage error) {
|
|
c := getResponseContext(ctx)
|
|
return ErrorOnPath(ctx, c.recover(ctx, err))
|
|
}
|
|
|
|
// HasFieldError returns true if the given field has already errored
|
|
func HasFieldError(ctx context.Context, rctx *FieldContext) bool {
|
|
c := getResponseContext(ctx)
|
|
|
|
c.errorsMu.Lock()
|
|
defer c.errorsMu.Unlock()
|
|
|
|
if len(c.errors) == 0 {
|
|
return false
|
|
}
|
|
|
|
path := rctx.Path()
|
|
for _, err := range c.errors {
|
|
if equalPath(err.Path, path) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// GetFieldErrors returns a list of errors that occurred in the given field
|
|
func GetFieldErrors(ctx context.Context, rctx *FieldContext) gqlerror.List {
|
|
c := getResponseContext(ctx)
|
|
|
|
c.errorsMu.Lock()
|
|
defer c.errorsMu.Unlock()
|
|
|
|
if len(c.errors) == 0 {
|
|
return nil
|
|
}
|
|
|
|
path := rctx.Path()
|
|
var errs gqlerror.List
|
|
for _, err := range c.errors {
|
|
if equalPath(err.Path, path) {
|
|
errs = append(errs, err)
|
|
}
|
|
}
|
|
return errs
|
|
}
|
|
|
|
func GetErrors(ctx context.Context) gqlerror.List {
|
|
resCtx := getResponseContext(ctx)
|
|
resCtx.errorsMu.Lock()
|
|
defer resCtx.errorsMu.Unlock()
|
|
|
|
if len(resCtx.errors) == 0 {
|
|
return nil
|
|
}
|
|
|
|
errs := resCtx.errors
|
|
cpy := make(gqlerror.List, len(errs))
|
|
for i := range errs {
|
|
errCpy := *errs[i]
|
|
cpy[i] = &errCpy
|
|
}
|
|
return cpy
|
|
}
|
|
|
|
// RegisterExtension allows you to add a new extension into the graphql response
|
|
func RegisterExtension(ctx context.Context, key string, value interface{}) {
|
|
c := getResponseContext(ctx)
|
|
c.extensionsMu.Lock()
|
|
defer c.extensionsMu.Unlock()
|
|
|
|
if c.extensions == nil {
|
|
c.extensions = make(map[string]interface{})
|
|
}
|
|
|
|
if _, ok := c.extensions[key]; ok {
|
|
panic(fmt.Errorf("extension already registered for key %s", key))
|
|
}
|
|
|
|
c.extensions[key] = value
|
|
}
|
|
|
|
// GetExtensions returns any extensions registered in the current result context
|
|
func GetExtensions(ctx context.Context) map[string]interface{} {
|
|
ext := getResponseContext(ctx).extensions
|
|
if ext == nil {
|
|
return map[string]interface{}{}
|
|
}
|
|
|
|
return ext
|
|
}
|
|
|
|
func GetExtension(ctx context.Context, name string) interface{} {
|
|
ext := getResponseContext(ctx).extensions
|
|
if ext == nil {
|
|
return nil
|
|
}
|
|
|
|
return ext[name]
|
|
}
|