func (tc *TypeConverter) unionToGQLUnion(nomsType *types.Type) *graphql.Union {
	nomsMemberTypes := nomsType.Desc.(types.CompoundDesc).ElemTypes
	memberTypes := make([]*graphql.Object, len(nomsMemberTypes))
	for i, nomsUnionType := range nomsMemberTypes {
		memberTypes[i] = tc.nomsTypeToGraphQLType(nomsUnionType, true).(*graphql.Object)
	}
	return graphql.NewUnion(graphql.UnionConfig{
		Name:  tc.getTypeName(nomsType),
		Types: memberTypes,
		ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object {
			if v, ok := p.Value.(types.Value); ok {
				for i, t := range nomsMemberTypes {
					if types.IsValueSubtypeOf(v, t) {
						return memberTypes[i]
					}
				}
				return nil
			}
			var nomsType *types.Type
			switch p.Value.(type) {
			case float64:
				nomsType = types.NumberType
			case string:
				nomsType = types.StringType
			case bool:
				nomsType = types.BoolType
			}
			return tc.nomsTypeToGraphQLType(nomsType, true).(*graphql.Object)
		},
	})
}
Creates a union of structs type.
package ngql
import (
	"context"
	"errors"
	"fmt"
	"strings"
	"github.com/attic-labs/graphql"
	"github.com/attic-labs/noms/go/d"
	"github.com/attic-labs/noms/go/types"
)
type TypeConverter struct {
	tm       TypeMap
	NameFunc NameFunc
}
func NewTypeConverter() *TypeConverter {
	return &TypeConverter{
		TypeMap{},
		DefaultNameFunc,
	}
}
type NameFunc func(nomsType *types.Type, isInputType bool) string
func (tc *TypeConverter) getTypeName(nomsType *types.Type) string {
	return tc.NameFunc(nomsType, false)
}
func (tc *TypeConverter) getInputTypeName(nomsType *types.Type) string {
	return tc.NameFunc(nomsType, true)
}
func (tc *TypeConverter) NomsTypeToGraphQLType(nomsType *types.Type) graphql.Type {
	return tc.nomsTypeToGraphQLType(nomsType, false)
}
func (tc *TypeConverter) NomsTypeToGraphQLInputType(nomsType *types.Type) (graphql.Input, error) {
	return tc.nomsTypeToGraphQLInputType(nomsType)
}
type TypeMap map[typeMapKey]graphql.Type
type typeMapKey struct {
	name          string
	boxedIfScalar bool
}
func NewTypeMap() *TypeMap {
	return &TypeMap{}
}
type graphQLTypeMode uint8
const (
	inputMode graphQLTypeMode = iota
	outputMode
)
type getFieldFn func(v interface{}, fieldName string, ctx context.Context) types.Value
type getSubvaluesFn func(vrw types.ValueReadWriter, v types.Value, args map[string]interface{}) interface{}
func (tc *TypeConverter) scalarToValue(nomsType *types.Type, scalarType graphql.Type) graphql.Type {
	return graphql.NewObject(graphql.ObjectConfig{
		Name: fmt.Sprintf("%sValue", tc.getTypeName(nomsType)),
		Fields: graphql.Fields{
			scalarValue: &graphql.Field{
				Type: graphql.NewNonNull(scalarType),
				Resolve: func(p graphql.ResolveParams) (interface{}, error) {
					return p.Source, nil  
				},
			},
		}})
}
func isScalar(nomsType *types.Type) bool {
	switch nomsType {
	case types.BoolType, types.NumberType, types.StringType:
		return true
	default:
		return false
	}
}
func NomsTypeToGraphQLType(nomsType *types.Type, boxedIfScalar bool, tm *TypeMap) graphql.Type {
	tc := TypeConverter{*tm, DefaultNameFunc}
	return tc.nomsTypeToGraphQLType(nomsType, boxedIfScalar)
}
func (tc *TypeConverter) nomsTypeToGraphQLType(nomsType *types.Type, boxedIfScalar bool) graphql.Type {
	name := tc.getTypeName(nomsType)
	key := typeMapKey{name, boxedIfScalar && isScalar(nomsType)}
	gqlType, ok := tc.tm[key]
	if ok {
		return gqlType
	}
	switch nomsType.TargetKind() {
	case types.NumberKind:
		gqlType = graphql.Float
		if boxedIfScalar {
			gqlType = tc.scalarToValue(nomsType, gqlType)
		}
	case types.StringKind:
		gqlType = graphql.String
		if boxedIfScalar {
			gqlType = tc.scalarToValue(nomsType, gqlType)
		}
	case types.BoolKind:
		gqlType = graphql.Boolean
		if boxedIfScalar {
			gqlType = tc.scalarToValue(nomsType, gqlType)
		}
	case types.StructKind:
		gqlType = tc.structToGQLObject(nomsType)
	case types.ListKind, types.SetKind:
		gqlType = tc.listAndSetToGraphQLObject(nomsType)
	case types.MapKind:
		gqlType = tc.mapToGraphQLObject(nomsType)
	case types.RefKind:
		gqlType = tc.refToGraphQLObject(nomsType)
	case types.UnionKind:
		gqlType = tc.unionToGQLUnion(nomsType)
	case types.BlobKind, types.ValueKind, types.TypeKind:
		gqlType = graphql.String
	case types.CycleKind:
		panic("not reached")  
	default:
		panic("not reached")
	}
	tc.tm[key] = gqlType
	return gqlType
}
func NomsTypeToGraphQLInputType(nomsType *types.Type, tm *TypeMap) (graphql.Input, error) {
	tc := TypeConverter{*tm, DefaultNameFunc}
	return tc.nomsTypeToGraphQLInputType(nomsType)
}
func (tc *TypeConverter) nomsTypeToGraphQLInputType(nomsType *types.Type) (graphql.Input, error) {
	if types.HasStructCycles(nomsType) {
		return nil, errors.New("GraphQL input type cannot contain cycles")
	}
	name := tc.getInputTypeName(nomsType)
	key := typeMapKey{name, false}
	gqlType, ok := tc.tm[key]
	if ok {
		return gqlType, nil
	}
	var err error
	switch nomsType.TargetKind() {
	case types.NumberKind:
		gqlType = graphql.Float
	case types.StringKind:
		gqlType = graphql.String
	case types.BoolKind:
		gqlType = graphql.Boolean
	case types.StructKind:
		gqlType, err = tc.structToGQLInputObject(nomsType)
	case types.ListKind, types.SetKind:
		gqlType, err = tc.listAndSetToGraphQLInputObject(nomsType)
	case types.MapKind:
		gqlType, err = tc.mapToGraphQLInputObject(nomsType)
	case types.RefKind:
		gqlType = graphql.String
	case types.UnionKind:
		return nil, errors.New("GraphQL input type cannot contain unions")
	case types.BlobKind, types.ValueKind, types.TypeKind:
		gqlType = graphql.String
	case types.CycleKind:
		panic("not reachable")  
	default:
		panic("not reached")
	}
	if err != nil {
		return nil, err
	}
	tc.tm[key] = gqlType
	return gqlType, nil
}
func isEmptyNomsUnion(nomsType *types.Type) bool {
	return nomsType.TargetKind() == types.UnionKind && len(nomsType.Desc.(types.CompoundDesc).ElemTypes) == 0
}