Skip to content

Commit

Permalink
Merge pull request #195 from SnaphyLabs/master
Browse files Browse the repository at this point in the history
Adding `AppendType` method to add Type to Schema object at runtime
  • Loading branch information
chris-ramon authored Jul 23, 2017
2 parents 96585f9 + c0ad112 commit d114382
Show file tree
Hide file tree
Showing 3 changed files with 199 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.DS_Store
.idea
141 changes: 141 additions & 0 deletions abstract_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,147 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForInterface(t *testing.T) {
}
}


func TestAppendTypeUsedToAddRuntimeCustomScalarTypeForInterface(t *testing.T) {

petType := graphql.NewInterface(graphql.InterfaceConfig{
Name: "Pet",
Fields: graphql.Fields{
"name": &graphql.Field{
Type: graphql.String,
},
},
})

// ie declare that Dog belongs to Pet interface
dogType := graphql.NewObject(graphql.ObjectConfig{
Name: "Dog",
Interfaces: []*graphql.Interface{
petType,
},
IsTypeOf: func(p graphql.IsTypeOfParams) bool {
_, ok := p.Value.(*testDog)
return ok
},
Fields: graphql.Fields{
"name": &graphql.Field{
Type: graphql.String,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
if dog, ok := p.Source.(*testDog); ok {
return dog.Name, nil
}
return nil, nil
},
},
"woofs": &graphql.Field{
Type: graphql.Boolean,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
if dog, ok := p.Source.(*testDog); ok {
return dog.Woofs, nil
}
return nil, nil
},
},
},
})
// ie declare that Cat belongs to Pet interface
catType := graphql.NewObject(graphql.ObjectConfig{
Name: "Cat",
Interfaces: []*graphql.Interface{
petType,
},
IsTypeOf: func(p graphql.IsTypeOfParams) bool {
_, ok := p.Value.(*testCat)
return ok
},
Fields: graphql.Fields{
"name": &graphql.Field{
Type: graphql.String,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
if cat, ok := p.Source.(*testCat); ok {
return cat.Name, nil
}
return nil, nil
},
},
"meows": &graphql.Field{
Type: graphql.Boolean,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
if cat, ok := p.Source.(*testCat); ok {
return cat.Meows, nil
}
return nil, nil
},
},
},
})
schema, err := graphql.NewSchema(graphql.SchemaConfig{
Query: graphql.NewObject(graphql.ObjectConfig{
Name: "Query",
Fields: graphql.Fields{
"pets": &graphql.Field{
Type: graphql.NewList(petType),
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
return []interface{}{
&testDog{"Odie", true},
&testCat{"Garfield", false},
}, nil
},
},
},
}),

})
if err != nil {
t.Fatalf("Error in schema %v", err.Error())
}

//Now add types catType and dogType at runtime.
schema.AppendType(catType)
schema.AppendType(dogType)

query := `{
pets {
name
... on Dog {
woofs
}
... on Cat {
meows
}
}
}`

expected := &graphql.Result{
Data: map[string]interface{}{
"pets": []interface{}{
map[string]interface{}{
"name": "Odie",
"woofs": bool(true),
},
map[string]interface{}{
"name": "Garfield",
"meows": bool(false),
},
},
},
Errors: nil,
}

result := graphql.Do(graphql.Params{
Schema: schema,
RequestString: query,
})
if len(result.Errors) != 0 {
t.Fatalf("wrong result, unexpected errors: %v", result.Errors)
}
if !reflect.DeepEqual(expected, result) {
t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expected, result))
}
}



func TestIsTypeOfUsedToResolveRuntimeTypeForUnion(t *testing.T) {

dogType := graphql.NewObject(graphql.ObjectConfig{
Expand Down
57 changes: 57 additions & 0 deletions schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,63 @@ func NewSchema(config SchemaConfig) (Schema, error) {
return schema, nil
}



//Added Check implementation of interfaces at runtime..
//Add Implementations at Runtime..
func (gq *Schema) AddImplementation() error{

// Keep track of all implementations by interface name.
if gq.implementations == nil {
gq.implementations = map[string][]*Object{}
}
for _, ttype := range gq.typeMap {
if ttype, ok := ttype.(*Object); ok {
for _, iface := range ttype.Interfaces() {
impls, ok := gq.implementations[iface.Name()]
if impls == nil || !ok {
impls = []*Object{}
}
impls = append(impls, ttype)
gq.implementations[iface.Name()] = impls
}
}
}

// Enforce correct interface implementations
for _, ttype := range gq.typeMap {
if ttype, ok := ttype.(*Object); ok {
for _, iface := range ttype.Interfaces() {
err := assertObjectImplementsInterface(gq, ttype, iface)
if err != nil {
return err
}
}
}
}

return nil
}


//Edited. To check add Types at RunTime..
//Append Runtime schema to typeMap
func (gq *Schema)AppendType(objectType Type) error {
if objectType.Error() != nil {
return objectType.Error()
}
var err error
gq.typeMap, err = typeMapReducer(gq, gq.typeMap, objectType)
if err != nil {
return err
}
//Now Add interface implementation..
return gq.AddImplementation()
}




func (gq *Schema) QueryType() *Object {
return gq.queryType
}
Expand Down

0 comments on commit d114382

Please sign in to comment.