github.com/ndau/noms@v1.0.5/go/ngql/types.go (about)

     1  // Copyright 2017 Attic Labs, Inc. All rights reserved.
     2  // Licensed under the Apache License, version 2.0:
     3  // http://www.apache.org/licenses/LICENSE-2.0
     4  
     5  package ngql
     6  
     7  import (
     8  	"context"
     9  	"errors"
    10  	"fmt"
    11  
    12  	"strings"
    13  
    14  	"github.com/attic-labs/graphql"
    15  	"github.com/ndau/noms/go/d"
    16  	"github.com/ndau/noms/go/types"
    17  )
    18  
    19  // TypeConverter provides functions to convert between Noms types and GraphQL
    20  // types.
    21  type TypeConverter struct {
    22  	tm       TypeMap
    23  	NameFunc NameFunc
    24  }
    25  
    26  // NewTypeConverter creates a new TypeConverter.
    27  func NewTypeConverter() *TypeConverter {
    28  	return &TypeConverter{
    29  		TypeMap{},
    30  		DefaultNameFunc,
    31  	}
    32  }
    33  
    34  // NameFunc defines how to compute the GraphQL name for a Noms type.
    35  type NameFunc func(nomsType *types.Type, isInputType bool) string
    36  
    37  func (tc *TypeConverter) getTypeName(nomsType *types.Type) string {
    38  	return tc.NameFunc(nomsType, false)
    39  }
    40  
    41  func (tc *TypeConverter) getInputTypeName(nomsType *types.Type) string {
    42  	return tc.NameFunc(nomsType, true)
    43  }
    44  
    45  // NomsTypeToGraphQLType creates a GraphQL type from a Noms type that knows how
    46  // to resolve the Noms values.
    47  func (tc *TypeConverter) NomsTypeToGraphQLType(nomsType *types.Type) graphql.Type {
    48  	return tc.nomsTypeToGraphQLType(nomsType, false)
    49  }
    50  
    51  // NomsTypeToGraphQLInputType creates a GraphQL input type from a Noms type.
    52  // Input types may not be unions or cyclic structs. If we encounter those
    53  // this returns an error.
    54  func (tc *TypeConverter) NomsTypeToGraphQLInputType(nomsType *types.Type) (graphql.Input, error) {
    55  	return tc.nomsTypeToGraphQLInputType(nomsType)
    56  }
    57  
    58  // TypeMap is used as a cache in NomsTypeToGraphQLType and
    59  // NomsTypeToGraphQLInputType.
    60  type TypeMap map[typeMapKey]graphql.Type
    61  
    62  type typeMapKey struct {
    63  	name          string
    64  	boxedIfScalar bool
    65  }
    66  
    67  // NewTypeMap creates a new map that is used as a cache in
    68  // NomsTypeToGraphQLType and NomsTypeToGraphQLInputType.
    69  func NewTypeMap() *TypeMap {
    70  	return &TypeMap{}
    71  }
    72  
    73  // GraphQL has two type systems.
    74  // - One for output types which is used with resolvers to produce an output set.
    75  // - And another one for input types. Input types are used to verify that the
    76  // JSON like data passes as arguments are of the right type.
    77  // There is some overlap here. Scalars are the same and List can be used in
    78  // both.
    79  // The significant difference is graphql.Object (output) vs graphql.InputObject
    80  // Input types cannot be unions and input object types cannot contain cycles.
    81  
    82  type graphQLTypeMode uint8
    83  
    84  const (
    85  	inputMode graphQLTypeMode = iota
    86  	outputMode
    87  )
    88  
    89  // In terms of resolving a graph of data, there are three types of value:
    90  // scalars, lists and maps. During resolution, we are converting some noms
    91  // value to a graphql value. A getFieldFn will be invoked for a matching noms
    92  // type. Its job is to retrieve the sub-value from the noms type which is
    93  // mapped to a graphql map as a fieldname.
    94  type getFieldFn func(v interface{}, fieldName string, ctx context.Context) types.Value
    95  
    96  // When a field name is resolved, it may take key:value arguments. A
    97  // getSubvaluesFn handles returning one or more *noms* values whose presence is
    98  // indicated by the provided arguments.
    99  type getSubvaluesFn func(vrw types.ValueReadWriter, v types.Value, args map[string]interface{}) interface{}
   100  
   101  // GraphQL requires all memberTypes in a Union to be Structs, so when a noms
   102  // union contains a scalar, we represent it in that context as a "boxed" value.
   103  // E.g.
   104  // Boolean! =>
   105  // type BooleanValue {
   106  //   scalarValue: Boolean!
   107  // }
   108  func (tc *TypeConverter) scalarToValue(nomsType *types.Type, scalarType graphql.Type) graphql.Type {
   109  	return graphql.NewObject(graphql.ObjectConfig{
   110  		Name: fmt.Sprintf("%sValue", tc.getTypeName(nomsType)),
   111  		Fields: graphql.Fields{
   112  			scalarValue: &graphql.Field{
   113  				Type: graphql.NewNonNull(scalarType),
   114  				Resolve: func(p graphql.ResolveParams) (interface{}, error) {
   115  					return p.Source, nil // p.Source is already a go-native scalar type
   116  				},
   117  			},
   118  		}})
   119  }
   120  
   121  func isScalar(nomsType *types.Type) bool {
   122  	switch nomsType {
   123  	case types.BoolType, types.NumberType, types.StringType:
   124  		return true
   125  	default:
   126  		return false
   127  	}
   128  }
   129  
   130  // NomsTypeToGraphQLType creates a GraphQL type from a Noms type that knows how
   131  // to resolve the Noms values.
   132  func NomsTypeToGraphQLType(nomsType *types.Type, boxedIfScalar bool, tm *TypeMap) graphql.Type {
   133  	tc := TypeConverter{*tm, DefaultNameFunc}
   134  	return tc.nomsTypeToGraphQLType(nomsType, boxedIfScalar)
   135  }
   136  
   137  func (tc *TypeConverter) nomsTypeToGraphQLType(nomsType *types.Type, boxedIfScalar bool) graphql.Type {
   138  	name := tc.getTypeName(nomsType)
   139  	key := typeMapKey{name, boxedIfScalar && isScalar(nomsType)}
   140  	gqlType, ok := tc.tm[key]
   141  	if ok {
   142  		return gqlType
   143  	}
   144  
   145  	// The graphql package has built in support for recursive types using
   146  	// FieldsThunk which allows the inner type to refer to an outer type by
   147  	// lazily initializing the fields.
   148  	switch nomsType.TargetKind() {
   149  	case types.NumberKind:
   150  		gqlType = graphql.Float
   151  		if boxedIfScalar {
   152  			gqlType = tc.scalarToValue(nomsType, gqlType)
   153  		}
   154  
   155  	case types.StringKind:
   156  		gqlType = graphql.String
   157  		if boxedIfScalar {
   158  			gqlType = tc.scalarToValue(nomsType, gqlType)
   159  		}
   160  
   161  	case types.BoolKind:
   162  		gqlType = graphql.Boolean
   163  		if boxedIfScalar {
   164  			gqlType = tc.scalarToValue(nomsType, gqlType)
   165  		}
   166  
   167  	case types.StructKind:
   168  		gqlType = tc.structToGQLObject(nomsType)
   169  
   170  	case types.ListKind, types.SetKind:
   171  		gqlType = tc.listAndSetToGraphQLObject(nomsType)
   172  
   173  	case types.MapKind:
   174  		gqlType = tc.mapToGraphQLObject(nomsType)
   175  
   176  	case types.RefKind:
   177  		gqlType = tc.refToGraphQLObject(nomsType)
   178  
   179  	case types.UnionKind:
   180  		gqlType = tc.unionToGQLUnion(nomsType)
   181  
   182  	case types.BlobKind, types.ValueKind, types.TypeKind:
   183  		// TODO: https://github.com/ndau/noms/issues/3155
   184  		gqlType = graphql.String
   185  
   186  	case types.CycleKind:
   187  		panic("not reached") // we should never attempt to create a schema for any unresolved cycle
   188  
   189  	default:
   190  		panic("not reached")
   191  	}
   192  
   193  	tc.tm[key] = gqlType
   194  	return gqlType
   195  }
   196  
   197  // NomsTypeToGraphQLInputType creates a GraphQL input type from a Noms type.
   198  // Input types may not be unions or cyclic structs. If we encounter those
   199  // this returns an error.
   200  func NomsTypeToGraphQLInputType(nomsType *types.Type, tm *TypeMap) (graphql.Input, error) {
   201  	tc := TypeConverter{*tm, DefaultNameFunc}
   202  	return tc.nomsTypeToGraphQLInputType(nomsType)
   203  }
   204  
   205  func (tc *TypeConverter) nomsTypeToGraphQLInputType(nomsType *types.Type) (graphql.Input, error) {
   206  	// GraphQL input types do not support cycles.
   207  	if types.HasStructCycles(nomsType) {
   208  		return nil, errors.New("GraphQL input type cannot contain cycles")
   209  	}
   210  
   211  	name := tc.getInputTypeName(nomsType)
   212  	key := typeMapKey{name, false}
   213  	gqlType, ok := tc.tm[key]
   214  	if ok {
   215  		return gqlType, nil
   216  	}
   217  
   218  	var err error
   219  	switch nomsType.TargetKind() {
   220  	case types.NumberKind:
   221  		gqlType = graphql.Float
   222  
   223  	case types.StringKind:
   224  		gqlType = graphql.String
   225  
   226  	case types.BoolKind:
   227  		gqlType = graphql.Boolean
   228  
   229  	case types.StructKind:
   230  		gqlType, err = tc.structToGQLInputObject(nomsType)
   231  
   232  	case types.ListKind, types.SetKind:
   233  		gqlType, err = tc.listAndSetToGraphQLInputObject(nomsType)
   234  
   235  	case types.MapKind:
   236  		gqlType, err = tc.mapToGraphQLInputObject(nomsType)
   237  
   238  	case types.RefKind:
   239  		gqlType = graphql.String
   240  
   241  	case types.UnionKind:
   242  		return nil, errors.New("GraphQL input type cannot contain unions")
   243  
   244  	case types.BlobKind, types.ValueKind, types.TypeKind:
   245  		// TODO: https://github.com/ndau/noms/issues/3155
   246  		gqlType = graphql.String
   247  
   248  	case types.CycleKind:
   249  		panic("not reachable") // This is handled at the top of nomsTypeToGraphQLInputType
   250  
   251  	default:
   252  		panic("not reached")
   253  	}
   254  
   255  	if err != nil {
   256  		return nil, err
   257  	}
   258  
   259  	tc.tm[key] = gqlType
   260  	return gqlType, nil
   261  }
   262  
   263  func isEmptyNomsUnion(nomsType *types.Type) bool {
   264  	return nomsType.TargetKind() == types.UnionKind && len(nomsType.Desc.(types.CompoundDesc).ElemTypes) == 0
   265  }
   266  
   267  // Creates a union of structs type.
   268  func (tc *TypeConverter) unionToGQLUnion(nomsType *types.Type) *graphql.Union {
   269  	nomsMemberTypes := nomsType.Desc.(types.CompoundDesc).ElemTypes
   270  	memberTypes := make([]*graphql.Object, len(nomsMemberTypes))
   271  
   272  	for i, nomsUnionType := range nomsMemberTypes {
   273  		// Member types cannot be non-null and must be struct (graphl.Object)
   274  		memberTypes[i] = tc.nomsTypeToGraphQLType(nomsUnionType, true).(*graphql.Object)
   275  	}
   276  
   277  	return graphql.NewUnion(graphql.UnionConfig{
   278  		Name:  tc.getTypeName(nomsType),
   279  		Types: memberTypes,
   280  		ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object {
   281  			if v, ok := p.Value.(types.Value); ok {
   282  				// We cannot just get the type of the value here. GraphQL requires
   283  				// us to return one of the types in memberTypes.
   284  				for i, t := range nomsMemberTypes {
   285  					if types.IsValueSubtypeOf(v, t) {
   286  						return memberTypes[i]
   287  					}
   288  				}
   289  				return nil
   290  			}
   291  
   292  			var nomsType *types.Type
   293  			switch p.Value.(type) {
   294  			case float64:
   295  				nomsType = types.NumberType
   296  			case string:
   297  				nomsType = types.StringType
   298  			case bool:
   299  				nomsType = types.BoolType
   300  			}
   301  			return tc.nomsTypeToGraphQLType(nomsType, true).(*graphql.Object)
   302  		},
   303  	})
   304  }
   305  
   306  func (tc *TypeConverter) structToGQLObject(nomsType *types.Type) *graphql.Object {
   307  	return graphql.NewObject(graphql.ObjectConfig{
   308  		Name: tc.getTypeName(nomsType),
   309  		Fields: graphql.FieldsThunk(func() graphql.Fields {
   310  			structDesc := nomsType.Desc.(types.StructDesc)
   311  			fields := graphql.Fields{
   312  				"hash": &graphql.Field{
   313  					Type: graphql.NewNonNull(graphql.String),
   314  					Resolve: func(p graphql.ResolveParams) (interface{}, error) {
   315  						return p.Source.(types.Struct).Hash().String(), nil
   316  					},
   317  				},
   318  			}
   319  
   320  			structDesc.IterFields(func(name string, nomsFieldType *types.Type, optional bool) {
   321  				fieldType := tc.nomsTypeToGraphQLType(nomsFieldType, false)
   322  				if !optional {
   323  					fieldType = graphql.NewNonNull(fieldType)
   324  				}
   325  
   326  				fields[name] = &graphql.Field{
   327  					Type: fieldType,
   328  					Resolve: func(p graphql.ResolveParams) (interface{}, error) {
   329  						if field, ok := p.Source.(types.Struct).MaybeGet(name); ok {
   330  							return MaybeGetScalar(field), nil
   331  						}
   332  						return nil, nil
   333  					},
   334  				}
   335  			})
   336  
   337  			return fields
   338  		}),
   339  	})
   340  }
   341  
   342  func (tc *TypeConverter) listAndSetToGraphQLInputObject(nomsType *types.Type) (graphql.Input, error) {
   343  	nomsValueType := nomsType.Desc.(types.CompoundDesc).ElemTypes[0]
   344  	elemType, err := tc.nomsTypeToGraphQLInputType(nomsValueType)
   345  	if err != nil {
   346  		return nil, err
   347  	}
   348  	return graphql.NewList(graphql.NewNonNull(elemType)), nil
   349  }
   350  
   351  func (tc *TypeConverter) mapToGraphQLInputObject(nomsType *types.Type) (graphql.Input, error) {
   352  	nomsKeyType := nomsType.Desc.(types.CompoundDesc).ElemTypes[0]
   353  	nomsValueType := nomsType.Desc.(types.CompoundDesc).ElemTypes[1]
   354  
   355  	keyType, err := tc.nomsTypeToGraphQLInputType(nomsKeyType)
   356  	if err != nil {
   357  		return nil, err
   358  	}
   359  	valueType, err := tc.nomsTypeToGraphQLInputType(nomsValueType)
   360  	if err != nil {
   361  		return nil, err
   362  	}
   363  
   364  	entryType := tc.mapEntryToGraphQLInputObject(keyType, valueType, nomsKeyType, nomsValueType)
   365  	return graphql.NewList(entryType), nil
   366  }
   367  
   368  func (tc *TypeConverter) structToGQLInputObject(nomsType *types.Type) (graphql.Input, error) {
   369  	var err error
   370  	rv := graphql.NewInputObject(graphql.InputObjectConfig{
   371  		Name: tc.getInputTypeName(nomsType),
   372  		Fields: graphql.InputObjectConfigFieldMapThunk(func() graphql.InputObjectConfigFieldMap {
   373  			structDesc := nomsType.Desc.(types.StructDesc)
   374  			fields := make(graphql.InputObjectConfigFieldMap, structDesc.Len())
   375  
   376  			structDesc.IterFields(func(name string, nomsFieldType *types.Type, optional bool) {
   377  				if err != nil {
   378  					return
   379  				}
   380  				var fieldType graphql.Input
   381  				fieldType, err = tc.nomsTypeToGraphQLInputType(nomsFieldType)
   382  				if err != nil {
   383  					return
   384  				}
   385  				if !optional {
   386  					fieldType = graphql.NewNonNull(fieldType)
   387  				}
   388  				fields[name] = &graphql.InputObjectFieldConfig{
   389  					Type: fieldType,
   390  				}
   391  			})
   392  
   393  			return fields
   394  		}),
   395  	})
   396  	if err != nil {
   397  		return nil, err
   398  	}
   399  	return rv, nil
   400  }
   401  
   402  var listArgs = graphql.FieldConfigArgument{
   403  	atKey:    &graphql.ArgumentConfig{Type: graphql.Int},
   404  	countKey: &graphql.ArgumentConfig{Type: graphql.Int},
   405  }
   406  
   407  func getListElements(vrw types.ValueReadWriter, v types.Value, args map[string]interface{}) interface{} {
   408  	l := v.(types.Collection)
   409  	idx := 0
   410  	count := int(l.Len())
   411  	end := count
   412  
   413  	if at, ok := args[atKey].(int); ok {
   414  		idx = at
   415  	}
   416  
   417  	if c, ok := args[countKey].(int); ok {
   418  		count = c
   419  	}
   420  
   421  	// Clamp ranges
   422  	if count <= 0 || idx >= end {
   423  		return ([]interface{})(nil)
   424  	}
   425  	if idx < 0 {
   426  		idx = 0
   427  	}
   428  	if idx+count > end {
   429  		count = end - idx
   430  	}
   431  
   432  	values := make([]interface{}, count)
   433  
   434  	cols, offset := types.LoadLeafNodes([]types.Collection{l}, uint64(idx), uint64(idx+count))
   435  
   436  	// Iterate the collections we got, skipping the first offset elements and bailing out
   437  	// once we've filled values with count elements.
   438  	elementsSeen := uint64(0)
   439  	maybeAddElement := func(v types.Value) {
   440  		if elementsSeen >= offset && elementsSeen-offset < uint64(count) {
   441  			values[elementsSeen-offset] = MaybeGetScalar(v)
   442  		}
   443  		elementsSeen++
   444  	}
   445  	// TODO: Use a cursor so we do not have to instantiate all values. @arv has a
   446  	// change in the works that only creates Values as needed.
   447  	for _, c := range cols {
   448  		v := c.(types.Value)
   449  		v.WalkValues(maybeAddElement)
   450  		if elementsSeen-offset >= uint64(count) {
   451  			break
   452  		}
   453  	}
   454  
   455  	return values
   456  }
   457  
   458  func getSetElements(vrw types.ValueReadWriter, v types.Value, args map[string]interface{}) interface{} {
   459  	s := v.(types.Set)
   460  
   461  	iter, nomsKey, nomsThrough, count, singleExactMatch := getCollectionArgs(vrw, s, args, iteratorFactory{
   462  		IteratorFrom: func(from types.Value) interface{} {
   463  			return s.IteratorFrom(from)
   464  		},
   465  		IteratorAt: func(at uint64) interface{} {
   466  			return s.IteratorAt(at)
   467  		},
   468  		First: func() interface{} {
   469  			return &setFirstIterator{s: s}
   470  		},
   471  	})
   472  
   473  	if count == 0 {
   474  		return ([]interface{})(nil)
   475  	}
   476  
   477  	setIter := iter.(types.SetIterator)
   478  	values := make([]interface{}, 0, count)
   479  	for i := uint64(0); i < count; i++ {
   480  		v := setIter.Next()
   481  		if v == nil {
   482  			break
   483  		}
   484  		if singleExactMatch {
   485  			if nomsKey.Equals(v) {
   486  				values = append(values, MaybeGetScalar(v))
   487  			}
   488  			break
   489  		}
   490  
   491  		if nomsThrough != nil {
   492  			if !nomsThrough.Less(v) {
   493  				values = append(values, MaybeGetScalar(v))
   494  			} else {
   495  				break
   496  			}
   497  		} else {
   498  			values = append(values, MaybeGetScalar(v))
   499  		}
   500  	}
   501  
   502  	return values
   503  }
   504  
   505  func getCollectionArgs(vrw types.ValueReadWriter, col types.Collection, args map[string]interface{}, factory iteratorFactory) (iter interface{}, nomsKey, nomsThrough types.Value, count uint64, singleExactMatch bool) {
   506  	typ := types.TypeOf(col)
   507  	length := col.Len()
   508  	nomsKeyType := typ.Desc.(types.CompoundDesc).ElemTypes[0]
   509  
   510  	if keys, ok := args[keysKey]; ok {
   511  		slice := keys.([]interface{})
   512  		nomsKeys := make(types.ValueSlice, len(slice))
   513  		for i, v := range slice {
   514  			var nomsValue types.Value
   515  			nomsValue = InputToNomsValue(vrw, v, nomsKeyType)
   516  			nomsKeys[i] = nomsValue
   517  		}
   518  		count = uint64(len(slice))
   519  		iter = &mapIteratorForKeys{
   520  			m:    col.(types.Map),
   521  			keys: nomsKeys,
   522  		}
   523  		return
   524  	}
   525  
   526  	nomsThrough = getThroughArg(vrw, nomsKeyType, args)
   527  
   528  	count, singleExactMatch = getCountArg(length, args)
   529  
   530  	if key, ok := args[keyKey]; ok {
   531  		nomsKey = InputToNomsValue(vrw, key, nomsKeyType)
   532  		iter = factory.IteratorFrom(nomsKey)
   533  	} else if at, ok := args[atKey]; ok {
   534  		idx := at.(int)
   535  		if idx < 0 {
   536  			idx = 0
   537  		} else if uint64(idx) > length {
   538  			count = 0
   539  			return
   540  		}
   541  		iter = factory.IteratorAt(uint64(idx))
   542  	} else if count == 1 && !singleExactMatch {
   543  		// no key, no at, no through, but a count:1
   544  		iter = factory.First()
   545  	} else {
   546  		iter = factory.IteratorAt(0)
   547  	}
   548  
   549  	return
   550  }
   551  
   552  type mapAppender func(slice []interface{}, k, v types.Value) []interface{}
   553  
   554  type mapiter interface {
   555  	Valid() bool
   556  	Entry() (k, v types.Value)
   557  	Next() bool
   558  }
   559  
   560  func getMapElements(vrw types.ValueReadWriter, v types.Value, args map[string]interface{}, app mapAppender) (interface{}, error) {
   561  	m := v.(types.Map)
   562  
   563  	iter, nomsKey, nomsThrough, count, singleExactMatch := getCollectionArgs(vrw, m, args, iteratorFactory{
   564  		IteratorFrom: func(from types.Value) interface{} {
   565  			return m.IteratorFrom(from)
   566  		},
   567  		IteratorAt: func(at uint64) interface{} {
   568  			return m.IteratorAt(at)
   569  		},
   570  		First: func() interface{} {
   571  			return &mapFirstIterator{m: &m}
   572  		},
   573  	})
   574  
   575  	if count == 0 {
   576  		return ([]interface{})(nil), nil
   577  	}
   578  
   579  	mapIter := iter.(mapiter)
   580  	values := make([]interface{}, 0, count)
   581  	for i := uint64(0); i < count; i++ {
   582  		if !mapIter.Valid() {
   583  			break
   584  		}
   585  
   586  		k, v := mapIter.Entry()
   587  
   588  		if singleExactMatch {
   589  			if nomsKey.Equals(k) {
   590  				values = app(values, k, v)
   591  			}
   592  			break
   593  		}
   594  
   595  		if nomsThrough != nil {
   596  			if !nomsThrough.Less(k) {
   597  				values = app(values, k, v)
   598  			} else {
   599  				break
   600  			}
   601  		} else {
   602  			values = app(values, k, v)
   603  		}
   604  
   605  		mapIter.Next()
   606  	}
   607  
   608  	return values, nil
   609  }
   610  
   611  func getCountArg(count uint64, args map[string]interface{}) (c uint64, singleExactMatch bool) {
   612  	if c, ok := args[countKey]; ok {
   613  		c := c.(int)
   614  		if c <= 0 {
   615  			return 0, false
   616  		}
   617  		return uint64(c), false
   618  	}
   619  	// If we have key and no count/through we use count 1
   620  	_, hasKey := args[keyKey]
   621  	_, hasThrough := args[throughKey]
   622  	if hasKey && !hasThrough {
   623  		return uint64(1), true
   624  	}
   625  
   626  	return count, false
   627  }
   628  
   629  func getThroughArg(vrw types.ValueReadWriter, nomsKeyType *types.Type, args map[string]interface{}) types.Value {
   630  	if through, ok := args[throughKey]; ok {
   631  		return InputToNomsValue(vrw, through, nomsKeyType)
   632  	}
   633  	return nil
   634  }
   635  
   636  type iteratorFactory struct {
   637  	IteratorFrom func(from types.Value) interface{}
   638  	IteratorAt   func(at uint64) interface{}
   639  	First        func() interface{}
   640  }
   641  
   642  type mapEntry struct {
   643  	key, value types.Value
   644  }
   645  
   646  // Map data must be returned as a list of key-value pairs. Each unique keyType:valueType is
   647  // represented as a graphql
   648  //
   649  // type <KeyTypeName><ValueTypeName>Entry {
   650  //	 key: <KeyType>!
   651  //	 value: <ValueType>!
   652  // }
   653  func (tc *TypeConverter) mapEntryToGraphQLObject(keyType, valueType graphql.Type, nomsKeyType, nomsValueType *types.Type) graphql.Type {
   654  	return graphql.NewNonNull(graphql.NewObject(graphql.ObjectConfig{
   655  		Name: fmt.Sprintf("%s%sEntry", tc.getTypeName(nomsKeyType), tc.getTypeName(nomsValueType)),
   656  		Fields: graphql.FieldsThunk(func() graphql.Fields {
   657  			return graphql.Fields{
   658  				keyKey: &graphql.Field{
   659  					Type: keyType,
   660  					Resolve: func(p graphql.ResolveParams) (interface{}, error) {
   661  						entry := p.Source.(mapEntry)
   662  						return MaybeGetScalar(entry.key), nil
   663  					},
   664  				},
   665  				valueKey: &graphql.Field{
   666  					Type: valueType,
   667  					Resolve: func(p graphql.ResolveParams) (interface{}, error) {
   668  						entry := p.Source.(mapEntry)
   669  						return MaybeGetScalar(entry.value), nil
   670  					},
   671  				},
   672  			}
   673  		}),
   674  	}))
   675  }
   676  
   677  func (tc *TypeConverter) mapEntryToGraphQLInputObject(keyType, valueType graphql.Input, nomsKeyType, nomsValueType *types.Type) graphql.Input {
   678  	return graphql.NewNonNull(graphql.NewInputObject(graphql.InputObjectConfig{
   679  		Name: fmt.Sprintf("%s%sEntryInput", tc.getInputTypeName(nomsKeyType), tc.getInputTypeName(nomsValueType)),
   680  		Fields: graphql.InputObjectConfigFieldMapThunk(func() graphql.InputObjectConfigFieldMap {
   681  			return graphql.InputObjectConfigFieldMap{
   682  				keyKey: &graphql.InputObjectFieldConfig{
   683  					Type: graphql.NewNonNull(keyType),
   684  				},
   685  				valueKey: &graphql.InputObjectFieldConfig{
   686  					Type: graphql.NewNonNull(valueType),
   687  				},
   688  			}
   689  		}),
   690  	}))
   691  }
   692  
   693  // DefaultNameFunc returns the GraphQL type name for a Noms type.
   694  func DefaultNameFunc(nomsType *types.Type, isInputType bool) string {
   695  	if isInputType {
   696  		return GetInputTypeName(nomsType)
   697  	}
   698  	return GetTypeName(nomsType)
   699  }
   700  
   701  // GetTypeName provides a unique type name that is used by GraphQL.
   702  func GetTypeName(nomsType *types.Type) string {
   703  	return getTypeName(nomsType, "")
   704  }
   705  
   706  // GetInputTypeName returns a type name that is unique and useful for GraphQL
   707  // input types.
   708  func GetInputTypeName(nomsType *types.Type) string {
   709  	return getTypeName(nomsType, "Input")
   710  }
   711  
   712  func getTypeName(nomsType *types.Type, suffix string) string {
   713  	switch nomsType.TargetKind() {
   714  	case types.BoolKind:
   715  		return "Boolean"
   716  
   717  	case types.NumberKind:
   718  		return "Number"
   719  
   720  	case types.StringKind:
   721  		return "String"
   722  
   723  	case types.BlobKind:
   724  		return "Blob"
   725  
   726  	case types.ValueKind:
   727  		return "Value"
   728  
   729  	case types.ListKind:
   730  		nomsValueType := nomsType.Desc.(types.CompoundDesc).ElemTypes[0]
   731  		if isEmptyNomsUnion(nomsValueType) {
   732  			return "EmptyList"
   733  		}
   734  		return fmt.Sprintf("%sList%s", GetTypeName(nomsValueType), suffix)
   735  
   736  	case types.MapKind:
   737  		nomsKeyType := nomsType.Desc.(types.CompoundDesc).ElemTypes[0]
   738  		nomsValueType := nomsType.Desc.(types.CompoundDesc).ElemTypes[1]
   739  		if isEmptyNomsUnion(nomsKeyType) {
   740  			d.Chk.True(isEmptyNomsUnion(nomsValueType))
   741  			return "EmptyMap"
   742  		}
   743  
   744  		return fmt.Sprintf("%sTo%sMap%s", GetTypeName(nomsKeyType), GetTypeName(nomsValueType), suffix)
   745  
   746  	case types.RefKind:
   747  		return fmt.Sprintf("%sRef%s", GetTypeName(nomsType.Desc.(types.CompoundDesc).ElemTypes[0]), suffix)
   748  
   749  	case types.SetKind:
   750  		nomsValueType := nomsType.Desc.(types.CompoundDesc).ElemTypes[0]
   751  		if isEmptyNomsUnion(nomsValueType) {
   752  			return "EmptySet"
   753  		}
   754  
   755  		return fmt.Sprintf("%sSet%s", GetTypeName(nomsValueType), suffix)
   756  
   757  	case types.StructKind:
   758  		// GraphQL Name cannot start with a number.
   759  		// GraphQL type names must be globally unique.
   760  		return fmt.Sprintf("%s%s_%s", nomsType.Desc.(types.StructDesc).Name, suffix, nomsType.Hash().String()[:6])
   761  
   762  	case types.TypeKind:
   763  		// GraphQL Name cannot start with a number.
   764  		// TODO: https://github.com/ndau/noms/issues/3155
   765  		return fmt.Sprintf("Type%s_%s", suffix, nomsType.Hash().String()[:6])
   766  
   767  	case types.UnionKind:
   768  		unionMemberTypes := nomsType.Desc.(types.CompoundDesc).ElemTypes
   769  		names := make([]string, len(unionMemberTypes))
   770  		for i, unionMemberType := range unionMemberTypes {
   771  			names[i] = GetTypeName(unionMemberType)
   772  		}
   773  		return strings.Join(names, "Or") + suffix
   774  
   775  	case types.CycleKind:
   776  		return "Cycle"
   777  
   778  	default:
   779  		panic(fmt.Sprintf("(GetTypeName) not reached: %s", nomsType.Describe()))
   780  	}
   781  }
   782  
   783  func argsWithSize() graphql.Fields {
   784  	return graphql.Fields{
   785  		sizeKey: &graphql.Field{
   786  			Type: graphql.Float,
   787  			Resolve: func(p graphql.ResolveParams) (interface{}, error) {
   788  				c := p.Source.(types.Collection)
   789  				return MaybeGetScalar(types.Number(c.Len())), nil
   790  			},
   791  		},
   792  	}
   793  }
   794  
   795  func (tc *TypeConverter) listAndSetToGraphQLObject(nomsType *types.Type) *graphql.Object {
   796  	nomsValueType := nomsType.Desc.(types.CompoundDesc).ElemTypes[0]
   797  	var listType, valueType graphql.Type
   798  	var keyInputType graphql.Input
   799  	var keyInputError error
   800  	if !isEmptyNomsUnion(nomsValueType) {
   801  		valueType = tc.nomsTypeToGraphQLType(nomsValueType, false)
   802  		keyInputType, keyInputError = tc.nomsTypeToGraphQLInputType(nomsValueType)
   803  		listType = graphql.NewNonNull(valueType)
   804  	}
   805  
   806  	return graphql.NewObject(graphql.ObjectConfig{
   807  		Name: tc.getTypeName(nomsType),
   808  		Fields: graphql.FieldsThunk(func() graphql.Fields {
   809  			fields := argsWithSize()
   810  
   811  			if listType != nil {
   812  				var args graphql.FieldConfigArgument
   813  				var getSubvalues getSubvaluesFn
   814  
   815  				switch nomsType.TargetKind() {
   816  				case types.ListKind:
   817  					args = listArgs
   818  					getSubvalues = getListElements
   819  
   820  				case types.SetKind:
   821  					args = graphql.FieldConfigArgument{
   822  						atKey:    &graphql.ArgumentConfig{Type: graphql.Int},
   823  						countKey: &graphql.ArgumentConfig{Type: graphql.Int},
   824  					}
   825  					if keyInputError == nil {
   826  						args[keyKey] = &graphql.ArgumentConfig{Type: keyInputType}
   827  						args[throughKey] = &graphql.ArgumentConfig{Type: keyInputType}
   828  					}
   829  					getSubvalues = getSetElements
   830  				}
   831  				valuesField := &graphql.Field{
   832  					Type: graphql.NewList(listType),
   833  					Args: args,
   834  					Resolve: func(p graphql.ResolveParams) (interface{}, error) {
   835  						c := p.Source.(types.Collection)
   836  						vrw := p.Context.Value(vrwKey).(types.ValueReadWriter)
   837  						return getSubvalues(vrw, c, p.Args), nil
   838  					},
   839  				}
   840  				fields[valuesKey] = valuesField
   841  				fields[elementsKey] = valuesField
   842  			}
   843  
   844  			return fields
   845  		}),
   846  	})
   847  }
   848  
   849  func (tc *TypeConverter) mapToGraphQLObject(nomsType *types.Type) *graphql.Object {
   850  	return graphql.NewObject(graphql.ObjectConfig{
   851  		Name: tc.getTypeName(nomsType),
   852  		Fields: graphql.FieldsThunk(func() graphql.Fields {
   853  			nomsKeyType := nomsType.Desc.(types.CompoundDesc).ElemTypes[0]
   854  			nomsValueType := nomsType.Desc.(types.CompoundDesc).ElemTypes[1]
   855  			isEmptyMap := isEmptyNomsUnion(nomsKeyType) || isEmptyNomsUnion(nomsValueType)
   856  
   857  			fields := argsWithSize()
   858  
   859  			if !isEmptyMap {
   860  				keyType := tc.nomsTypeToGraphQLType(nomsKeyType, false)
   861  				keyInputType, keyInputError := tc.nomsTypeToGraphQLInputType(nomsKeyType)
   862  				valueType := tc.nomsTypeToGraphQLType(nomsValueType, false)
   863  				entryType := tc.mapEntryToGraphQLObject(graphql.NewNonNull(keyType), valueType, nomsKeyType, nomsValueType)
   864  
   865  				args := graphql.FieldConfigArgument{
   866  					atKey:    &graphql.ArgumentConfig{Type: graphql.Int},
   867  					countKey: &graphql.ArgumentConfig{Type: graphql.Int},
   868  				}
   869  				if keyInputError == nil {
   870  					args[keyKey] = &graphql.ArgumentConfig{Type: keyInputType}
   871  					args[keysKey] = &graphql.ArgumentConfig{Type: graphql.NewList(graphql.NewNonNull(keyInputType))}
   872  					args[throughKey] = &graphql.ArgumentConfig{Type: keyInputType}
   873  				}
   874  
   875  				entriesField := &graphql.Field{
   876  					Type: graphql.NewList(entryType),
   877  					Args: args,
   878  					Resolve: func(p graphql.ResolveParams) (interface{}, error) {
   879  						c := p.Source.(types.Collection)
   880  						vrw := p.Context.Value(vrwKey).(types.ValueReadWriter)
   881  						return getMapElements(vrw, c, p.Args, mapAppendEntry)
   882  					},
   883  				}
   884  				fields[entriesKey] = entriesField
   885  				fields[elementsKey] = entriesField
   886  
   887  				fields[keysKey] = &graphql.Field{
   888  					Type: graphql.NewList(keyType),
   889  					Args: args,
   890  					Resolve: func(p graphql.ResolveParams) (interface{}, error) {
   891  						c := p.Source.(types.Collection)
   892  						vrw := p.Context.Value(vrwKey).(types.ValueReadWriter)
   893  						return getMapElements(vrw, c, p.Args, mapAppendKey)
   894  					},
   895  				}
   896  				fields[valuesKey] = &graphql.Field{
   897  					Type: graphql.NewList(valueType),
   898  					Args: args,
   899  					Resolve: func(p graphql.ResolveParams) (interface{}, error) {
   900  						c := p.Source.(types.Collection)
   901  						vrw := p.Context.Value(vrwKey).(types.ValueReadWriter)
   902  						return getMapElements(vrw, c, p.Args, mapAppendValue)
   903  					},
   904  				}
   905  			}
   906  
   907  			return fields
   908  		}),
   909  	})
   910  }
   911  
   912  func mapAppendKey(slice []interface{}, k, v types.Value) []interface{} {
   913  	return append(slice, MaybeGetScalar(k))
   914  }
   915  
   916  func mapAppendValue(slice []interface{}, k, v types.Value) []interface{} {
   917  	return append(slice, MaybeGetScalar(v))
   918  }
   919  
   920  func mapAppendEntry(slice []interface{}, k, v types.Value) []interface{} {
   921  	return append(slice, mapEntry{k, v})
   922  }
   923  
   924  // Refs are represented as structs:
   925  //
   926  // type <ValueTypeName>Entry {
   927  //	 targetHash: String!
   928  //	 targetValue: <ValueType>!
   929  // }
   930  func (tc *TypeConverter) refToGraphQLObject(nomsType *types.Type) *graphql.Object {
   931  	return graphql.NewObject(graphql.ObjectConfig{
   932  		Name: tc.getTypeName(nomsType),
   933  		Fields: graphql.FieldsThunk(func() graphql.Fields {
   934  			nomsTargetType := nomsType.Desc.(types.CompoundDesc).ElemTypes[0]
   935  			targetType := tc.nomsTypeToGraphQLType(nomsTargetType, false)
   936  
   937  			return graphql.Fields{
   938  				targetHashKey: &graphql.Field{
   939  					Type: graphql.NewNonNull(graphql.String),
   940  					Resolve: func(p graphql.ResolveParams) (interface{}, error) {
   941  						r := p.Source.(types.Ref)
   942  						return MaybeGetScalar(types.String(r.TargetHash().String())), nil
   943  					},
   944  				},
   945  
   946  				targetValueKey: &graphql.Field{
   947  					Type: targetType,
   948  					Resolve: func(p graphql.ResolveParams) (interface{}, error) {
   949  						r := p.Source.(types.Ref)
   950  						return MaybeGetScalar(r.TargetValue(p.Context.Value(vrwKey).(types.ValueReader))), nil
   951  					},
   952  				},
   953  			}
   954  		}),
   955  	})
   956  }
   957  
   958  func MaybeGetScalar(v types.Value) interface{} {
   959  	switch v.(type) {
   960  	case types.Bool:
   961  		return bool(v.(types.Bool))
   962  	case types.Number:
   963  		return float64(v.(types.Number))
   964  	case types.String:
   965  		return string(v.(types.String))
   966  	case *types.Type, types.Blob:
   967  		// TODO: https://github.com/ndau/noms/issues/3155
   968  		return v.Hash()
   969  	}
   970  
   971  	return v
   972  }
   973  
   974  // InputToNomsValue converts a GraphQL input value (as used in arguments and
   975  // variables) to a Noms value.
   976  func InputToNomsValue(vrw types.ValueReadWriter, arg interface{}, nomsType *types.Type) types.Value {
   977  	switch nomsType.TargetKind() {
   978  	case types.BoolKind:
   979  		return types.Bool(arg.(bool))
   980  	case types.NumberKind:
   981  		if i, ok := arg.(int); ok {
   982  			return types.Number(i)
   983  		}
   984  		return types.Number(arg.(float64))
   985  	case types.StringKind:
   986  		return types.String(arg.(string))
   987  	case types.ListKind, types.SetKind:
   988  		elemType := nomsType.Desc.(types.CompoundDesc).ElemTypes[0]
   989  		sl := arg.([]interface{})
   990  		vs := make(types.ValueSlice, len(sl))
   991  		for i, v := range sl {
   992  			vs[i] = InputToNomsValue(vrw, v, elemType)
   993  		}
   994  		if nomsType.TargetKind() == types.ListKind {
   995  			return types.NewList(vrw, vs...)
   996  		}
   997  		return types.NewSet(vrw, vs...)
   998  	case types.MapKind:
   999  		// Maps are passed as [{key: K, value: V}, ...]
  1000  		keyType := nomsType.Desc.(types.CompoundDesc).ElemTypes[0]
  1001  		valType := nomsType.Desc.(types.CompoundDesc).ElemTypes[1]
  1002  		sl := arg.([]interface{})
  1003  		kvs := make(types.ValueSlice, 2*len(sl))
  1004  		for i, v := range sl {
  1005  			v := v.(map[string]interface{})
  1006  			kvs[2*i] = InputToNomsValue(vrw, v["key"], keyType)
  1007  			kvs[2*i+1] = InputToNomsValue(vrw, v["value"], valType)
  1008  		}
  1009  		return types.NewMap(vrw, kvs...)
  1010  	case types.StructKind:
  1011  		desc := nomsType.Desc.(types.StructDesc)
  1012  		data := make(types.StructData, desc.Len())
  1013  		m := arg.(map[string]interface{})
  1014  		desc.IterFields(func(name string, t *types.Type, optional bool) {
  1015  			if m[name] != nil || !optional {
  1016  				data[name] = InputToNomsValue(vrw, m[name], t)
  1017  			}
  1018  		})
  1019  		return types.NewStruct(desc.Name, data)
  1020  	}
  1021  	panic("not yet implemented")
  1022  }
  1023  
  1024  type mapIteratorForKeys struct {
  1025  	m    types.Map
  1026  	keys types.ValueSlice
  1027  	idx  int
  1028  }
  1029  
  1030  func (it *mapIteratorForKeys) Valid() bool {
  1031  	return it.idx < len(it.keys)
  1032  }
  1033  
  1034  func (it *mapIteratorForKeys) Entry() (k, v types.Value) {
  1035  	if it.idx >= len(it.keys) {
  1036  		return
  1037  	}
  1038  	k = it.keys[it.idx]
  1039  	v = it.m.Get(k)
  1040  	return
  1041  }
  1042  
  1043  func (it *mapIteratorForKeys) Next() bool {
  1044  	it.idx++
  1045  	return it.Valid()
  1046  }
  1047  
  1048  type setFirstIterator struct {
  1049  	s types.Set
  1050  }
  1051  
  1052  func (it *setFirstIterator) Next() types.Value {
  1053  	return it.s.First()
  1054  }
  1055  
  1056  func (it *setFirstIterator) SkipTo(v types.Value) types.Value {
  1057  	panic("not implemented")
  1058  }
  1059  
  1060  type mapFirstIterator struct {
  1061  	m *types.Map
  1062  }
  1063  
  1064  func (it *mapFirstIterator) Valid() bool {
  1065  	return it.m != nil && !it.m.Empty()
  1066  }
  1067  
  1068  func (it *mapFirstIterator) Entry() (types.Value, types.Value) {
  1069  	if it.m == nil {
  1070  		return nil, nil
  1071  	}
  1072  	k, v := it.m.First()
  1073  	it.m = nil
  1074  	return k, v
  1075  }
  1076  
  1077  func (it *mapFirstIterator) Next() bool {
  1078  	return false
  1079  }