Skip to content

Commit ccd7f68

Browse files
author
Sebastian Friedel
committed
Improve performance by not eagerly formatting error messages for invariants
1 parent 491504a commit ccd7f68

File tree

4 files changed

+77
-75
lines changed

4 files changed

+77
-75
lines changed

definition.go

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -266,20 +266,20 @@ func NewScalar(config ScalarConfig) *Scalar {
266266
st.PrivateName = config.Name
267267
st.PrivateDescription = config.Description
268268

269-
err = invariant(
269+
err = invariantf(
270270
config.Serialize != nil,
271-
fmt.Sprintf(`%v must provide "serialize" function. If this custom Scalar is `+
271+
`%v must provide "serialize" function. If this custom Scalar is `+
272272
`also used as an input type, ensure "parseValue" and "parseLiteral" `+
273-
`functions are also provided.`, st),
273+
`functions are also provided.`, st,
274274
)
275275
if err != nil {
276276
st.err = err
277277
return st
278278
}
279279
if config.ParseValue != nil || config.ParseLiteral != nil {
280-
err = invariant(
280+
err = invariantf(
281281
config.ParseValue != nil && config.ParseLiteral != nil,
282-
fmt.Sprintf(`%v must provide both "parseValue" and "parseLiteral" functions.`, st),
282+
`%v must provide both "parseValue" and "parseLiteral" functions.`, st,
283283
)
284284
if err != nil {
285285
st.err = err
@@ -478,20 +478,20 @@ func defineInterfaces(ttype *Object, interfaces []*Interface) ([]*Interface, err
478478
return ifaces, nil
479479
}
480480
for _, iface := range interfaces {
481-
err := invariant(
481+
err := invariantf(
482482
iface != nil,
483-
fmt.Sprintf(`%v may only implement Interface types, it cannot implement: %v.`, ttype, iface),
483+
`%v may only implement Interface types, it cannot implement: %v.`, ttype, iface,
484484
)
485485
if err != nil {
486486
return ifaces, err
487487
}
488488
if iface.ResolveType != nil {
489-
err = invariant(
489+
err = invariantf(
490490
iface.ResolveType != nil,
491-
fmt.Sprintf(`Interface Type %v does not provide a "resolveType" function `+
491+
`Interface Type %v does not provide a "resolveType" function `+
492492
`and implementing Type %v does not provide a "isTypeOf" `+
493493
`function. There is no way to resolve this implementing type `+
494-
`during execution.`, iface, ttype),
494+
`during execution.`, iface, ttype,
495495
)
496496
if err != nil {
497497
return ifaces, err
@@ -507,9 +507,9 @@ func defineFieldMap(ttype Named, fields Fields) (FieldDefinitionMap, error) {
507507

508508
resultFieldMap := FieldDefinitionMap{}
509509

510-
err := invariant(
510+
err := invariantf(
511511
len(fields) > 0,
512-
fmt.Sprintf(`%v fields must be an object with field names as keys or a function which return such an object.`, ttype),
512+
`%v fields must be an object with field names as keys or a function which return such an object.`, ttype,
513513
)
514514
if err != nil {
515515
return resultFieldMap, err
@@ -519,9 +519,9 @@ func defineFieldMap(ttype Named, fields Fields) (FieldDefinitionMap, error) {
519519
if field == nil {
520520
continue
521521
}
522-
err = invariant(
522+
err = invariantf(
523523
field.Type != nil,
524-
fmt.Sprintf(`%v.%v field type must be Output Type but got: %v.`, ttype, fieldName, field.Type),
524+
`%v.%v field type must be Output Type but got: %v.`, ttype, fieldName, field.Type,
525525
)
526526
if err != nil {
527527
return resultFieldMap, err
@@ -547,16 +547,16 @@ func defineFieldMap(ttype Named, fields Fields) (FieldDefinitionMap, error) {
547547
if err != nil {
548548
return resultFieldMap, err
549549
}
550-
err = invariant(
550+
err = invariantf(
551551
arg != nil,
552-
fmt.Sprintf(`%v.%v args must be an object with argument names as keys.`, ttype, fieldName),
552+
`%v.%v args must be an object with argument names as keys.`, ttype, fieldName,
553553
)
554554
if err != nil {
555555
return resultFieldMap, err
556556
}
557-
err = invariant(
557+
err = invariantf(
558558
arg.Type != nil,
559-
fmt.Sprintf(`%v.%v(%v:) argument type must be Input Type but got: %v.`, ttype, fieldName, argName, arg.Type),
559+
`%v.%v(%v:) argument type must be Input Type but got: %v.`, ttype, fieldName, argName, arg.Type,
560560
)
561561
if err != nil {
562562
return resultFieldMap, err
@@ -823,30 +823,30 @@ func NewUnion(config UnionConfig) *Union {
823823
objectType.PrivateDescription = config.Description
824824
objectType.ResolveType = config.ResolveType
825825

826-
err = invariant(
826+
err = invariantf(
827827
len(config.Types) > 0,
828-
fmt.Sprintf(`Must provide Array of types for Union %v.`, config.Name),
828+
`Must provide Array of types for Union %v.`, config.Name,
829829
)
830830
if err != nil {
831831
objectType.err = err
832832
return objectType
833833
}
834834
for _, ttype := range config.Types {
835-
err := invariant(
835+
err := invariantf(
836836
ttype != nil,
837-
fmt.Sprintf(`%v may only contain Object types, it cannot contain: %v.`, objectType, ttype),
837+
`%v may only contain Object types, it cannot contain: %v.`, objectType, ttype,
838838
)
839839
if err != nil {
840840
objectType.err = err
841841
return objectType
842842
}
843843
if objectType.ResolveType == nil {
844-
err = invariant(
844+
err = invariantf(
845845
ttype.IsTypeOf != nil,
846-
fmt.Sprintf(`Union Type %v does not provide a "resolveType" function `+
846+
`Union Type %v does not provide a "resolveType" function `+
847847
`and possible Type %v does not provide a "isTypeOf" `+
848848
`function. There is no way to resolve this possible type `+
849-
`during execution.`, objectType, ttype),
849+
`during execution.`, objectType, ttype,
850850
)
851851
if err != nil {
852852
objectType.err = err
@@ -947,19 +947,19 @@ func NewEnum(config EnumConfig) *Enum {
947947
func (gt *Enum) defineEnumValues(valueMap EnumValueConfigMap) ([]*EnumValueDefinition, error) {
948948
values := []*EnumValueDefinition{}
949949

950-
err := invariant(
950+
err := invariantf(
951951
len(valueMap) > 0,
952-
fmt.Sprintf(`%v values must be an object with value names as keys.`, gt),
952+
`%v values must be an object with value names as keys.`, gt,
953953
)
954954
if err != nil {
955955
return values, err
956956
}
957957

958958
for valueName, valueConfig := range valueMap {
959-
err := invariant(
959+
err := invariantf(
960960
valueConfig != nil,
961-
fmt.Sprintf(`%v.%v must refer to an object with a "value" key `+
962-
`representing an internal value but got: %v.`, gt, valueName, valueConfig),
961+
`%v.%v must refer to an object with a "value" key `+
962+
`representing an internal value but got: %v.`, gt, valueName, valueConfig,
963963
)
964964
if err != nil {
965965
return values, err
@@ -1130,9 +1130,9 @@ func (gt *InputObject) defineFieldMap() InputObjectFieldMap {
11301130
}
11311131
resultFieldMap := InputObjectFieldMap{}
11321132

1133-
err := invariant(
1133+
err := invariantf(
11341134
len(fieldMap) > 0,
1135-
fmt.Sprintf(`%v fields must be an object with field names as keys or a function which return such an object.`, gt),
1135+
`%v fields must be an object with field names as keys or a function which return such an object.`, gt,
11361136
)
11371137
if err != nil {
11381138
gt.err = err
@@ -1147,9 +1147,9 @@ func (gt *InputObject) defineFieldMap() InputObjectFieldMap {
11471147
if err != nil {
11481148
continue
11491149
}
1150-
err = invariant(
1150+
err = invariantf(
11511151
fieldConfig.Type != nil,
1152-
fmt.Sprintf(`%v.%v field type must be Input Type but got: %v.`, gt, fieldName, fieldConfig.Type),
1152+
`%v.%v field type must be Input Type but got: %v.`, gt, fieldName, fieldConfig.Type,
11531153
)
11541154
if err != nil {
11551155
gt.err = err
@@ -1205,7 +1205,7 @@ type List struct {
12051205
func NewList(ofType Type) *List {
12061206
gl := &List{}
12071207

1208-
err := invariant(ofType != nil, fmt.Sprintf(`Can only create List of a Type but got: %v.`, ofType))
1208+
err := invariantf(ofType != nil, `Can only create List of a Type but got: %v.`, ofType)
12091209
if err != nil {
12101210
gl.err = err
12111211
return gl
@@ -1259,7 +1259,7 @@ func NewNonNull(ofType Type) *NonNull {
12591259
gl := &NonNull{}
12601260

12611261
_, isOfTypeNonNull := ofType.(*NonNull)
1262-
err := invariant(ofType != nil && !isOfTypeNonNull, fmt.Sprintf(`Can only create NonNull of a Nullable Type but got: %v.`, ofType))
1262+
err := invariantf(ofType != nil && !isOfTypeNonNull, `Can only create NonNull of a Nullable Type but got: %v.`, ofType)
12631263
if err != nil {
12641264
gl.err = err
12651265
return gl
@@ -1286,8 +1286,8 @@ func (gl *NonNull) Error() error {
12861286
var NameRegExp, _ = regexp.Compile("^[_a-zA-Z][_a-zA-Z0-9]*$")
12871287

12881288
func assertValidName(name string) error {
1289-
return invariant(
1289+
return invariantf(
12901290
NameRegExp.MatchString(name),
1291-
fmt.Sprintf(`Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but "%v" does not.`, name),
1291+
`Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but "%v" does not.`, name,
12921292
)
12931293
}

executor.go

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -635,9 +635,7 @@ func completeValue(eCtx *ExecutionContext, returnType Type, fieldASTs []*ast.Fie
635635
}
636636

637637
// Not reachable. All possible output types have been considered.
638-
err := invariant(false,
639-
fmt.Sprintf(`Cannot complete value of unexpected type "%v."`, returnType),
640-
)
638+
err := invariantf(false, `Cannot complete value of unexpected type "%v."`, returnType)
641639
if err != nil {
642640
panic(gqlerrors.FormatError(err))
643641
}
@@ -663,8 +661,9 @@ func completeAbstractValue(eCtx *ExecutionContext, returnType Abstract, fieldAST
663661
runtimeType = defaultResolveTypeFn(resolveTypeParams, returnType)
664662
}
665663

666-
err := invariant(runtimeType != nil,
667-
fmt.Sprintf(`Could not determine runtime type of value "%v" for field %v.%v.`, result, info.ParentType, info.FieldName),
664+
err := invariantf(runtimeType != nil,
665+
`Could not determine runtime type of value "%v" for field %v.%v.`,
666+
result, info.ParentType, info.FieldName,
668667
)
669668
if err != nil {
670669
panic(err)
@@ -746,10 +745,10 @@ func completeListValue(eCtx *ExecutionContext, returnType *List, fieldASTs []*as
746745
if info.ParentType != nil {
747746
parentTypeName = info.ParentType.Name()
748747
}
749-
err := invariant(
748+
err := invariantf(
750749
resultVal.IsValid() && resultVal.Type().Kind() == reflect.Slice,
751-
fmt.Sprintf("User Error: expected iterable, but did not find one "+
752-
"for field %v.%v.", parentTypeName, info.FieldName),
750+
"User Error: expected iterable, but did not find one "+
751+
"for field %v.%v.", parentTypeName, info.FieldName,
753752
)
754753
if err != nil {
755754
panic(gqlerrors.FormatError(err))

schema.go

Lines changed: 23 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
package graphql
22

3-
import (
4-
"fmt"
5-
)
6-
73
type SchemaConfig struct {
84
Query *Object
95
Mutation *Object
@@ -224,9 +220,9 @@ func typeMapReducer(schema *Schema, typeMap TypeMap, objectType Type) (TypeMap,
224220
}
225221

226222
if mappedObjectType, ok := typeMap[objectType.Name()]; ok {
227-
err := invariant(
223+
err := invariantf(
228224
mappedObjectType == objectType,
229-
fmt.Sprintf(`Schema must contain unique named types but contains multiple types named "%v".`, objectType.Name()),
225+
`Schema must contain unique named types but contains multiple types named "%v".`, objectType.Name(),
230226
)
231227
if err != nil {
232228
return typeMap, err
@@ -344,23 +340,23 @@ func assertObjectImplementsInterface(schema *Schema, object *Object, iface *Inte
344340
ifaceField := ifaceFieldMap[fieldName]
345341

346342
// Assert interface field exists on object.
347-
err := invariant(
343+
err := invariantf(
348344
objectField != nil,
349-
fmt.Sprintf(`"%v" expects field "%v" but "%v" does not `+
350-
`provide it.`, iface, fieldName, object),
345+
`"%v" expects field "%v" but "%v" does not `+
346+
`provide it.`, iface, fieldName, object,
351347
)
352348
if err != nil {
353349
return err
354350
}
355351

356352
// Assert interface field type is satisfied by object field type, by being
357353
// a valid subtype. (covariant)
358-
err = invariant(
354+
err = invariantf(
359355
isTypeSubTypeOf(schema, objectField.Type, ifaceField.Type),
360-
fmt.Sprintf(`%v.%v expects type "%v" but `+
356+
`%v.%v expects type "%v" but `+
361357
`%v.%v provides type "%v".`,
362-
iface, fieldName, ifaceField.Type,
363-
object, fieldName, objectField.Type),
358+
iface, fieldName, ifaceField.Type,
359+
object, fieldName, objectField.Type,
364360
)
365361
if err != nil {
366362
return err
@@ -377,27 +373,26 @@ func assertObjectImplementsInterface(schema *Schema, object *Object, iface *Inte
377373
}
378374
}
379375
// Assert interface field arg exists on object field.
380-
err = invariant(
376+
err = invariantf(
381377
objectArg != nil,
382-
fmt.Sprintf(`%v.%v expects argument "%v" but `+
378+
`%v.%v expects argument "%v" but `+
383379
`%v.%v does not provide it.`,
384-
iface, fieldName, argName,
385-
object, fieldName),
380+
iface, fieldName, argName,
381+
object, fieldName,
386382
)
387383
if err != nil {
388384
return err
389385
}
390386

391387
// Assert interface field arg type matches object field arg type.
392388
// (invariant)
393-
err = invariant(
389+
err = invariantf(
394390
isEqualType(ifaceArg.Type, objectArg.Type),
395-
fmt.Sprintf(
396-
`%v.%v(%v:) expects type "%v" `+
397-
`but %v.%v(%v:) provides `+
398-
`type "%v".`,
399-
iface, fieldName, argName, ifaceArg.Type,
400-
object, fieldName, argName, objectArg.Type),
391+
`%v.%v(%v:) expects type "%v" `+
392+
`but %v.%v(%v:) provides `+
393+
`type "%v".`,
394+
iface, fieldName, argName, ifaceArg.Type,
395+
object, fieldName, argName, objectArg.Type,
401396
)
402397
if err != nil {
403398
return err
@@ -416,12 +411,12 @@ func assertObjectImplementsInterface(schema *Schema, object *Object, iface *Inte
416411

417412
if ifaceArg == nil {
418413
_, ok := objectArg.Type.(*NonNull)
419-
err = invariant(
414+
err = invariantf(
420415
!ok,
421-
fmt.Sprintf(`%v.%v(%v:) is of required type `+
416+
`%v.%v(%v:) is of required type `+
422417
`"%v" but is not also provided by the interface %v.%v.`,
423-
object, fieldName, argName,
424-
objectArg.Type, iface, fieldName),
418+
object, fieldName, argName,
419+
objectArg.Type, iface, fieldName,
425420
)
426421
if err != nil {
427422
return err

values.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ import (
77
"reflect"
88
"strings"
99

10+
"sort"
11+
1012
"github.com/graphql-go/graphql/gqlerrors"
1113
"github.com/graphql-go/graphql/language/ast"
1214
"github.com/graphql-go/graphql/language/kinds"
1315
"github.com/graphql-go/graphql/language/printer"
14-
"sort"
1516
)
1617

1718
// Prepares an object map of variableValues of the correct type based on the
@@ -442,3 +443,10 @@ func invariant(condition bool, message string) error {
442443
}
443444
return nil
444445
}
446+
447+
func invariantf(condition bool, message string, args ...interface{}) error {
448+
if !condition {
449+
return gqlerrors.NewFormattedError(fmt.Sprintf(message, args...))
450+
}
451+
return nil
452+
}

0 commit comments

Comments
 (0)