Skip to content

Commit d951837

Browse files
authored
Merge branch 'master' into lazy-invariant
2 parents b16d2fd + 77b1ae5 commit d951837

File tree

2 files changed

+69
-46
lines changed

2 files changed

+69
-46
lines changed

definition.go

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -365,9 +365,11 @@ type Object struct {
365365
PrivateDescription string `json:"description"`
366366
IsTypeOf IsTypeOfFn
367367

368-
typeConfig ObjectConfig
369-
fields FieldDefinitionMap
370-
interfaces []*Interface
368+
typeConfig ObjectConfig
369+
initialisedFields bool
370+
fields FieldDefinitionMap
371+
initialisedInterfaces bool
372+
interfaces []*Interface
371373
// Interim alternative to throwing an error during schema definition at run-time
372374
err error
373375
}
@@ -429,6 +431,7 @@ func (gt *Object) AddFieldConfig(fieldName string, fieldConfig *Field) {
429431
switch gt.typeConfig.Fields.(type) {
430432
case Fields:
431433
gt.typeConfig.Fields.(Fields)[fieldName] = fieldConfig
434+
gt.initialisedFields = false
432435
}
433436
}
434437
func (gt *Object) Name() string {
@@ -441,20 +444,30 @@ func (gt *Object) String() string {
441444
return gt.PrivateName
442445
}
443446
func (gt *Object) Fields() FieldDefinitionMap {
447+
if gt.initialisedFields {
448+
return gt.fields
449+
}
450+
444451
var configureFields Fields
445452
switch gt.typeConfig.Fields.(type) {
446453
case Fields:
447454
configureFields = gt.typeConfig.Fields.(Fields)
448455
case FieldsThunk:
449456
configureFields = gt.typeConfig.Fields.(FieldsThunk)()
450457
}
458+
451459
fields, err := defineFieldMap(gt, configureFields)
452460
gt.err = err
453461
gt.fields = fields
462+
gt.initialisedFields = true
454463
return gt.fields
455464
}
456465

457466
func (gt *Object) Interfaces() []*Interface {
467+
if gt.initialisedInterfaces {
468+
return gt.interfaces
469+
}
470+
458471
var configInterfaces []*Interface
459472
switch gt.typeConfig.Interfaces.(type) {
460473
case InterfacesThunk:
@@ -463,14 +476,18 @@ func (gt *Object) Interfaces() []*Interface {
463476
configInterfaces = gt.typeConfig.Interfaces.([]*Interface)
464477
case nil:
465478
default:
466-
gt.err = fmt.Errorf("Unknown Object.Interfaces type: %v", reflect.TypeOf(gt.typeConfig.Interfaces))
479+
gt.err = fmt.Errorf("Unknown Object.Interfaces type: %T", gt.typeConfig.Interfaces)
480+
gt.initialisedInterfaces = true
467481
return nil
468482
}
483+
469484
interfaces, err := defineInterfaces(gt, configInterfaces)
470485
gt.err = err
471486
gt.interfaces = interfaces
487+
gt.initialisedInterfaces = true
472488
return gt.interfaces
473489
}
490+
474491
func (gt *Object) Error() error {
475492
return gt.err
476493
}
@@ -507,15 +524,7 @@ func defineInterfaces(ttype *Object, interfaces []*Interface) ([]*Interface, err
507524
return ifaces, nil
508525
}
509526

510-
func defineFieldMap(ttype Named, fields interface{}) (FieldDefinitionMap, error) {
511-
var fieldMap Fields
512-
switch fields.(type) {
513-
case Fields:
514-
fieldMap = fields.(Fields)
515-
case FieldsThunk:
516-
fieldMap = fields.(FieldsThunk)()
517-
}
518-
527+
func defineFieldMap(ttype Named, fieldMap Fields) (FieldDefinitionMap, error) {
519528
resultFieldMap := FieldDefinitionMap{}
520529

521530
err := invariantf(
@@ -695,9 +704,10 @@ type Interface struct {
695704
PrivateDescription string `json:"description"`
696705
ResolveType ResolveTypeFn
697706

698-
typeConfig InterfaceConfig
699-
fields FieldDefinitionMap
700-
err error
707+
typeConfig InterfaceConfig
708+
initialisedFields bool
709+
fields FieldDefinitionMap
710+
err error
701711
}
702712
type InterfaceConfig struct {
703713
Name string `json:"name"`
@@ -751,30 +761,42 @@ func (it *Interface) AddFieldConfig(fieldName string, fieldConfig *Field) {
751761
switch it.typeConfig.Fields.(type) {
752762
case Fields:
753763
it.typeConfig.Fields.(Fields)[fieldName] = fieldConfig
764+
it.initialisedFields = false
754765
}
755766
}
767+
756768
func (it *Interface) Name() string {
757769
return it.PrivateName
758770
}
771+
759772
func (it *Interface) Description() string {
760773
return it.PrivateDescription
761774
}
775+
762776
func (it *Interface) Fields() (fields FieldDefinitionMap) {
777+
if it.initialisedFields {
778+
return it.fields
779+
}
780+
763781
var configureFields Fields
764782
switch it.typeConfig.Fields.(type) {
765783
case Fields:
766784
configureFields = it.typeConfig.Fields.(Fields)
767785
case FieldsThunk:
768786
configureFields = it.typeConfig.Fields.(FieldsThunk)()
769787
}
788+
770789
fields, err := defineFieldMap(it, configureFields)
771790
it.err = err
772791
it.fields = fields
792+
it.initialisedFields = true
773793
return it.fields
774794
}
795+
775796
func (it *Interface) String() string {
776797
return it.PrivateName
777798
}
799+
778800
func (it *Interface) Error() error {
779801
return it.err
780802
}

executor.go

Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ func Execute(p ExecuteParams) (result *Result) {
3535
go func(out chan<- *Result, done <-chan struct{}) {
3636
result := &Result{}
3737

38-
exeContext, err := buildExecutionContext(BuildExecutionCtxParams{
38+
exeContext, err := buildExecutionContext(buildExecutionCtxParams{
3939
Schema: p.Schema,
4040
Root: p.Root,
4141
AST: p.AST,
@@ -70,7 +70,7 @@ func Execute(p ExecuteParams) (result *Result) {
7070
}
7171
}()
7272

73-
result = executeOperation(ExecuteOperationParams{
73+
result = executeOperation(executeOperationParams{
7474
ExecutionContext: exeContext,
7575
Root: p.Root,
7676
Operation: exeContext.Operation,
@@ -92,7 +92,7 @@ func Execute(p ExecuteParams) (result *Result) {
9292
return
9393
}
9494

95-
type BuildExecutionCtxParams struct {
95+
type buildExecutionCtxParams struct {
9696
Schema Schema
9797
Root interface{}
9898
AST *ast.Document
@@ -102,7 +102,8 @@ type BuildExecutionCtxParams struct {
102102
Result *Result
103103
Context context.Context
104104
}
105-
type ExecutionContext struct {
105+
106+
type executionContext struct {
106107
Schema Schema
107108
Fragments map[string]ast.Definition
108109
Root interface{}
@@ -112,8 +113,8 @@ type ExecutionContext struct {
112113
Context context.Context
113114
}
114115

115-
func buildExecutionContext(p BuildExecutionCtxParams) (*ExecutionContext, error) {
116-
eCtx := &ExecutionContext{}
116+
func buildExecutionContext(p buildExecutionCtxParams) (*executionContext, error) {
117+
eCtx := &executionContext{}
117118
var operation *ast.OperationDefinition
118119
fragments := map[string]ast.Definition{}
119120

@@ -159,25 +160,25 @@ func buildExecutionContext(p BuildExecutionCtxParams) (*ExecutionContext, error)
159160
return eCtx, nil
160161
}
161162

162-
type ExecuteOperationParams struct {
163-
ExecutionContext *ExecutionContext
163+
type executeOperationParams struct {
164+
ExecutionContext *executionContext
164165
Root interface{}
165166
Operation ast.Definition
166167
}
167168

168-
func executeOperation(p ExecuteOperationParams) *Result {
169+
func executeOperation(p executeOperationParams) *Result {
169170
operationType, err := getOperationRootType(p.ExecutionContext.Schema, p.Operation)
170171
if err != nil {
171172
return &Result{Errors: gqlerrors.FormatErrors(err)}
172173
}
173174

174-
fields := collectFields(CollectFieldsParams{
175+
fields := collectFields(collectFieldsParams{
175176
ExeContext: p.ExecutionContext,
176177
RuntimeType: operationType,
177178
SelectionSet: p.Operation.GetSelectionSet(),
178179
})
179180

180-
executeFieldsParams := ExecuteFieldsParams{
181+
executeFieldsParams := executeFieldsParams{
181182
ExecutionContext: p.ExecutionContext,
182183
ParentType: operationType,
183184
Source: p.Root,
@@ -238,15 +239,15 @@ func getOperationRootType(schema Schema, operation ast.Definition) (*Object, err
238239
}
239240
}
240241

241-
type ExecuteFieldsParams struct {
242-
ExecutionContext *ExecutionContext
242+
type executeFieldsParams struct {
243+
ExecutionContext *executionContext
243244
ParentType *Object
244245
Source interface{}
245246
Fields map[string][]*ast.Field
246247
}
247248

248249
// Implements the "Evaluating selection sets" section of the spec for "write" mode.
249-
func executeFieldsSerially(p ExecuteFieldsParams) *Result {
250+
func executeFieldsSerially(p executeFieldsParams) *Result {
250251
if p.Source == nil {
251252
p.Source = map[string]interface{}{}
252253
}
@@ -270,7 +271,7 @@ func executeFieldsSerially(p ExecuteFieldsParams) *Result {
270271
}
271272

272273
// Implements the "Evaluating selection sets" section of the spec for "read" mode.
273-
func executeFields(p ExecuteFieldsParams) *Result {
274+
func executeFields(p executeFieldsParams) *Result {
274275
if p.Source == nil {
275276
p.Source = map[string]interface{}{}
276277
}
@@ -293,8 +294,8 @@ func executeFields(p ExecuteFieldsParams) *Result {
293294
}
294295
}
295296

296-
type CollectFieldsParams struct {
297-
ExeContext *ExecutionContext
297+
type collectFieldsParams struct {
298+
ExeContext *executionContext
298299
RuntimeType *Object // previously known as OperationType
299300
SelectionSet *ast.SelectionSet
300301
Fields map[string][]*ast.Field
@@ -306,7 +307,7 @@ type CollectFieldsParams struct {
306307
// CollectFields requires the "runtime type" of an object. For a field which
307308
// returns and Interface or Union type, the "runtime type" will be the actual
308309
// Object type returned by that field.
309-
func collectFields(p CollectFieldsParams) map[string][]*ast.Field {
310+
func collectFields(p collectFieldsParams) map[string][]*ast.Field {
310311

311312
fields := p.Fields
312313
if fields == nil {
@@ -335,7 +336,7 @@ func collectFields(p CollectFieldsParams) map[string][]*ast.Field {
335336
!doesFragmentConditionMatch(p.ExeContext, selection, p.RuntimeType) {
336337
continue
337338
}
338-
innerParams := CollectFieldsParams{
339+
innerParams := collectFieldsParams{
339340
ExeContext: p.ExeContext,
340341
RuntimeType: p.RuntimeType,
341342
SelectionSet: selection.SelectionSet,
@@ -362,7 +363,7 @@ func collectFields(p CollectFieldsParams) map[string][]*ast.Field {
362363
if !doesFragmentConditionMatch(p.ExeContext, fragment, p.RuntimeType) {
363364
continue
364365
}
365-
innerParams := CollectFieldsParams{
366+
innerParams := collectFieldsParams{
366367
ExeContext: p.ExeContext,
367368
RuntimeType: p.RuntimeType,
368369
SelectionSet: fragment.GetSelectionSet(),
@@ -378,7 +379,7 @@ func collectFields(p CollectFieldsParams) map[string][]*ast.Field {
378379

379380
// Determines if a field should be included based on the @include and @skip
380381
// directives, where @skip has higher precedence than @include.
381-
func shouldIncludeNode(eCtx *ExecutionContext, directives []*ast.Directive) bool {
382+
func shouldIncludeNode(eCtx *executionContext, directives []*ast.Directive) bool {
382383

383384
defaultReturnValue := true
384385

@@ -436,7 +437,7 @@ func shouldIncludeNode(eCtx *ExecutionContext, directives []*ast.Directive) bool
436437
}
437438

438439
// Determines if a fragment is applicable to the given type.
439-
func doesFragmentConditionMatch(eCtx *ExecutionContext, fragment ast.Node, ttype *Object) bool {
440+
func doesFragmentConditionMatch(eCtx *executionContext, fragment ast.Node, ttype *Object) bool {
440441

441442
switch fragment := fragment.(type) {
442443
case *ast.FragmentDefinition:
@@ -507,7 +508,7 @@ type resolveFieldResultState struct {
507508
// figures out the value that the field returns by calling its resolve function,
508509
// then calls completeValue to complete promises, serialize scalars, or execute
509510
// the sub-selection-set for objects.
510-
func resolveField(eCtx *ExecutionContext, parentType *Object, source interface{}, fieldASTs []*ast.Field) (result interface{}, resultState resolveFieldResultState) {
511+
func resolveField(eCtx *executionContext, parentType *Object, source interface{}, fieldASTs []*ast.Field) (result interface{}, resultState resolveFieldResultState) {
511512
// catch panic from resolveFn
512513
var returnType Output
513514
defer func() (interface{}, resolveFieldResultState) {
@@ -584,7 +585,7 @@ func resolveField(eCtx *ExecutionContext, parentType *Object, source interface{}
584585
return completed, resultState
585586
}
586587

587-
func completeValueCatchingError(eCtx *ExecutionContext, returnType Type, fieldASTs []*ast.Field, info ResolveInfo, result interface{}) (completed interface{}) {
588+
func completeValueCatchingError(eCtx *executionContext, returnType Type, fieldASTs []*ast.Field, info ResolveInfo, result interface{}) (completed interface{}) {
588589
// catch panic
589590
defer func() interface{} {
590591
if r := recover(); r != nil {
@@ -608,7 +609,7 @@ func completeValueCatchingError(eCtx *ExecutionContext, returnType Type, fieldAS
608609
return completed
609610
}
610611

611-
func completeValue(eCtx *ExecutionContext, returnType Type, fieldASTs []*ast.Field, info ResolveInfo, result interface{}) interface{} {
612+
func completeValue(eCtx *executionContext, returnType Type, fieldASTs []*ast.Field, info ResolveInfo, result interface{}) interface{} {
612613

613614
resultVal := reflect.ValueOf(result)
614615
if resultVal.IsValid() && resultVal.Type().Kind() == reflect.Func {
@@ -678,7 +679,7 @@ func completeValue(eCtx *ExecutionContext, returnType Type, fieldASTs []*ast.Fie
678679

679680
// completeAbstractValue completes value of an Abstract type (Union / Interface) by determining the runtime type
680681
// of that value, then completing based on that type.
681-
func completeAbstractValue(eCtx *ExecutionContext, returnType Abstract, fieldASTs []*ast.Field, info ResolveInfo, result interface{}) interface{} {
682+
func completeAbstractValue(eCtx *executionContext, returnType Abstract, fieldASTs []*ast.Field, info ResolveInfo, result interface{}) interface{} {
682683

683684
var runtimeType *Object
684685

@@ -715,7 +716,7 @@ func completeAbstractValue(eCtx *ExecutionContext, returnType Abstract, fieldAST
715716
}
716717

717718
// completeObjectValue complete an Object value by executing all sub-selections.
718-
func completeObjectValue(eCtx *ExecutionContext, returnType *Object, fieldASTs []*ast.Field, info ResolveInfo, result interface{}) interface{} {
719+
func completeObjectValue(eCtx *executionContext, returnType *Object, fieldASTs []*ast.Field, info ResolveInfo, result interface{}) interface{} {
719720

720721
// If there is an isTypeOf predicate function, call it with the
721722
// current result. If isTypeOf returns false, then raise an error rather
@@ -742,7 +743,7 @@ func completeObjectValue(eCtx *ExecutionContext, returnType *Object, fieldASTs [
742743
}
743744
selectionSet := fieldAST.SelectionSet
744745
if selectionSet != nil {
745-
innerParams := CollectFieldsParams{
746+
innerParams := collectFieldsParams{
746747
ExeContext: eCtx,
747748
RuntimeType: returnType,
748749
SelectionSet: selectionSet,
@@ -752,7 +753,7 @@ func completeObjectValue(eCtx *ExecutionContext, returnType *Object, fieldASTs [
752753
subFieldASTs = collectFields(innerParams)
753754
}
754755
}
755-
executeFieldsParams := ExecuteFieldsParams{
756+
executeFieldsParams := executeFieldsParams{
756757
ExecutionContext: eCtx,
757758
ParentType: returnType,
758759
Source: result,
@@ -774,7 +775,7 @@ func completeLeafValue(returnType Leaf, result interface{}) interface{} {
774775
}
775776

776777
// completeListValue complete a list value by completing each item in the list with the inner type
777-
func completeListValue(eCtx *ExecutionContext, returnType *List, fieldASTs []*ast.Field, info ResolveInfo, result interface{}) interface{} {
778+
func completeListValue(eCtx *executionContext, returnType *List, fieldASTs []*ast.Field, info ResolveInfo, result interface{}) interface{} {
778779
resultVal := reflect.ValueOf(result)
779780
parentTypeName := ""
780781
if info.ParentType != nil {

0 commit comments

Comments
 (0)