Skip to content

Commit 0e40a4e

Browse files
alex-langeAlexander Lange
authored andcommitted
Support thunks for Union.Types definitions
In schemas, it is possible to define the Union type before the definitions of the object types that are part of the union. This change adds a "UnionTypesThunk" option when creating a new Union, similar to the existing FieldsThunk and InterfacesThunk. This more closely matches the interface in graphql-js: https://github.com/graphql/graphql-js/blob/47bd8c8897c72d3efc17ecb1599a95cee6bac5e8/src/type/definition.ts#L1307 It is a first step in closing out graphql-go#624
1 parent f02a1c9 commit 0e40a4e

File tree

2 files changed

+99
-23
lines changed

2 files changed

+99
-23
lines changed

definition.go

Lines changed: 59 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -796,15 +796,19 @@ type Union struct {
796796
PrivateDescription string `json:"description"`
797797
ResolveType ResolveTypeFn
798798

799-
typeConfig UnionConfig
800-
types []*Object
801-
possibleTypes map[string]bool
799+
typeConfig UnionConfig
800+
initalizedTypes bool
801+
types []*Object
802+
possibleTypes map[string]bool
802803

803804
err error
804805
}
806+
807+
type UnionTypesThunk func() []*Object
808+
805809
type UnionConfig struct {
806-
Name string `json:"name"`
807-
Types []*Object `json:"types"`
810+
Name string `json:"name"`
811+
Types interface{} `json:"types"`
808812
ResolveType ResolveTypeFn
809813
Description string `json:"description"`
810814
}
@@ -822,48 +826,80 @@ func NewUnion(config UnionConfig) *Union {
822826
objectType.PrivateDescription = config.Description
823827
objectType.ResolveType = config.ResolveType
824828

825-
if objectType.err = invariantf(
826-
len(config.Types) > 0,
827-
`Must provide Array of types for Union %v.`, config.Name,
828-
); objectType.err != nil {
829-
return objectType
829+
objectType.typeConfig = config
830+
831+
return objectType
832+
}
833+
834+
func (ut *Union) Types() []*Object {
835+
if ut.initalizedTypes {
836+
return ut.types
837+
}
838+
839+
var unionTypes []*Object
840+
switch utype := ut.typeConfig.Types.(type) {
841+
case UnionTypesThunk:
842+
unionTypes = utype()
843+
case []*Object:
844+
unionTypes = utype
845+
case nil:
846+
default:
847+
ut.err = fmt.Errorf("Unknown Union.Types type: %T", ut.typeConfig.Types)
848+
ut.initalizedTypes = true
849+
return nil
850+
}
851+
852+
ut.types, ut.err = defineUnionTypes(ut, unionTypes)
853+
ut.initalizedTypes = true
854+
return ut.types
855+
}
856+
857+
func defineUnionTypes(objectType *Union, unionTypes []*Object) ([]*Object, error) {
858+
definedUnionTypes := []*Object{}
859+
860+
if err := invariantf(
861+
len(unionTypes) > 0,
862+
`Must provide Array of types for Union %v.`, objectType.Name(),
863+
); err != nil {
864+
return definedUnionTypes, err
830865
}
831-
for _, ttype := range config.Types {
832-
if objectType.err = invariantf(
866+
867+
for _, ttype := range unionTypes {
868+
if err := invariantf(
833869
ttype != nil,
834870
`%v may only contain Object types, it cannot contain: %v.`, objectType, ttype,
835-
); objectType.err != nil {
836-
return objectType
871+
); err != nil {
872+
return definedUnionTypes, err
837873
}
838874
if objectType.ResolveType == nil {
839-
if objectType.err = invariantf(
875+
if err := invariantf(
840876
ttype.IsTypeOf != nil,
841877
`Union Type %v does not provide a "resolveType" function `+
842878
`and possible Type %v does not provide a "isTypeOf" `+
843879
`function. There is no way to resolve this possible type `+
844880
`during execution.`, objectType, ttype,
845-
); objectType.err != nil {
846-
return objectType
881+
); err != nil {
882+
return definedUnionTypes, err
847883
}
848884
}
885+
definedUnionTypes = append(definedUnionTypes, ttype)
849886
}
850-
objectType.types = config.Types
851-
objectType.typeConfig = config
852887

853-
return objectType
854-
}
855-
func (ut *Union) Types() []*Object {
856-
return ut.types
888+
return definedUnionTypes, nil
857889
}
890+
858891
func (ut *Union) String() string {
859892
return ut.PrivateName
860893
}
894+
861895
func (ut *Union) Name() string {
862896
return ut.PrivateName
863897
}
898+
864899
func (ut *Union) Description() string {
865900
return ut.PrivateDescription
866901
}
902+
867903
func (ut *Union) Error() error {
868904
return ut.err
869905
}

definition_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,7 @@ func TestTypeSystem_DefinitionExample_ProhibitsNilTypeInUnions(t *testing.T) {
519519
Name: "BadUnion",
520520
Types: []*graphql.Object{nil},
521521
})
522+
ttype.Types()
522523
expected := `BadUnion may only contain Object types, it cannot contain: <nil>.`
523524
if ttype.Error().Error() != expected {
524525
t.Fatalf(`expected %v , got: %v`, expected, ttype.Error())
@@ -666,3 +667,42 @@ func TestTypeSystem_DefinitionExample_CanAddInputObjectField(t *testing.T) {
666667
t.Fatal("Unexpected result, inputObject should have a field named 'newValue'")
667668
}
668669
}
670+
671+
func TestTypeSystem_DefinitionExample_IncludesUnionTypesThunk(t *testing.T) {
672+
someObject := graphql.NewObject(graphql.ObjectConfig{
673+
Name: "SomeObject",
674+
Fields: graphql.Fields{
675+
"f": &graphql.Field{
676+
Type: graphql.Int,
677+
},
678+
},
679+
})
680+
681+
someOtherObject := graphql.NewObject(graphql.ObjectConfig{
682+
Name: "SomeOtherObject",
683+
Fields: graphql.Fields{
684+
"g": &graphql.Field{
685+
Type: graphql.Int,
686+
},
687+
},
688+
})
689+
690+
someUnion := graphql.NewUnion(graphql.UnionConfig{
691+
Name: "SomeUnion",
692+
Types: (graphql.UnionTypesThunk)(func() []*graphql.Object {
693+
return []*graphql.Object{someObject, someOtherObject}
694+
}),
695+
ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object {
696+
return nil
697+
},
698+
})
699+
700+
unionTypes := someUnion.Types()
701+
702+
if someUnion.Error() != nil {
703+
t.Fatalf("unexpected error, got: %v", someUnion.Error().Error())
704+
}
705+
if len(unionTypes) != 2 {
706+
t.Fatalf("Unexpected result, someUnion should have two unionTypes, has %d", len(unionTypes))
707+
}
708+
}

0 commit comments

Comments
 (0)