Skip to content

Commit 3daf4a8

Browse files
author
Nick Randall
committed
POC: allow users to get requested fields from context
This POC could solve #17
1 parent 2e23573 commit 3daf4a8

File tree

2 files changed

+42
-1
lines changed

2 files changed

+42
-1
lines changed

graphql.go

+9
Original file line numberDiff line numberDiff line change
@@ -140,3 +140,12 @@ func (s *Schema) ToJSON() ([]byte, error) {
140140
}
141141
return json.MarshalIndent(result, "", "\t")
142142
}
143+
144+
// GetFieldsFromContext can be used in resolvers to get the fields that were requested in the currenty query for the current type
145+
func GetFieldsFromContext(ctx context.Context) []string {
146+
fields, ok := ctx.Value(exec.GRAPHQL_FIELDS).([]string)
147+
if !ok {
148+
panic("Could not get graphql fields from context")
149+
}
150+
return fields
151+
}

internal/exec/exec.go

+33-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ const OpenTracingTagTrivial = "graphql.trivial"
2525
const OpenTracingTagArgsPrefix = "graphql.args."
2626
const OpenTracingTagError = "graphql.error"
2727

28+
type contextKey string
29+
30+
const GRAPHQL_FIELDS contextKey = "GRAPHQL_FIELD"
31+
2832
type Exec struct {
2933
queryExec iExec
3034
mutationExec iExec
@@ -494,12 +498,14 @@ func (e *objectExec) execSelectionSet(ctx context.Context, r *request, selSet *q
494498

495499
switch sel := sel.(type) {
496500
case *query.Field:
501+
var namedFields []string
497502
if skipByDirective(r, sel.Directives) {
498503
continue
499504
}
500505

506+
namedFields = resolveFieldNames("", namedFields, sel.SelSet, r.doc)
501507
execSel(func() {
502-
e.execField(ctx, r, sel, resolver, addResult)
508+
e.execField(context.WithValue(ctx, GRAPHQL_FIELDS, namedFields), r, sel, resolver, addResult)
503509
})
504510

505511
case *query.FragmentSpread:
@@ -533,6 +539,32 @@ func (e *objectExec) execSelectionSet(ctx context.Context, r *request, selSet *q
533539
wg.Wait()
534540
}
535541

542+
func resolveFieldNames(prefix string, namedFields []string, selSet *query.SelectionSet, doc *query.Document) []string {
543+
if selSet != nil {
544+
for _, selectionField := range selSet.Selections {
545+
switch selectionField := selectionField.(type) {
546+
case *query.Field:
547+
if selectionField.SelSet != nil {
548+
namedFields = resolveFieldNames(selectionField.Name+".", namedFields, selectionField.SelSet, doc)
549+
} else {
550+
namedFields = append(namedFields, prefix+selectionField.Name)
551+
}
552+
case *query.FragmentSpread:
553+
frag, ok := doc.Fragments[selectionField.Name]
554+
if !ok {
555+
panic(fmt.Errorf("fragment %q not found", selectionField.Name)) // TODO proper error handling
556+
}
557+
namedFields = resolveFieldNames(prefix, namedFields, frag.SelSet, doc)
558+
case *query.InlineFragment:
559+
namedFields = resolveFieldNames(prefix, namedFields, selectionField.SelSet, doc)
560+
default:
561+
panic("invalid type")
562+
}
563+
}
564+
}
565+
return namedFields
566+
}
567+
536568
func (e *objectExec) execField(ctx context.Context, r *request, f *query.Field, resolver reflect.Value, addResult addResultFn) {
537569
switch f.Name {
538570
case "__typename":

0 commit comments

Comments
 (0)