github.com/attic-labs/noms@v0.0.0-20210827224422-e5fa29d95e8b/go/ngql/query_test.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  	"bytes"
     9  	"encoding/json"
    10  	"errors"
    11  	"fmt"
    12  	"testing"
    13  
    14  	"github.com/attic-labs/graphql"
    15  	"github.com/attic-labs/noms/go/chunks"
    16  	"github.com/attic-labs/noms/go/marshal"
    17  	"github.com/attic-labs/noms/go/types"
    18  	"github.com/attic-labs/noms/go/util/test"
    19  	"github.com/stretchr/testify/assert"
    20  	"github.com/stretchr/testify/suite"
    21  )
    22  
    23  type QueryGraphQLSuite struct {
    24  	suite.Suite
    25  	vs *types.ValueStore
    26  }
    27  
    28  func TestQueryGraphQL(t *testing.T) {
    29  	suite.Run(t, &QueryGraphQLSuite{})
    30  }
    31  
    32  func newTestValueStore() *types.ValueStore {
    33  	storage := &chunks.MemoryStorage{}
    34  	return types.NewValueStore(storage.NewView())
    35  }
    36  
    37  func (suite *QueryGraphQLSuite) SetupTest() {
    38  	suite.vs = newTestValueStore()
    39  }
    40  
    41  func (suite *QueryGraphQLSuite) assertQueryResult(v types.Value, q, expect string) {
    42  	buf := &bytes.Buffer{}
    43  	Query(v, q, suite.vs, buf)
    44  	suite.JSONEq(test.RemoveHashes(expect), test.RemoveHashes(buf.String()))
    45  }
    46  
    47  func (suite *QueryGraphQLSuite) TestScalars() {
    48  	suite.assertQueryResult(types.String("aaa"), "{root}", `{"data":{"root":"aaa"}}`)
    49  	suite.assertQueryResult(types.String(""), "{root}", `{"data":{"root":""}}`)
    50  
    51  	suite.assertQueryResult(types.Number(0), "{root}", `{"data":{"root":0}}`)
    52  	suite.assertQueryResult(types.Number(1), "{root}", `{"data":{"root":1}}`)
    53  	suite.assertQueryResult(types.Number(-1), "{root}", `{"data":{"root":-1}}`)
    54  	suite.assertQueryResult(types.Number(1<<31), "{root}", `{"data":{"root":2.147483648e+09}}`)
    55  	suite.assertQueryResult(types.Number(-(1 << 31)), "{root}", `{"data":{"root":-2.147483648e+09}}`)
    56  	suite.assertQueryResult(types.Number(0.001), "{root}", `{"data":{"root":0.001}}`)
    57  	suite.assertQueryResult(types.Number(0.00000001), "{root}", `{"data":{"root":1e-08}}`)
    58  
    59  	suite.assertQueryResult(types.Bool(false), "{root}", `{"data":{"root":false}}`)
    60  	suite.assertQueryResult(types.Bool(true), "{root}", `{"data":{"root":true}}`)
    61  }
    62  
    63  func (suite *QueryGraphQLSuite) TestStructBasic() {
    64  	s1 := types.NewStruct("Foo", types.StructData{
    65  		"a": types.String("aaa"),
    66  		"b": types.Bool(true),
    67  		"c": types.Number(0.1),
    68  	})
    69  
    70  	suite.assertQueryResult(s1, "{root{a}}", `{"data":{"root":{"a":"aaa"}}}`)
    71  	suite.assertQueryResult(s1, "{root{a b}}", `{"data":{"root":{"a":"aaa","b":true}}}`)
    72  	suite.assertQueryResult(s1, "{root{a b c}}", `{"data":{"root":{"a":"aaa","b":true,"c":0.1}}}`)
    73  	suite.assertQueryResult(s1, "{root{a c}}", `{"data":{"root":{"a":"aaa","c":0.1}}}`)
    74  }
    75  
    76  func (suite *QueryGraphQLSuite) TestEmptyStruct() {
    77  	s1 := types.NewStruct("", types.StructData{})
    78  
    79  	suite.assertQueryResult(s1, "{root{hash}}", `{"data":{"root":{"hash":"0123456789abcdefghijklmnopqrstuv"}}}`)
    80  }
    81  
    82  func (suite *QueryGraphQLSuite) TestEmbeddedStruct() {
    83  	s1 := types.NewStruct("Foo", types.StructData{
    84  		"a": types.String("aaa"),
    85  		"b": types.NewStruct("Bar", types.StructData{
    86  			"c": types.Bool(true),
    87  			"d": types.Number(0.1),
    88  		}),
    89  	})
    90  
    91  	suite.assertQueryResult(s1, "{root{a}}", `{"data":{"root":{"a":"aaa"}}}`)
    92  	suite.assertQueryResult(s1, "{root{a b {c}}}", `{"data":{"root":{"a":"aaa","b":{"c":true}}}}`)
    93  	suite.assertQueryResult(s1, "{root{a b {c d}}}", `{"data":{"root":{"a":"aaa","b":{"c":true,"d":0.1}}}}`)
    94  }
    95  
    96  func (suite *QueryGraphQLSuite) TestListBasic() {
    97  	for _, valuesKey := range []string{"elements", "values"} {
    98  		list := types.NewList(suite.vs)
    99  		suite.assertQueryResult(list, "{root{size}}", `{"data":{"root":{"size":0}}}`)
   100  		suite.assertQueryResult(list, "{root{"+valuesKey+"}}", `{"data":{"root":{}}}`)
   101  
   102  		list = types.NewList(suite.vs, types.String("foo"), types.String("bar"), types.String("baz"))
   103  
   104  		suite.assertQueryResult(list, "{root{"+valuesKey+"}}", `{"data":{"root":{"`+valuesKey+`":["foo","bar","baz"]}}}`)
   105  		suite.assertQueryResult(list, "{root{size}}", `{"data":{"root":{"size":3}}}`)
   106  		suite.assertQueryResult(list, "{root{"+valuesKey+"(at:1,count:2)}}", `{"data":{"root":{"`+valuesKey+`":["bar","baz"]}}}`)
   107  
   108  		list = types.NewList(suite.vs, types.Bool(true), types.Bool(false), types.Bool(false))
   109  
   110  		suite.assertQueryResult(list, "{root{"+valuesKey+"}}", `{"data":{"root":{"`+valuesKey+`":[true,false,false]}}}`)
   111  		suite.assertQueryResult(list, "{root{"+valuesKey+"(at:1,count:2)}}", `{"data":{"root":{"`+valuesKey+`":[false,false]}}}`)
   112  
   113  		list = types.NewList(suite.vs, types.Number(1), types.Number(1.1), types.Number(-100))
   114  
   115  		suite.assertQueryResult(list, "{root{"+valuesKey+"}}", `{"data":{"root":{"`+valuesKey+`":[1,1.1,-100]}}}`)
   116  		suite.assertQueryResult(list, "{root{"+valuesKey+"(at:1,count:2)}}", `{"data":{"root":{"`+valuesKey+`":[1.1,-100]}}}`)
   117  
   118  		list = types.NewList(suite.vs, types.String("a"), types.String("b"), types.String("c"))
   119  		suite.assertQueryResult(list, "{root{"+valuesKey+"(at:4)}}", `{"data":{"root":{"`+valuesKey+`":[]}}}`)
   120  		suite.assertQueryResult(list, "{root{"+valuesKey+"(count:0)}}", `{"data":{"root":{"`+valuesKey+`":[]}}}`)
   121  		suite.assertQueryResult(list, "{root{"+valuesKey+"(count:10)}}", `{"data":{"root":{"`+valuesKey+`":["a","b","c"]}}}`)
   122  		suite.assertQueryResult(list, "{root{"+valuesKey+"(at:-1)}}", `{"data":{"root":{"`+valuesKey+`":["a","b","c"]}}}`)
   123  	}
   124  }
   125  
   126  func (suite *QueryGraphQLSuite) TestListOfStruct() {
   127  	list := types.NewList(suite.vs,
   128  		types.NewStruct("Foo", types.StructData{
   129  			"a": types.Number(28),
   130  			"b": types.String("foo"),
   131  		}),
   132  		types.NewStruct("Foo", types.StructData{
   133  			"a": types.Number(-20.102),
   134  			"b": types.String("bar"),
   135  		}),
   136  		types.NewStruct("Foo", types.StructData{
   137  			"a": types.Number(5),
   138  			"b": types.String("baz"),
   139  		}),
   140  	)
   141  
   142  	suite.assertQueryResult(list, "{root{elements{a b}}}", `{"data":{"root":{"elements":[{"a":28,"b":"foo"},{"a":-20.102,"b":"bar"},{"a":5,"b":"baz"}]}}}`)
   143  
   144  	suite.assertQueryResult(list, "{root{elements{a}}}", `{"data":{"root":{"elements":[{"a":28},{"a":-20.102},{"a":5}]}}}`)
   145  }
   146  
   147  func (suite *QueryGraphQLSuite) TestListOfStructWithOptionalFields() {
   148  	list := types.NewList(suite.vs,
   149  		types.NewStruct("Foo", types.StructData{
   150  			"a": types.Number(1),
   151  		}),
   152  		types.NewStruct("Foo", types.StructData{
   153  			"a": types.Number(2),
   154  			"b": types.String("bar"),
   155  		}),
   156  	)
   157  
   158  	suite.assertQueryResult(list, "{root{elements{a b}}}", `{
   159                  "data": {
   160                          "root": {
   161                                  "elements": [
   162                                          {"a": 1, "b": null},
   163                                          {"a": 2, "b": "bar"}
   164                                  ]
   165                          }
   166                  }
   167          }`)
   168  }
   169  
   170  func (suite *QueryGraphQLSuite) TestSetBasic() {
   171  	for _, valuesKey := range []string{"elements", "values"} {
   172  		set := types.NewSet(suite.vs)
   173  		suite.assertQueryResult(set, "{root{size}}", `{"data":{"root":{"size":0}}}`)
   174  		suite.assertQueryResult(set, "{root{"+valuesKey+"}}", `{"data":{"root":{}}}`)
   175  
   176  		set = types.NewSet(suite.vs, types.String("foo"), types.String("bar"), types.String("baz"))
   177  
   178  		suite.assertQueryResult(set, "{root{"+valuesKey+"}}", `{"data":{"root":{"`+valuesKey+`":["bar","baz","foo"]}}}`)
   179  		suite.assertQueryResult(set, "{root{size}}", `{"data":{"root":{"size":3}}}`)
   180  		suite.assertQueryResult(set, "{root{"+valuesKey+"(count:2)}}", `{"data":{"root":{"`+valuesKey+`":["bar","baz"]}}}`)
   181  
   182  		set = types.NewSet(suite.vs, types.Bool(true), types.Bool(false))
   183  
   184  		suite.assertQueryResult(set, "{root{"+valuesKey+"}}", `{"data":{"root":{"`+valuesKey+`":[false,true]}}}`)
   185  		suite.assertQueryResult(set, "{root{"+valuesKey+"(count:1)}}", `{"data":{"root":{"`+valuesKey+`":[false]}}}`)
   186  
   187  		set = types.NewSet(suite.vs, types.Number(1), types.Number(1.1), types.Number(-100))
   188  
   189  		suite.assertQueryResult(set, "{root{"+valuesKey+"}}", `{"data":{"root":{"`+valuesKey+`":[-100,1,1.1]}}}`)
   190  		suite.assertQueryResult(set, "{root{"+valuesKey+"(count:2)}}", `{"data":{"root":{"`+valuesKey+`":[-100,1]}}}`)
   191  
   192  		set = types.NewSet(suite.vs, types.String("a"), types.String("b"), types.String("c"), types.String("d"))
   193  		suite.assertQueryResult(set, "{root{"+valuesKey+"(count:0)}}", `{"data":{"root":{"`+valuesKey+`":[]}}}`)
   194  		suite.assertQueryResult(set, "{root{"+valuesKey+"(count:2)}}", `{"data":{"root":{"`+valuesKey+`":["a","b"]}}}`)
   195  
   196  		suite.assertQueryResult(set, "{root{"+valuesKey+"(at:0,count:2)}}", `{"data":{"root":{"`+valuesKey+`":["a","b"]}}}`)
   197  		suite.assertQueryResult(set, "{root{"+valuesKey+"(at:-1,count:2)}}", `{"data":{"root":{"`+valuesKey+`":["a","b"]}}}`)
   198  		suite.assertQueryResult(set, "{root{"+valuesKey+"(at:1,count:2)}}", `{"data":{"root":{"`+valuesKey+`":["b","c"]}}}`)
   199  		suite.assertQueryResult(set, "{root{"+valuesKey+"(at:2)}}", `{"data":{"root":{"`+valuesKey+`":["c","d"]}}}`)
   200  		suite.assertQueryResult(set, "{root{"+valuesKey+"(at:2,count:1)}}", `{"data":{"root":{"`+valuesKey+`":["c"]}}}`)
   201  		suite.assertQueryResult(set, "{root{"+valuesKey+"(at:2,count:0)}}", `{"data":{"root":{"`+valuesKey+`":[]}}}`)
   202  		suite.assertQueryResult(set, "{root{"+valuesKey+"(at:2,count:10)}}", `{"data":{"root":{"`+valuesKey+`":["c","d"]}}}`)
   203  	}
   204  }
   205  
   206  func (suite *QueryGraphQLSuite) TestSetOfStruct() {
   207  	set := types.NewSet(suite.vs,
   208  		types.NewStruct("Foo", types.StructData{
   209  			"a": types.Number(28),
   210  			"b": types.String("foo"),
   211  		}),
   212  		types.NewStruct("Foo", types.StructData{
   213  			"a": types.Number(-20.102),
   214  			"b": types.String("bar"),
   215  		}),
   216  		types.NewStruct("Foo", types.StructData{
   217  			"a": types.Number(5),
   218  			"b": types.String("baz"),
   219  		}),
   220  	)
   221  
   222  	suite.assertQueryResult(set, "{root{values{a b}}}",
   223  		`{"data":{"root":{"values":[{"a":28,"b":"foo"},{"a":5,"b":"baz"},{"a":-20.102,"b":"bar"}]}}}`)
   224  	suite.assertQueryResult(set, "{root{values{a}}}", `{"data":{"root":{"values":[{"a":28},{"a":5},{"a":-20.102}]}}}`)
   225  }
   226  
   227  func (suite *QueryGraphQLSuite) TestMapBasic() {
   228  	for _, entriesKey := range []string{"elements", "entries"} {
   229  
   230  		m := types.NewMap(suite.vs)
   231  		suite.assertQueryResult(m, "{root{size}}", `{"data":{"root":{"size":0}}}`)
   232  		suite.assertQueryResult(m, "{root{"+entriesKey+"}}", `{"data":{"root":{}}}`)
   233  
   234  		m = types.NewMap(suite.vs,
   235  			types.String("a"), types.Number(1),
   236  			types.String("b"), types.Number(2),
   237  			types.String("c"), types.Number(3),
   238  			types.String("d"), types.Number(4),
   239  		)
   240  
   241  		suite.assertQueryResult(m, "{root{"+entriesKey+"{key value}}}", `{"data":{"root":{"`+entriesKey+`":[{"key":"a","value":1},{"key":"b","value":2},{"key":"c","value":3},{"key":"d","value":4}]}}}`)
   242  		suite.assertQueryResult(m, "{root{size}}", `{"data":{"root":{"size":4}}}`)
   243  	}
   244  }
   245  
   246  func (suite *QueryGraphQLSuite) TestMapOfStruct() {
   247  	m := types.NewMap(suite.vs,
   248  		types.String("foo"), types.NewStruct("Foo", types.StructData{
   249  			"a": types.Number(28),
   250  			"b": types.String("foo"),
   251  		}),
   252  		types.String("bar"), types.NewStruct("Foo", types.StructData{
   253  			"a": types.Number(-20.102),
   254  			"b": types.String("bar"),
   255  		}),
   256  		types.String("baz"), types.NewStruct("Foo", types.StructData{
   257  			"a": types.Number(5),
   258  			"b": types.String("baz"),
   259  		}),
   260  	)
   261  
   262  	suite.assertQueryResult(m, "{root{entries{key value{a}}}}", `{"data":{"root":{"entries":[{"key":"bar","value":{"a":-20.102}},{"key":"baz","value":{"a":5}},{"key":"foo","value":{"a":28}}]}}}`)
   263  	suite.assertQueryResult(m, "{root{entries(count:1){value{a b}}}}", `{"data":{"root":{"entries":[{"value":{"a":-20.102,"b":"bar"}}]}}}`)
   264  	suite.assertQueryResult(m, "{root{entries(count:3){key}}}", `{"data":{"root":{"entries":[{"key":"bar"},{"key":"baz"},{"key":"foo"}]}}}`)
   265  }
   266  
   267  func (suite *QueryGraphQLSuite) TestRef() {
   268  	r := suite.vs.WriteValue(types.Number(100))
   269  
   270  	suite.assertQueryResult(r, "{root{targetValue}}", `{"data":{"root":{"targetValue":100}}}`)
   271  	suite.assertQueryResult(r, "{root{targetHash}}", `{"data":{"root":{"targetHash":"0123456789abcdefghijklmnopqrstuv"}}}`)
   272  	suite.assertQueryResult(r, "{root{targetValue targetHash}}", `{"data":{"root":{"targetHash":"0123456789abcdefghijklmnopqrstuv","targetValue":100}}}`)
   273  
   274  	r = suite.vs.WriteValue(types.NewStruct("Foo", types.StructData{
   275  		"a": types.Number(28),
   276  		"b": types.String("foo"),
   277  	}))
   278  
   279  	suite.assertQueryResult(r, "{root{targetValue{a}}}", `{"data":{"root":{"targetValue":{"a":28}}}}`)
   280  	suite.assertQueryResult(r, "{root{targetValue{a b}}}", `{"data":{"root":{"targetValue":{"a":28,"b":"foo"}}}}`)
   281  
   282  	r = suite.vs.WriteValue(types.NewList(suite.vs, types.String("foo"), types.String("bar"), types.String("baz")))
   283  
   284  	suite.assertQueryResult(r, "{root{targetValue{values}}}", `{"data":{"root":{"targetValue":{"values":["foo","bar","baz"]}}}}`)
   285  	suite.assertQueryResult(r, "{root{targetValue{values(at:1,count:2)}}}", `{"data":{"root":{"targetValue":{"values":["bar","baz"]}}}}`)
   286  }
   287  
   288  func (suite *QueryGraphQLSuite) TestListOfUnionOfStructs() {
   289  	list := types.NewList(suite.vs,
   290  		types.NewStruct("Foo", types.StructData{
   291  			"a": types.Number(28),
   292  			"b": types.String("baz"),
   293  		}),
   294  		types.NewStruct("Bar", types.StructData{
   295  			"b": types.String("bar"),
   296  		}),
   297  		types.NewStruct("Baz", types.StructData{
   298  			"c": types.Bool(true),
   299  		}),
   300  	)
   301  
   302  	suite.assertQueryResult(list,
   303  		fmt.Sprintf("{root{values{... on %s{a b} ... on %s{b} ... on %s{c}}}}",
   304  			GetTypeName(types.TypeOf(list.Get(0))),
   305  			GetTypeName(types.TypeOf(list.Get(1))),
   306  			GetTypeName(types.TypeOf(list.Get(2)))),
   307  		`{"data":{"root":{"values":[{"a":28,"b":"baz"},{"b":"bar"},{"c":true}]}}}`)
   308  }
   309  
   310  func (suite *QueryGraphQLSuite) TestListOfUnionOfStructsConflictingFieldTypes() {
   311  	list := types.NewList(suite.vs,
   312  		types.NewStruct("Foo", types.StructData{
   313  			"a": types.Number(28),
   314  		}),
   315  		types.NewStruct("Bar", types.StructData{
   316  			"a": types.String("bar"),
   317  		}),
   318  		types.NewStruct("Baz", types.StructData{
   319  			"a": types.Bool(true),
   320  		}),
   321  	)
   322  
   323  	suite.assertQueryResult(list,
   324  		fmt.Sprintf("{root{values{... on %s{a} ... on %s{b: a} ... on %s{c: a}}}}",
   325  			GetTypeName(types.TypeOf(list.Get(0))),
   326  			GetTypeName(types.TypeOf(list.Get(1))),
   327  			GetTypeName(types.TypeOf(list.Get(2)))),
   328  		`{"data":{"root":{"values":[{"a":28},{"b":"bar"},{"c":true}]}}}`)
   329  }
   330  
   331  func (suite *QueryGraphQLSuite) TestListOfUnionOfScalars() {
   332  	list := types.NewList(suite.vs,
   333  		types.Number(28),
   334  		types.String("bar"),
   335  		types.Bool(true),
   336  	)
   337  
   338  	suite.assertQueryResult(list, "{root{values{... on BooleanValue{b: scalarValue} ... on StringValue{s: scalarValue} ... on NumberValue{n: scalarValue}}}}", `{"data":{"root":{"values":[{"n":28},{"s":"bar"},{"b":true}]}}}`)
   339  }
   340  
   341  func (suite *QueryGraphQLSuite) TestCyclicStructs() {
   342  	// struct A {
   343  	//  a: "aaa"
   344  	//  b: Set(struct A {
   345  	// 	 a: "bbb"
   346  	// 	 b: Set()
   347  	//  })
   348  	// }
   349  
   350  	s1 := types.NewStruct("A", types.StructData{
   351  		"a": types.String("aaa"),
   352  		"b": types.NewSet(suite.vs,
   353  			types.NewStruct("A", types.StructData{
   354  				"a": types.String("bbb"),
   355  				"b": types.NewSet(suite.vs),
   356  			})),
   357  	})
   358  
   359  	suite.assertQueryResult(s1, "{root{a b{values{a}}}}", `{"data":{"root":{"a":"aaa","b":{"values":[{"a":"bbb"}]}}}}`)
   360  }
   361  
   362  func (suite *QueryGraphQLSuite) TestCyclicStructsWithUnion() {
   363  	// struct A {
   364  	//  a: "aaa"
   365  	//  b: Struct A {
   366  	// 	 a: "bbb"
   367  	// 	 b: 42
   368  	//  })
   369  	// }
   370  
   371  	// struct A {
   372  	//   a: String,
   373  	//   b: Number | Cycle<A>,
   374  	// }
   375  
   376  	s1 := types.NewStruct("A", types.StructData{
   377  		"a": types.String("aaa"),
   378  		"b": types.NewStruct("A", types.StructData{
   379  			"a": types.String("bbb"),
   380  			"b": types.Number(42),
   381  		}),
   382  	})
   383  
   384  	suite.assertQueryResult(s1,
   385  		`{
   386                          root{
   387                                  a
   388                                  b {
   389                                          a
   390                                          b {
   391                                                  scalarValue
   392                                          }
   393                                  }
   394                          }
   395                  }
   396                  `,
   397  		`{
   398                          "data": {
   399                                  "root": {
   400                                          "a": "aaa",
   401                                          "b": {
   402                                                  "a": "bbb",
   403                                                  "b": {
   404                                                          "scalarValue": 42
   405                                                  }
   406                                          }
   407                                  }
   408                          }
   409                  }`)
   410  
   411  	suite.assertQueryResult(s1,
   412  		fmt.Sprintf(`{
   413  	                root{
   414  	                        a
   415  	                        b {
   416  	                                ... on %s {
   417  	                                        a
   418  	                                }
   419  	                        }
   420  	                }
   421  	        }`, GetTypeName(types.TypeOf(s1))),
   422  		`{
   423  	                "data": {
   424  	                        "root": {
   425  	                                "a": "aaa",
   426  	                                "b": {
   427  	                                        "a": "bbb"
   428  	                                }
   429  	                        }
   430  	                }
   431  	        }`)
   432  }
   433  
   434  func (suite *QueryGraphQLSuite) TestNestedCollection() {
   435  	list := types.NewList(suite.vs,
   436  		types.NewSet(suite.vs,
   437  			types.NewMap(suite.vs, types.Number(10), types.String("foo")),
   438  			types.NewMap(suite.vs, types.Number(20), types.String("bar")),
   439  		),
   440  		types.NewSet(suite.vs,
   441  			types.NewMap(suite.vs, types.Number(30), types.String("baz")),
   442  			types.NewMap(suite.vs, types.Number(40), types.String("bat")),
   443  		),
   444  	)
   445  
   446  	suite.assertQueryResult(list, "{root{size}}", `{"data":{"root":{"size":2}}}`)
   447  	suite.assertQueryResult(list, "{root{values(count:1){size}}}", `{"data":{"root":{"values":[{"size":2}]}}}`)
   448  	suite.assertQueryResult(list, "{root{values(at:1,count:1){values(count:1){entries{key value}}}}}",
   449  		`{"data":{"root":{"values":[{"values":[{"entries":[{"key":40,"value":"bat"}]}]}]}}}`)
   450  }
   451  
   452  func (suite *QueryGraphQLSuite) TestLoFi() {
   453  	b := types.NewBlob(suite.vs, bytes.NewBufferString("I am a blob"))
   454  
   455  	suite.assertQueryResult(b, "{root}", `{"data":{"root":"0123456789abcdefghijklmnopqrstuv"}}`)
   456  
   457  	t := types.StringType
   458  	suite.assertQueryResult(t, "{root}", `{"data":{"root":"0123456789abcdefghijklmnopqrstuv"}}`)
   459  }
   460  
   461  func (suite *QueryGraphQLSuite) TestError() {
   462  	buff := &bytes.Buffer{}
   463  	Error(errors.New("Some error string"), buff)
   464  	suite.Equal(buff.String(), `{"data":null,"errors":[{"message":"Some error string","locations":null}]}
   465  `)
   466  }
   467  
   468  func (suite *QueryGraphQLSuite) TestMapArgs() {
   469  	for _, entriesKey := range []string{"elements", "entries"} {
   470  
   471  		m := types.NewMap(suite.vs,
   472  			types.String("a"), types.Number(1),
   473  			types.String("c"), types.Number(2),
   474  			types.String("e"), types.Number(3),
   475  			types.String("g"), types.Number(4),
   476  		)
   477  
   478  		// count
   479  		suite.assertQueryResult(m, "{root{"+entriesKey+"(count:0){value}}}", `{"data":{"root":{"`+entriesKey+`":[]}}}`)
   480  		suite.assertQueryResult(m, "{root{"+entriesKey+"(count:2){value}}}", `{"data":{"root":{"`+entriesKey+`":[{"value":1},{"value":2}]}}}`)
   481  		suite.assertQueryResult(m, "{root{"+entriesKey+"(count:3){key}}}", `{"data":{"root":{"`+entriesKey+`":[{"key":"a"},{"key":"c"},{"key":"e"}]}}}`)
   482  		suite.assertQueryResult(m, "{root{"+entriesKey+"(count: -1){key}}}", `{"data":{"root":{"`+entriesKey+`":[]}}}`)
   483  		suite.assertQueryResult(m, "{root{"+entriesKey+"(count:5){value}}}", `{"data":{"root":{"`+entriesKey+`":[{"value":1},{"value":2},{"value":3},{"value":4}]}}}`)
   484  
   485  		// at
   486  		suite.assertQueryResult(m, "{root{"+entriesKey+"(at:0){value}}}", `{"data":{"root":{"`+entriesKey+`":[{"value":1},{"value":2},{"value":3},{"value":4}]}}}`)
   487  		suite.assertQueryResult(m, "{root{"+entriesKey+"(at:-1){value}}}", `{"data":{"root":{"`+entriesKey+`":[{"value":1},{"value":2},{"value":3},{"value":4}]}}}`)
   488  		suite.assertQueryResult(m, "{root{"+entriesKey+"(at:2){value}}}", `{"data":{"root":{"`+entriesKey+`":[{"value":3},{"value":4}]}}}`)
   489  		suite.assertQueryResult(m, "{root{"+entriesKey+"(at:5){value}}}", `{"data":{"root":{"`+entriesKey+`":[]}}}`)
   490  
   491  		// at & count
   492  		suite.assertQueryResult(m, "{root{"+entriesKey+"(at:0,count:2){value}}}", `{"data":{"root":{"`+entriesKey+`":[{"value":1},{"value":2}]}}}`)
   493  		suite.assertQueryResult(m, "{root{"+entriesKey+"(at:-1,count:2){value}}}", `{"data":{"root":{"`+entriesKey+`":[{"value":1},{"value":2}]}}}`)
   494  		suite.assertQueryResult(m, "{root{"+entriesKey+"(at:1,count:2){value}}}", `{"data":{"root":{"`+entriesKey+`":[{"value":2},{"value":3}]}}}`)
   495  		suite.assertQueryResult(m, "{root{"+entriesKey+"(at:2,count:1){value}}}", `{"data":{"root":{"`+entriesKey+`":[{"value":3}]}}}`)
   496  		suite.assertQueryResult(m, "{root{"+entriesKey+"(at:2,count:0){value}}}", `{"data":{"root":{"`+entriesKey+`":[]}}}`)
   497  		suite.assertQueryResult(m, "{root{"+entriesKey+"(at:2,count:10){value}}}", `{"data":{"root":{"`+entriesKey+`":[{"value":3},{"value":4}]}}}`)
   498  
   499  		// key
   500  		suite.assertQueryResult(m, `{root{`+entriesKey+`(key:"e"){key value}}}`,
   501  			`{"data":{"root":{"`+entriesKey+`":[{"key":"e","value":3}]}}}`)
   502  		suite.assertQueryResult(m, `{root{`+entriesKey+`(key:"g"){value}}}`,
   503  			`{"data":{"root":{"`+entriesKey+`":[{"value":4}]}}}`)
   504  		// "f", no count/through so asking for exact match
   505  		suite.assertQueryResult(m, `{root{`+entriesKey+`(key:"f"){value}}}`,
   506  			`{"data":{"root":{"`+entriesKey+`":[]}}}`)
   507  		// "x" is larger than end
   508  		suite.assertQueryResult(m, `{root{`+entriesKey+`(key:"x"){value}}}`,
   509  			`{"data":{"root":{"`+entriesKey+`":[]}}}`)
   510  
   511  		// key & at
   512  		// at is ignored when key is present
   513  		suite.assertQueryResult(m, `{root{`+entriesKey+`(key:"e",at:2){key value}}}`,
   514  			`{"data":{"root":{"`+entriesKey+`":[{"key":"e","value":3}]}}}`)
   515  
   516  		// key & count
   517  		suite.assertQueryResult(m, `{root{`+entriesKey+`(key:"c", count: 2){key value}}}`,
   518  			`{"data":{"root":{"`+entriesKey+`":[{"key":"c","value":2},{"key":"e","value":3}]}}}`)
   519  		suite.assertQueryResult(m, `{root{`+entriesKey+`(key:"c", count: 0){key value}}}`,
   520  			`{"data":{"root":{"`+entriesKey+`":[]}}}`)
   521  		suite.assertQueryResult(m, `{root{`+entriesKey+`(key:"c", count: -1){key value}}}`,
   522  			`{"data":{"root":{"`+entriesKey+`":[]}}}`)
   523  		suite.assertQueryResult(m, `{root{`+entriesKey+`(key:"e", count: 5){key value}}}`,
   524  			`{"data":{"root":{"`+entriesKey+`":[{"key":"e","value":3},{"key":"g","value":4}]}}}`)
   525  
   526  		// through
   527  		suite.assertQueryResult(m, `{root{`+entriesKey+`(through:"c"){key}}}`,
   528  			`{"data":{"root":{"`+entriesKey+`":[{"key":"a"},{"key":"c"}]}}}`)
   529  		suite.assertQueryResult(m, `{root{`+entriesKey+`(through:"b"){key}}}`,
   530  			`{"data":{"root":{"`+entriesKey+`":[{"key":"a"}]}}}`)
   531  		suite.assertQueryResult(m, `{root{`+entriesKey+`(through:"0"){key}}}`,
   532  			`{"data":{"root":{"`+entriesKey+`":[]}}}`)
   533  
   534  		// key & through
   535  		suite.assertQueryResult(m, `{root{`+entriesKey+`(key:"c", through:"c"){key}}}`,
   536  			`{"data":{"root":{"`+entriesKey+`":[{"key":"c"}]}}}`)
   537  		suite.assertQueryResult(m, `{root{`+entriesKey+`(key:"c",through:"e"){key}}}`,
   538  			`{"data":{"root":{"`+entriesKey+`":[{"key":"c"},{"key":"e"}]}}}`)
   539  
   540  		// through & count
   541  		suite.assertQueryResult(m, `{root{`+entriesKey+`(through:"c",count:1){key}}}`,
   542  			`{"data":{"root":{"`+entriesKey+`":[{"key":"a"}]}}}`)
   543  		suite.assertQueryResult(m, `{root{`+entriesKey+`(through:"b",count:0){key}}}`,
   544  			`{"data":{"root":{"`+entriesKey+`":[]}}}`)
   545  		suite.assertQueryResult(m, `{root{`+entriesKey+`(through:"0",count:10){key}}}`,
   546  			`{"data":{"root":{"`+entriesKey+`":[]}}}`)
   547  
   548  		// at & through
   549  		suite.assertQueryResult(m, `{root{`+entriesKey+`(at:0,through:"a"){key}}}`,
   550  			`{"data":{"root":{"`+entriesKey+`":[{"key":"a"}]}}}`)
   551  		suite.assertQueryResult(m, `{root{`+entriesKey+`(at:1,through:"e"){key}}}`,
   552  			`{"data":{"root":{"`+entriesKey+`":[{"key":"c"},{"key":"e"}]}}}`)
   553  
   554  		// at & count & through
   555  		suite.assertQueryResult(m, `{root{`+entriesKey+`(at:0,count:2,through:"a"){key}}}`,
   556  			`{"data":{"root":{"`+entriesKey+`":[{"key":"a"}]}}}`)
   557  		suite.assertQueryResult(m, `{root{`+entriesKey+`(at:0,count:2,through:"e"){key}}}`,
   558  			`{"data":{"root":{"`+entriesKey+`":[{"key":"a"},{"key":"c"}]}}}`)
   559  
   560  		// key & count & through
   561  		suite.assertQueryResult(m, `{root{`+entriesKey+`(key:"c",count:2,through:"c"){key}}}`,
   562  			`{"data":{"root":{"`+entriesKey+`":[{"key":"c"}]}}}`)
   563  		suite.assertQueryResult(m, `{root{`+entriesKey+`(key:"c",count:2,through:"g"){key}}}`,
   564  			`{"data":{"root":{"`+entriesKey+`":[{"key":"c"},{"key":"e"}]}}}`)
   565  	}
   566  }
   567  
   568  func (suite *QueryGraphQLSuite) TestMapKeysArg() {
   569  	for _, entriesKey := range []string{"elements", "entries"} {
   570  		m := types.NewMap(suite.vs,
   571  			types.String("a"), types.Number(1),
   572  			types.String("c"), types.Number(2),
   573  			types.String("e"), types.Number(3),
   574  			types.String("g"), types.Number(4),
   575  		)
   576  		suite.assertQueryResult(m, `{root{`+entriesKey+`(keys:["c","a"]){value}}}`,
   577  			`{"data":{"root":{"`+entriesKey+`":[{"value":2},{"value":1}]}}}`)
   578  		suite.assertQueryResult(m, `{root{`+entriesKey+`(keys:[]){value}}}`,
   579  			`{"data":{"root":{"`+entriesKey+`":[]}}}`)
   580  
   581  		m = types.NewMap(suite.vs,
   582  			types.Number(1), types.String("a"),
   583  			types.Number(2), types.String("c"),
   584  			types.Number(3), types.String("e"),
   585  			types.Number(4), types.String("g"),
   586  		)
   587  		suite.assertQueryResult(m, `{root{`+entriesKey+`(keys:[4,1]){value}}}`,
   588  			`{"data":{"root":{"`+entriesKey+`":[{"value":"g"},{"value":"a"}]}}}`)
   589  
   590  		// Ignore other args
   591  		suite.assertQueryResult(m, `{root{`+entriesKey+`(keys:[4,1],key:2){value}}}`,
   592  			`{"data":{"root":{"`+entriesKey+`":[{"value":"g"},{"value":"a"}]}}}`)
   593  		suite.assertQueryResult(m, `{root{`+entriesKey+`(keys:[4,1],count:0){value}}}`,
   594  			`{"data":{"root":{"`+entriesKey+`":[{"value":"g"},{"value":"a"}]}}}`)
   595  		suite.assertQueryResult(m, `{root{`+entriesKey+`(keys:[4,1],at:4){value}}}`,
   596  			`{"data":{"root":{"`+entriesKey+`":[{"value":"g"},{"value":"a"}]}}}`)
   597  		suite.assertQueryResult(m, `{root{`+entriesKey+`(keys:[4,1],through:1){value}}}`,
   598  			`{"data":{"root":{"`+entriesKey+`":[{"value":"g"},{"value":"a"}]}}}`)
   599  	}
   600  }
   601  
   602  func (suite *QueryGraphQLSuite) TestSetArgs() {
   603  	for _, valuesKey := range []string{"elements", "values"} {
   604  		s := types.NewSet(suite.vs,
   605  			types.String("a"),
   606  			types.String("c"),
   607  			types.String("e"),
   608  			types.String("g"),
   609  		)
   610  
   611  		// count
   612  		suite.assertQueryResult(s, "{root{"+valuesKey+"(count:0)}}", `{"data":{"root":{"`+valuesKey+`":[]}}}`)
   613  		suite.assertQueryResult(s, "{root{"+valuesKey+"(count:2)}}", `{"data":{"root":{"`+valuesKey+`":["a","c"]}}}`)
   614  		suite.assertQueryResult(s, "{root{"+valuesKey+"(count:3)}}", `{"data":{"root":{"`+valuesKey+`":["a","c","e"]}}}`)
   615  		suite.assertQueryResult(s, "{root{"+valuesKey+"(count: -1)}}", `{"data":{"root":{"`+valuesKey+`":[]}}}`)
   616  		suite.assertQueryResult(s, "{root{"+valuesKey+"(count:5)}}", `{"data":{"root":{"`+valuesKey+`":["a","c","e","g"]}}}`)
   617  
   618  		// at
   619  		suite.assertQueryResult(s, "{root{"+valuesKey+"(at:0)}}", `{"data":{"root":{"`+valuesKey+`":["a","c","e","g"]}}}`)
   620  		suite.assertQueryResult(s, "{root{"+valuesKey+"(at:-1)}}", `{"data":{"root":{"`+valuesKey+`":["a","c","e","g"]}}}`)
   621  		suite.assertQueryResult(s, "{root{"+valuesKey+"(at:2)}}", `{"data":{"root":{"`+valuesKey+`":["e","g"]}}}`)
   622  		suite.assertQueryResult(s, "{root{"+valuesKey+"(at:5)}}", `{"data":{"root":{"`+valuesKey+`":[]}}}`)
   623  
   624  		// at & count
   625  		suite.assertQueryResult(s, "{root{"+valuesKey+"(at:0,count:2)}}", `{"data":{"root":{"`+valuesKey+`":["a","c"]}}}`)
   626  		suite.assertQueryResult(s, "{root{"+valuesKey+"(at:-1,count:2)}}", `{"data":{"root":{"`+valuesKey+`":["a","c"]}}}`)
   627  		suite.assertQueryResult(s, "{root{"+valuesKey+"(at:1,count:2)}}", `{"data":{"root":{"`+valuesKey+`":["c","e"]}}}`)
   628  		suite.assertQueryResult(s, "{root{"+valuesKey+"(at:2,count:1)}}", `{"data":{"root":{"`+valuesKey+`":["e"]}}}`)
   629  		suite.assertQueryResult(s, "{root{"+valuesKey+"(at:2,count:0)}}", `{"data":{"root":{"`+valuesKey+`":[]}}}`)
   630  		suite.assertQueryResult(s, "{root{"+valuesKey+"(at:2,count:10)}}", `{"data":{"root":{"`+valuesKey+`":["e","g"]}}}`)
   631  
   632  		// key
   633  		suite.assertQueryResult(s, `{root{`+valuesKey+`(key:"e")}}`,
   634  			`{"data":{"root":{"`+valuesKey+`":["e"]}}}`)
   635  		suite.assertQueryResult(s, `{root{`+valuesKey+`(key:"g")}}`,
   636  			`{"data":{"root":{"`+valuesKey+`":["g"]}}}`)
   637  		// "f", no count/through so asking for exact match
   638  		suite.assertQueryResult(s, `{root{`+valuesKey+`(key:"f")}}`,
   639  			`{"data":{"root":{"`+valuesKey+`":[]}}}`)
   640  		// "x" is larger than end
   641  		suite.assertQueryResult(s, `{root{`+valuesKey+`(key:"x")}}`,
   642  			`{"data":{"root":{"`+valuesKey+`":[]}}}`)
   643  		// exact match
   644  		suite.assertQueryResult(s, `{root{`+valuesKey+`(key:"0")}}`,
   645  			`{"data":{"root":{"`+valuesKey+`":[]}}}`)
   646  
   647  		// key & at
   648  		// at is ignored when key is present
   649  		suite.assertQueryResult(s, `{root{`+valuesKey+`(key:"e",at:2)}}`,
   650  			`{"data":{"root":{"`+valuesKey+`":["e"]}}}`)
   651  
   652  		// key & count
   653  		suite.assertQueryResult(s, `{root{`+valuesKey+`(key:"c", count: 2)}}`,
   654  			`{"data":{"root":{"`+valuesKey+`":["c","e"]}}}`)
   655  		suite.assertQueryResult(s, `{root{`+valuesKey+`(key:"c", count: 0)}}`,
   656  			`{"data":{"root":{"`+valuesKey+`":[]}}}`)
   657  		suite.assertQueryResult(s, `{root{`+valuesKey+`(key:"c", count: -1)}}`,
   658  			`{"data":{"root":{"`+valuesKey+`":[]}}}`)
   659  		suite.assertQueryResult(s, `{root{`+valuesKey+`(key:"e", count: 5)}}`,
   660  			`{"data":{"root":{"`+valuesKey+`":["e","g"]}}}`)
   661  
   662  		// through
   663  		suite.assertQueryResult(s, `{root{`+valuesKey+`(through:"c")}}`,
   664  			`{"data":{"root":{"`+valuesKey+`":["a","c"]}}}`)
   665  		suite.assertQueryResult(s, `{root{`+valuesKey+`(through:"b")}}`,
   666  			`{"data":{"root":{"`+valuesKey+`":["a"]}}}`)
   667  		suite.assertQueryResult(s, `{root{`+valuesKey+`(through:"0")}}`,
   668  			`{"data":{"root":{"`+valuesKey+`":[]}}}`)
   669  
   670  		// key & through
   671  		suite.assertQueryResult(s, `{root{`+valuesKey+`(key:"c", through:"c")}}`,
   672  			`{"data":{"root":{"`+valuesKey+`":["c"]}}}`)
   673  		suite.assertQueryResult(s, `{root{`+valuesKey+`(key:"c",through:"e")}}`,
   674  			`{"data":{"root":{"`+valuesKey+`":["c","e"]}}}`)
   675  
   676  		// through & count
   677  		suite.assertQueryResult(s, `{root{`+valuesKey+`(through:"c",count:1)}}`,
   678  			`{"data":{"root":{"`+valuesKey+`":["a"]}}}`)
   679  		suite.assertQueryResult(s, `{root{`+valuesKey+`(through:"b",count:0)}}`,
   680  			`{"data":{"root":{"`+valuesKey+`":[]}}}`)
   681  		suite.assertQueryResult(s, `{root{`+valuesKey+`(through:"0",count:10)}}`,
   682  			`{"data":{"root":{"`+valuesKey+`":[]}}}`)
   683  
   684  		// at & through
   685  		suite.assertQueryResult(s, `{root{`+valuesKey+`(at:0,through:"a")}}`,
   686  			`{"data":{"root":{"`+valuesKey+`":["a"]}}}`)
   687  		suite.assertQueryResult(s, `{root{`+valuesKey+`(at:1,through:"e")}}`,
   688  			`{"data":{"root":{"`+valuesKey+`":["c","e"]}}}`)
   689  
   690  		// at & count & through
   691  		suite.assertQueryResult(s, `{root{`+valuesKey+`(at:0,count:2,through:"a")}}`,
   692  			`{"data":{"root":{"`+valuesKey+`":["a"]}}}`)
   693  		suite.assertQueryResult(s, `{root{`+valuesKey+`(at:0,count:2,through:"e")}}`,
   694  			`{"data":{"root":{"`+valuesKey+`":["a","c"]}}}`)
   695  
   696  		// key & count & through
   697  		suite.assertQueryResult(s, `{root{`+valuesKey+`(key:"c",count:2,through:"c")}}`,
   698  			`{"data":{"root":{"`+valuesKey+`":["c"]}}}`)
   699  		suite.assertQueryResult(s, `{root{`+valuesKey+`(key:"c",count:2,through:"g")}}`,
   700  			`{"data":{"root":{"`+valuesKey+`":["c","e"]}}}`)
   701  	}
   702  }
   703  
   704  func (suite *QueryGraphQLSuite) TestMapValues() {
   705  	m := types.NewMap(suite.vs,
   706  		types.String("a"), types.Number(1),
   707  		types.String("c"), types.Number(2),
   708  		types.String("e"), types.Number(3),
   709  		types.String("g"), types.Number(4),
   710  	)
   711  
   712  	suite.assertQueryResult(m, "{root{values}}", `{"data":{"root":{"values":[1,2,3,4]}}}`)
   713  
   714  	// count
   715  	suite.assertQueryResult(m, "{root{values(count:0)}}", `{"data":{"root":{"values":[]}}}`)
   716  	suite.assertQueryResult(m, "{root{values(count:2)}}", `{"data":{"root":{"values":[1,2]}}}`)
   717  	suite.assertQueryResult(m, "{root{values(count:3)}}", `{"data":{"root":{"values":[1,2,3]}}}`)
   718  	suite.assertQueryResult(m, "{root{values(count: -1)}}", `{"data":{"root":{"values":[]}}}`)
   719  	suite.assertQueryResult(m, "{root{values(count:5)}}", `{"data":{"root":{"values":[1,2,3,4]}}}`)
   720  
   721  	// at
   722  	suite.assertQueryResult(m, "{root{values(at:0)}}", `{"data":{"root":{"values":[1,2,3,4]}}}`)
   723  	suite.assertQueryResult(m, "{root{values(at:-1)}}", `{"data":{"root":{"values":[1,2,3,4]}}}`)
   724  	suite.assertQueryResult(m, "{root{values(at:2)}}", `{"data":{"root":{"values":[3,4]}}}`)
   725  	suite.assertQueryResult(m, "{root{values(at:5)}}", `{"data":{"root":{"values":[]}}}`)
   726  
   727  	// at & count
   728  	suite.assertQueryResult(m, "{root{values(at:0,count:2)}}", `{"data":{"root":{"values":[1,2]}}}`)
   729  	suite.assertQueryResult(m, "{root{values(at:-1,count:2)}}", `{"data":{"root":{"values":[1,2]}}}`)
   730  	suite.assertQueryResult(m, "{root{values(at:1,count:2)}}", `{"data":{"root":{"values":[2,3]}}}`)
   731  	suite.assertQueryResult(m, "{root{values(at:2,count:1)}}", `{"data":{"root":{"values":[3]}}}`)
   732  	suite.assertQueryResult(m, "{root{values(at:2,count:0)}}", `{"data":{"root":{"values":[]}}}`)
   733  	suite.assertQueryResult(m, "{root{values(at:2,count:10)}}", `{"data":{"root":{"values":[3,4]}}}`)
   734  
   735  	// key
   736  	suite.assertQueryResult(m, `{root{values(key:"e")}}`, `{"data":{"root":{"values":[3]}}}`)
   737  	suite.assertQueryResult(m, `{root{values(key:"g")}}`, `{"data":{"root":{"values":[4]}}}`)
   738  	// "f", no count/through so asking for exact match
   739  	suite.assertQueryResult(m, `{root{values(key:"f")}}`, `{"data":{"root":{"values":[]}}}`)
   740  	// "x" is larger than end
   741  	suite.assertQueryResult(m, `{root{values(key:"x")}}`, `{"data":{"root":{"values":[]}}}`)
   742  
   743  	// key & at
   744  	// at is ignored when key is present
   745  	suite.assertQueryResult(m, `{root{values(key:"e",at:2)}}`, `{"data":{"root":{"values":[3]}}}`)
   746  
   747  	// key & count
   748  	suite.assertQueryResult(m, `{root{values(key:"c",count:2)}}`, `{"data":{"root":{"values":[2,3]}}}`)
   749  	suite.assertQueryResult(m, `{root{values(key:"c",count:0)}}`, `{"data":{"root":{"values":[]}}}`)
   750  	suite.assertQueryResult(m, `{root{values(key:"c",count:-1)}}`, `{"data":{"root":{"values":[]}}}`)
   751  	suite.assertQueryResult(m, `{root{values(key:"e",count:5)}}`, `{"data":{"root":{"values":[3,4]}}}`)
   752  
   753  	// through
   754  	suite.assertQueryResult(m, `{root{values(through:"c")}}`, `{"data":{"root":{"values":[1,2]}}}`)
   755  	suite.assertQueryResult(m, `{root{values(through:"b")}}`, `{"data":{"root":{"values":[1]}}}`)
   756  	suite.assertQueryResult(m, `{root{values(through:"0")}}`, `{"data":{"root":{"values":[]}}}`)
   757  
   758  	// key & through
   759  	suite.assertQueryResult(m, `{root{values(key:"c", through:"c")}}`, `{"data":{"root":{"values":[2]}}}`)
   760  	suite.assertQueryResult(m, `{root{values(key:"c",through:"e")}}`, `{"data":{"root":{"values":[2,3]}}}`)
   761  
   762  	// through & count
   763  	suite.assertQueryResult(m, `{root{values(through:"c",count:1)}}`, `{"data":{"root":{"values":[1]}}}`)
   764  	suite.assertQueryResult(m, `{root{values(through:"b",count:0)}}`, `{"data":{"root":{"values":[]}}}`)
   765  	suite.assertQueryResult(m, `{root{values(through:"0",count:10)}}`, `{"data":{"root":{"values":[]}}}`)
   766  
   767  	// at & through
   768  	suite.assertQueryResult(m, `{root{values(at:0,through:"a")}}`, `{"data":{"root":{"values":[1]}}}`)
   769  	suite.assertQueryResult(m, `{root{values(at:1,through:"e")}}`, `{"data":{"root":{"values":[2,3]}}}`)
   770  
   771  	// at & count & through
   772  	suite.assertQueryResult(m, `{root{values(at:0,count:2,through:"a")}}`, `{"data":{"root":{"values":[1]}}}`)
   773  	suite.assertQueryResult(m, `{root{values(at:0,count:2,through:"e")}}`, `{"data":{"root":{"values":[1,2]}}}`)
   774  
   775  	// key & count & through
   776  	suite.assertQueryResult(m, `{root{values(key:"c",count:2,through:"c")}}`,
   777  		`{"data":{"root":{"values":[2]}}}`)
   778  	suite.assertQueryResult(m, `{root{values(key:"c",count:2,through:"g")}}`,
   779  		`{"data":{"root":{"values":[2,3]}}}`)
   780  }
   781  
   782  func (suite *QueryGraphQLSuite) TestMapKeys() {
   783  	m := types.NewMap(suite.vs,
   784  		types.String("a"), types.Number(1),
   785  		types.String("c"), types.Number(2),
   786  		types.String("e"), types.Number(3),
   787  		types.String("g"), types.Number(4),
   788  	)
   789  
   790  	suite.assertQueryResult(m, "{root{keys}}", `{"data":{"root":{"keys":["a","c","e","g"]}}}`)
   791  
   792  	// count
   793  	suite.assertQueryResult(m, "{root{keys(count:0)}}", `{"data":{"root":{"keys":[]}}}`)
   794  	suite.assertQueryResult(m, "{root{keys(count:2)}}", `{"data":{"root":{"keys":["a","c"]}}}`)
   795  	suite.assertQueryResult(m, "{root{keys(count:3)}}", `{"data":{"root":{"keys":["a","c","e"]}}}`)
   796  	suite.assertQueryResult(m, "{root{keys(count: -1)}}", `{"data":{"root":{"keys":[]}}}`)
   797  	suite.assertQueryResult(m, "{root{keys(count:5)}}", `{"data":{"root":{"keys":["a","c","e","g"]}}}`)
   798  
   799  	// at
   800  	suite.assertQueryResult(m, "{root{keys(at:0)}}", `{"data":{"root":{"keys":["a","c","e","g"]}}}`)
   801  	suite.assertQueryResult(m, "{root{keys(at:-1)}}", `{"data":{"root":{"keys":["a","c","e","g"]}}}`)
   802  	suite.assertQueryResult(m, "{root{keys(at:2)}}", `{"data":{"root":{"keys":["e","g"]}}}`)
   803  	suite.assertQueryResult(m, "{root{keys(at:5)}}", `{"data":{"root":{"keys":[]}}}`)
   804  
   805  	// at & count
   806  	suite.assertQueryResult(m, "{root{keys(at:0,count:2)}}", `{"data":{"root":{"keys":["a","c"]}}}`)
   807  	suite.assertQueryResult(m, "{root{keys(at:-1,count:2)}}", `{"data":{"root":{"keys":["a","c"]}}}`)
   808  	suite.assertQueryResult(m, "{root{keys(at:1,count:2)}}", `{"data":{"root":{"keys":["c","e"]}}}`)
   809  	suite.assertQueryResult(m, "{root{keys(at:2,count:1)}}", `{"data":{"root":{"keys":["e"]}}}`)
   810  	suite.assertQueryResult(m, "{root{keys(at:2,count:0)}}", `{"data":{"root":{"keys":[]}}}`)
   811  	suite.assertQueryResult(m, "{root{keys(at:2,count:10)}}", `{"data":{"root":{"keys":["e","g"]}}}`)
   812  
   813  	// key
   814  	suite.assertQueryResult(m, `{root{keys(key:"e")}}`, `{"data":{"root":{"keys":["e"]}}}`)
   815  	suite.assertQueryResult(m, `{root{keys(key:"g")}}`, `{"data":{"root":{"keys":["g"]}}}`)
   816  	// "f", no count/through so asking for exact match
   817  	suite.assertQueryResult(m, `{root{keys(key:"f")}}`, `{"data":{"root":{"keys":[]}}}`)
   818  	// "x" is larger than end
   819  	suite.assertQueryResult(m, `{root{keys(key:"x")}}`, `{"data":{"root":{"keys":[]}}}`)
   820  
   821  	// key & at
   822  	// at is ignored when key is present
   823  	suite.assertQueryResult(m, `{root{keys(key:"e",at:2)}}`, `{"data":{"root":{"keys":["e"]}}}`)
   824  
   825  	// key & count
   826  	suite.assertQueryResult(m, `{root{keys(key:"c",count:2)}}`, `{"data":{"root":{"keys":["c","e"]}}}`)
   827  	suite.assertQueryResult(m, `{root{keys(key:"c",count:0)}}`, `{"data":{"root":{"keys":[]}}}`)
   828  	suite.assertQueryResult(m, `{root{keys(key:"c",count:-1)}}`, `{"data":{"root":{"keys":[]}}}`)
   829  	suite.assertQueryResult(m, `{root{keys(key:"e",count:5)}}`, `{"data":{"root":{"keys":["e","g"]}}}`)
   830  
   831  	// through
   832  	suite.assertQueryResult(m, `{root{keys(through:"c")}}`, `{"data":{"root":{"keys":["a","c"]}}}`)
   833  	suite.assertQueryResult(m, `{root{keys(through:"b")}}`, `{"data":{"root":{"keys":["a"]}}}`)
   834  	suite.assertQueryResult(m, `{root{keys(through:"0")}}`, `{"data":{"root":{"keys":[]}}}`)
   835  
   836  	// key & through
   837  	suite.assertQueryResult(m, `{root{keys(key:"c", through:"c")}}`, `{"data":{"root":{"keys":["c"]}}}`)
   838  	suite.assertQueryResult(m, `{root{keys(key:"c",through:"e")}}`, `{"data":{"root":{"keys":["c","e"]}}}`)
   839  
   840  	// through & count
   841  	suite.assertQueryResult(m, `{root{keys(through:"c",count:1)}}`, `{"data":{"root":{"keys":["a"]}}}`)
   842  	suite.assertQueryResult(m, `{root{keys(through:"b",count:0)}}`, `{"data":{"root":{"keys":[]}}}`)
   843  	suite.assertQueryResult(m, `{root{keys(through:"0",count:10)}}`, `{"data":{"root":{"keys":[]}}}`)
   844  
   845  	// at & through
   846  	suite.assertQueryResult(m, `{root{keys(at:0,through:"a")}}`, `{"data":{"root":{"keys":["a"]}}}`)
   847  	suite.assertQueryResult(m, `{root{keys(at:1,through:"e")}}`, `{"data":{"root":{"keys":["c","e"]}}}`)
   848  
   849  	// at & count & through
   850  	suite.assertQueryResult(m, `{root{keys(at:0,count:2,through:"a")}}`, `{"data":{"root":{"keys":["a"]}}}`)
   851  	suite.assertQueryResult(m, `{root{keys(at:0,count:2,through:"e")}}`, `{"data":{"root":{"keys":["a","c"]}}}`)
   852  
   853  	// key & count & through
   854  	suite.assertQueryResult(m, `{root{keys(key:"c",count:2,through:"c")}}`,
   855  		`{"data":{"root":{"keys":["c"]}}}`)
   856  	suite.assertQueryResult(m, `{root{keys(key:"c",count:2,through:"g")}}`,
   857  		`{"data":{"root":{"keys":["c","e"]}}}`)
   858  }
   859  
   860  func (suite *QueryGraphQLSuite) TestMapNullable() {
   861  	// When selecting the result based on keys the values may be null.
   862  	m := types.NewMap(suite.vs,
   863  		types.String("a"), types.Number(1),
   864  		types.String("c"), types.Number(2),
   865  	)
   866  
   867  	for _, entriesKey := range []string{"elements", "entries"} {
   868  		suite.assertQueryResult(m, `{root{`+entriesKey+`(keys:["a","b","c"]){value}}}`,
   869  			`{"data":{"root":{"`+entriesKey+`":[{"value":1},{"value":null},{"value":2}]}}}`)
   870  		suite.assertQueryResult(m, `{root{`+entriesKey+`(keys:["a","b","c"]){key}}}`,
   871  			`{"data":{"root":{"`+entriesKey+`":[{"key":"a"},{"key":"b"},{"key":"c"}]}}}`)
   872  		suite.assertQueryResult(m, `{root{`+entriesKey+`(keys:["a","b","c"]){key value}}}`,
   873  			`{"data":{"root":{"`+entriesKey+`":[{"key":"a","value":1},{"key":"b","value":null},{"key":"c","value":2}]}}}`)
   874  	}
   875  	suite.assertQueryResult(m, `{root{values(keys:["a","b","c"])}}`,
   876  		`{"data":{"root":{"values":[1,null,2]}}}`)
   877  	suite.assertQueryResult(m, `{root{keys(keys:["a","b","c"])}}`,
   878  		`{"data":{"root":{"keys":["a","b","c"]}}}`)
   879  }
   880  
   881  func (suite *QueryGraphQLSuite) TestStructWithOptionalField() {
   882  	tm := NewTypeMap()
   883  	rootValue := types.NewStruct("", types.StructData{
   884  		"n": types.Number(42),
   885  	})
   886  	rootType := NomsTypeToGraphQLType(types.MakeStructType("",
   887  		types.StructField{Name: "n", Type: types.NumberType, Optional: false},
   888  		types.StructField{Name: "s", Type: types.StringType, Optional: true},
   889  	), false, tm)
   890  
   891  	queryObj := graphql.NewObject(graphql.ObjectConfig{
   892  		Name: rootQueryKey,
   893  		Fields: graphql.Fields{
   894  			rootKey: &graphql.Field{
   895  				Type: rootType,
   896  				Resolve: func(p graphql.ResolveParams) (interface{}, error) {
   897  					return MaybeGetScalar(rootValue), nil
   898  				},
   899  			},
   900  		}})
   901  
   902  	schemaConfig := graphql.SchemaConfig{Query: queryObj}
   903  	schema, err := graphql.NewSchema(schemaConfig)
   904  	suite.NoError(err)
   905  	ctx := NewContext(suite.vs)
   906  	query := `{root{n s}}`
   907  
   908  	r := graphql.Do(graphql.Params{
   909  		Schema:        schema,
   910  		RequestString: query,
   911  		Context:       ctx,
   912  	})
   913  
   914  	suite.Equal(map[string]interface{}{"root": map[string]interface{}{"n": float64(42), "s": nil}}, r.Data)
   915  }
   916  
   917  func (suite *QueryGraphQLSuite) TestMutationScalarArgs() {
   918  	test := func(query, expected string, nomsType *types.Type) {
   919  		tc := NewTypeConverter()
   920  		inType, err := tc.NomsTypeToGraphQLInputType(nomsType)
   921  		suite.NoError(err)
   922  		outType := tc.NomsTypeToGraphQLType(nomsType)
   923  		suite.assertMutationTypes(query, expected, tc, inType, outType, func(p graphql.ResolveParams) (interface{}, error) {
   924  			return p.Args["new"], nil
   925  		})
   926  	}
   927  
   928  	test(`mutation {test(new: 123)}`, `{"data": {"test": 123}}`, types.NumberType)
   929  	test(`mutation {test(new: 0)}`, `{"data": {"test": 0}}`, types.NumberType)
   930  
   931  	test(`mutation {test(new: "hi")}`, `{"data": {"test": "hi"}}`, types.StringType)
   932  	test(`mutation {test(new: "")}`, `{"data": {"test": ""}}`, types.StringType)
   933  
   934  	test(`mutation {test(new: true)}`, `{"data": {"test": true}}`, types.BoolType)
   935  	test(`mutation {test(new: false)}`, `{"data": {"test": false}}`, types.BoolType)
   936  }
   937  
   938  func (suite *QueryGraphQLSuite) TestMutationWeirdosArgs() {
   939  	test := func(query, expected string, nomsType *types.Type) {
   940  		tc := NewTypeConverter()
   941  		inType, err := tc.NomsTypeToGraphQLInputType(nomsType)
   942  		suite.NoError(err)
   943  		outType := graphql.String
   944  		suite.assertMutationTypes(query, expected, tc, inType, outType, func(p graphql.ResolveParams) (interface{}, error) {
   945  			return p.Args["new"], nil
   946  		})
   947  	}
   948  
   949  	test(`mutation {test(new: "#abc")}`, `{"data": {"test": "#abc"}}`, types.MakeRefType(types.NumberType))
   950  	test(`mutation {test(new: "0123456789")}`, `{"data": {"test": "0123456789"}}`, types.BlobType)
   951  }
   952  
   953  func (suite *QueryGraphQLSuite) assertMutationTypes(query, expected string, tc *TypeConverter, inType graphql.Input, outType graphql.Type, resolver graphql.FieldResolveFn) {
   954  	buf := &bytes.Buffer{}
   955  	root := types.Number(0)
   956  	schemaConfig := graphql.SchemaConfig{
   957  		Mutation: graphql.NewObject(graphql.ObjectConfig{
   958  			Name: "Mutation",
   959  			Fields: graphql.Fields{
   960  				"test": &graphql.Field{
   961  					Type: outType,
   962  					Args: graphql.FieldConfigArgument{
   963  						"new": &graphql.ArgumentConfig{
   964  							Type: inType,
   965  						},
   966  					},
   967  					Resolve: resolver,
   968  				},
   969  			},
   970  		}),
   971  	}
   972  	queryWithSchemaConfig(root, query, schemaConfig, suite.vs, tc, buf)
   973  	suite.JSONEq(expected, buf.String())
   974  }
   975  
   976  func (suite *QueryGraphQLSuite) TestMutationCollectionArgs() {
   977  	test := func(query, expected string, expectedArg interface{}, nomsType *types.Type) {
   978  		tc := NewTypeConverter()
   979  		inType, err := tc.NomsTypeToGraphQLInputType(nomsType)
   980  		suite.NoError(err)
   981  		outType := graphql.Boolean
   982  		suite.assertMutationTypes(query, expected, tc, inType, outType, func(p graphql.ResolveParams) (interface{}, error) {
   983  			suite.Equal(expectedArg, p.Args["new"])
   984  			return true, nil
   985  		})
   986  	}
   987  
   988  	test(`mutation {test(new: [0, 1, 2, 3])}`, `{"data": {"test": true}}`, []interface{}{float64(0), float64(1), float64(2), float64(3)}, types.MakeListType(types.NumberType))
   989  	test(`mutation {test(new: [])}`, `{"data": {"test": true}}`, []interface{}{}, types.MakeListType(types.NumberType))
   990  
   991  	test(`mutation {test(new: [0, 1, 2, 3])}`, `{"data": {"test": true}}`, []interface{}{float64(0), float64(1), float64(2), float64(3)}, types.MakeSetType(types.NumberType))
   992  	test(`mutation {test(new: [])}`, `{"data": {"test": true}}`, []interface{}{}, types.MakeSetType(types.NumberType))
   993  
   994  	test(`mutation {
   995                  test(new: [
   996                          {
   997                                  key: 1,
   998                                  value: "a"
   999                          }, {
  1000                                  key: 2,
  1001                                  value: "b"
  1002                          }
  1003                  ])
  1004          }`, `{"data": {"test": true}}`, []interface{}{
  1005  		map[string]interface{}{"key": float64(1), "value": "a"},
  1006  		map[string]interface{}{"key": float64(2), "value": "b"},
  1007  	}, types.MakeMapType(types.NumberType, types.StringType))
  1008  	test(`mutation {test(new: [])}`, `{"data": {"test": true}}`, []interface{}{}, types.MakeMapType(types.NumberType, types.StringType))
  1009  
  1010  	st := types.MakeStructTypeFromFields("N", types.FieldMap{
  1011  		"f": types.NumberType,
  1012  		"b": types.BoolType,
  1013  		"s": types.StringType,
  1014  	})
  1015  	test(`mutation {test(new: {
  1016                  f: 42,
  1017                  b: true,
  1018                  s: "hi"
  1019          })}`, `{"data": {"test": true}}`, map[string]interface{}{"b": true, "f": float64(42), "s": "hi"}, st)
  1020  }
  1021  
  1022  func (suite *QueryGraphQLSuite) TestMapWithComplexKeys() {
  1023  	m := types.NewMap(suite.vs,
  1024  		types.NewList(suite.vs, types.String("a")), types.Number(1),
  1025  		types.NewList(suite.vs, types.String("c")), types.Number(2),
  1026  		types.NewList(suite.vs, types.String("e")), types.Number(3),
  1027  		types.NewList(suite.vs, types.String("g")), types.Number(4),
  1028  	)
  1029  
  1030  	suite.assertQueryResult(m, `{root{values(key: ["e"])}}`, `{"data":{"root":{"values":[3]}}}`)
  1031  	suite.assertQueryResult(m, `{root{values(key: [])}}`, `{"data":{"root":{"values":[]}}}`)
  1032  
  1033  	// The ordering here depends on the hash of the value...
  1034  	suite.assertQueryResult(m, `{root{values(key: ["a"], through: ["e"])}}`, `{"data":{"root":{"values":[1, 2, 3]}}}`)
  1035  
  1036  	suite.assertQueryResult(m, `{root{values(keys: [["a"],["b"],["c"]])}}`, `{"data":{"root":{"values":[1, null, 2]}}}`)
  1037  	suite.assertQueryResult(m, `{
  1038                  root {
  1039                          keys(keys: [["a"],["b"],["c"]]) {
  1040                                  values
  1041                          }
  1042                  }
  1043          }`, `{"data": {
  1044                  "root": {
  1045                          "keys": [
  1046                                  {"values": ["a"]},
  1047                                  {"values": ["b"]},
  1048                                  {"values": ["c"]}
  1049                          ]
  1050                  }
  1051          }}`)
  1052  
  1053  	m2 := types.NewMap(suite.vs,
  1054  		types.NewStruct("", types.StructData{
  1055  			"n": types.String("a"),
  1056  		}), types.Number(1),
  1057  		types.NewStruct("", types.StructData{
  1058  			"n": types.String("c"),
  1059  		}), types.Number(2),
  1060  		types.NewStruct("", types.StructData{
  1061  			"n": types.String("e"),
  1062  		}), types.Number(3),
  1063  		types.NewStruct("", types.StructData{
  1064  			"n": types.String("g"),
  1065  		}), types.Number(4),
  1066  	)
  1067  	suite.assertQueryResult(m2, `{root{values(key: {n: "e"})}}`, `{"data":{"root":{"values":[3]}}}`)
  1068  	suite.assertQueryResult(m2, `{root{values(key: {n: "x"})}}`, `{"data":{"root":{"values":[]}}}`)
  1069  	// The order is based on hash
  1070  	suite.assertQueryResult(m2, `{root{values(key: {n: "g"}, through: {n: "c"})}}`, `{"data":{"root":{"values":[4,2]}}}`)
  1071  	suite.assertQueryResult(m2, `{root{values(keys: [{n: "a"}, {n: "b"}, {n: "c"}])}}`,
  1072  		`{"data":{"root":{"values":[1, null, 2]}}}`)
  1073  	suite.assertQueryResult(m2, `{root{keys(keys: [{n: "a"}, {n: "b"}, {n: "c"}]) { n }}}`,
  1074  		`{"data":{"root":{"keys":[{"n": "a"}, {"n": "b"}, {"n": "c"}]}}}`)
  1075  }
  1076  
  1077  func (suite *QueryGraphQLSuite) TestSetWithComplexKeys() {
  1078  	s := types.NewSet(suite.vs,
  1079  		types.NewList(suite.vs, types.String("a")),
  1080  		types.NewList(suite.vs, types.String("c")),
  1081  		types.NewList(suite.vs, types.String("e")),
  1082  		types.NewList(suite.vs, types.String("g")),
  1083  	)
  1084  
  1085  	suite.assertQueryResult(s, `{root{values(key: ["e"]) { values }}}`,
  1086  		`{"data":{"root":{"values":[{"values":["e"]}]}}}`)
  1087  	suite.assertQueryResult(s, `{root{values(key: []) { values }}}`, `{"data":{"root":{"values":[]}}}`)
  1088  
  1089  	// The ordering here depends on the hash of the value...
  1090  	suite.assertQueryResult(s, `{root{values(key: ["g"], through: ["c"]) { values }}}`,
  1091  		`{"data":{"root":{"values":[{"values":["g"]},{"values":["a"]},{"values":["c"]}]}}}`)
  1092  
  1093  	s2 := types.NewSet(suite.vs,
  1094  		types.NewStruct("", types.StructData{
  1095  			"n": types.String("a"),
  1096  		}),
  1097  		types.NewStruct("", types.StructData{
  1098  			"n": types.String("c"),
  1099  		}),
  1100  		types.NewStruct("", types.StructData{
  1101  			"n": types.String("e"),
  1102  		}),
  1103  		types.NewStruct("", types.StructData{
  1104  			"n": types.String("g"),
  1105  		}),
  1106  	)
  1107  
  1108  	suite.assertQueryResult(s2, `{root{values(key: {n: "e"}) { n } }}`,
  1109  		`{"data":{"root":{"values":[{"n": "e"}]}}}`)
  1110  	suite.assertQueryResult(s2, `{root{values(key: {n: "x"}) { n } }}`, `{"data":{"root":{"values":[]}}}`)
  1111  	// The order is based on hash
  1112  	suite.assertQueryResult(s2, `{root{values(key: {n: "c"}, through: {n: "e"}) { n }}}`,
  1113  		`{"data":{"root":{"values":[{"n": "c"}, {"n": "e"}]}}}`)
  1114  }
  1115  
  1116  func (suite *QueryGraphQLSuite) TestInputToNomsValue() {
  1117  	test := func(expected types.Value, val interface{}) {
  1118  		suite.True(expected.Equals(InputToNomsValue(suite.vs, val, types.TypeOf(expected))))
  1119  	}
  1120  
  1121  	test(types.Number(42), int(42))
  1122  	test(types.Number(0), int(0))
  1123  
  1124  	test(types.Number(1.23), float64(1.23))
  1125  	test(types.Number(0), float64(0))
  1126  
  1127  	test(types.Bool(true), true)
  1128  	test(types.Bool(false), false)
  1129  
  1130  	test(types.String("hi"), "hi")
  1131  	test(types.String(""), "")
  1132  
  1133  	test(types.NewList(suite.vs, types.Number(42)), []interface{}{float64(42)})
  1134  	test(types.NewList(suite.vs, types.Number(1), types.Number(2)), []interface{}{float64(1), float64(2)})
  1135  
  1136  	test(types.NewSet(suite.vs, types.Number(42)), []interface{}{float64(42)})
  1137  	test(types.NewSet(suite.vs, types.Number(1), types.Number(2)), []interface{}{float64(1), float64(2)})
  1138  
  1139  	test(types.NewMap(suite.vs,
  1140  		types.String("a"), types.Number(1),
  1141  		types.String("b"), types.Number(2),
  1142  	), []interface{}{
  1143  		map[string]interface{}{"key": "a", "value": 1},
  1144  		map[string]interface{}{"key": "b", "value": 2},
  1145  	})
  1146  	test(types.NewMap(suite.vs,
  1147  		types.NewList(suite.vs, types.String("a")), types.Number(1),
  1148  		types.NewList(suite.vs, types.String("b")), types.Number(2),
  1149  	), []interface{}{
  1150  		map[string]interface{}{"key": []interface{}{"a"}, "value": 1},
  1151  		map[string]interface{}{"key": []interface{}{"b"}, "value": 2},
  1152  	})
  1153  
  1154  	test(types.NewMap(suite.vs,
  1155  		types.NewStruct("S", types.StructData{"a": types.Number(1)}), types.Number(11),
  1156  		types.NewStruct("S", types.StructData{"a": types.Number(2)}), types.Number(22),
  1157  	), []interface{}{
  1158  		map[string]interface{}{"key": map[string]interface{}{"a": float64(1)}, "value": 11},
  1159  		map[string]interface{}{"key": map[string]interface{}{"a": float64(2)}, "value": 22},
  1160  	})
  1161  
  1162  	test(types.NewSet(suite.vs,
  1163  		types.NewStruct("S", types.StructData{"a": types.Number(1)}),
  1164  		types.NewStruct("S", types.StructData{"a": types.Number(2)}),
  1165  	), []interface{}{
  1166  		map[string]interface{}{"a": float64(1)},
  1167  		map[string]interface{}{"a": float64(2)},
  1168  	})
  1169  
  1170  	expected := types.NewStruct("S", types.StructData{
  1171  		"x": types.Number(42),
  1172  	})
  1173  	expectedType := types.MakeStructType("S",
  1174  		types.StructField{Name: "a", Type: types.BoolType, Optional: true},
  1175  		types.StructField{Name: "x", Type: types.NumberType, Optional: false},
  1176  	)
  1177  	val := map[string]interface{}{
  1178  		"x": float64(42),
  1179  	}
  1180  	suite.Equal(expected, InputToNomsValue(suite.vs, val, expectedType))
  1181  
  1182  	val = map[string]interface{}{
  1183  		"x": float64(42),
  1184  		"a": nil,
  1185  	}
  1186  	suite.Equal(expected, InputToNomsValue(suite.vs, val, expectedType))
  1187  
  1188  	val = map[string]interface{}{
  1189  		"x": nil,
  1190  	}
  1191  	suite.Panics(func() {
  1192  		InputToNomsValue(suite.vs, val, expectedType)
  1193  	})
  1194  }
  1195  
  1196  func (suite *QueryGraphQLSuite) TestErrorsInInputType() {
  1197  	ut := types.MakeUnionType(types.BoolType, types.NumberType)
  1198  
  1199  	test := func(t *types.Type) {
  1200  		tm := NewTypeMap()
  1201  		_, err := NomsTypeToGraphQLInputType(t, tm)
  1202  		suite.Error(err)
  1203  	}
  1204  
  1205  	test(ut)
  1206  	test(types.MakeListType(ut))
  1207  	test(types.MakeSetType(ut))
  1208  	test(types.MakeMapType(ut, types.BoolType))
  1209  	test(types.MakeMapType(types.BoolType, ut))
  1210  	test(types.MakeMapType(ut, ut))
  1211  	test(types.MakeStructTypeFromFields("", types.FieldMap{"u": ut}))
  1212  
  1213  	test(types.MakeStructTypeFromFields("S", types.FieldMap{
  1214  		"l": types.MakeListType(types.MakeCycleType("S")),
  1215  	}))
  1216  	test(types.MakeStructTypeFromFields("S", types.FieldMap{
  1217  		"n": types.NumberType,
  1218  		"l": types.MakeListType(types.MakeCycleType("S")),
  1219  	}))
  1220  }
  1221  
  1222  func (suite *QueryGraphQLSuite) TestVariables() {
  1223  	test := func(rootValue types.Value, expected string, query string, vars map[string]interface{}) {
  1224  		tc := NewTypeConverter()
  1225  		ctx := NewContext(suite.vs)
  1226  		schema, err := graphql.NewSchema(graphql.SchemaConfig{
  1227  			Query: tc.NewRootQueryObject(rootValue),
  1228  		})
  1229  		suite.NoError(err)
  1230  
  1231  		r := graphql.Do(graphql.Params{
  1232  			Schema:         schema,
  1233  			RequestString:  query,
  1234  			Context:        ctx,
  1235  			VariableValues: vars,
  1236  		})
  1237  		b, err := json.Marshal(r)
  1238  		suite.NoError(err)
  1239  		suite.JSONEq(expected, string(b))
  1240  	}
  1241  
  1242  	v := types.NewList(suite.vs, types.Number(0), types.Number(1), types.Number(2), types.Number(3))
  1243  	test(v, `{"data":{"root":{"values":[0,1,2,3]}}}`, `query Test($c: Int) { root { values(count: $c) } }`, nil)
  1244  	test(v, `{"data":{"root":{"values":[0,1]}}}`, `query Test($c: Int) { root { values(count: $c) } }`, map[string]interface{}{
  1245  		"c": 2,
  1246  	})
  1247  
  1248  	m := types.NewMap(suite.vs,
  1249  		types.String("a"), types.Number(0),
  1250  		types.String("b"), types.Number(1),
  1251  		types.String("c"), types.Number(2),
  1252  		types.String("d"), types.Number(3),
  1253  	)
  1254  	test(m, `{"data":{"root":{"values":[1]}}}`, `query Test($k: String) { root { values(key: $k) } }`, map[string]interface{}{
  1255  		"k": "b",
  1256  	})
  1257  	test(m, `{"data":{"root":{"values":[1, 2]}}}`, `query Test($k: String, $t: String) { root { values(key: $k, through: $t) } }`,
  1258  		map[string]interface{}{
  1259  			"k": "b",
  1260  			"t": "c",
  1261  		})
  1262  	test(m, `{"data":{"root":{"values":[0, 2]}}}`, `query Test($ks: [String!]!) { root { values(keys: $ks) } }`,
  1263  		map[string]interface{}{
  1264  			"ks": []string{"a", "c"},
  1265  		})
  1266  
  1267  	m2 := types.NewMap(suite.vs,
  1268  		types.NewStruct("S", types.StructData{"n": types.String("a")}), types.Number(0),
  1269  		types.NewStruct("S", types.StructData{"n": types.String("b")}), types.Number(1),
  1270  		types.NewStruct("S", types.StructData{"n": types.String("c")}), types.Number(2),
  1271  		types.NewStruct("S", types.StructData{"n": types.String("d")}), types.Number(3),
  1272  	)
  1273  	keyType := types.TypeOf(m2).Desc.(types.CompoundDesc).ElemTypes[0]
  1274  	q := fmt.Sprintf(`query Test($k: %s) { root { values(key: $k) } }`, GetInputTypeName(keyType))
  1275  	test(m2, `{"data":{"root":{"values":[1]}}}`, q, map[string]interface{}{
  1276  		"k": map[string]interface{}{
  1277  			"n": "b",
  1278  		},
  1279  	})
  1280  	q = fmt.Sprintf(`query Test($ks: [%s!]) { root { values(keys: $ks) } }`, GetInputTypeName(keyType))
  1281  	test(m2, `{"data":{"root":{"values":[0, 3]}}}`, q, map[string]interface{}{
  1282  		"ks": []interface{}{
  1283  			map[string]interface{}{
  1284  				"n": "a",
  1285  			},
  1286  			map[string]interface{}{
  1287  				"n": "d",
  1288  			},
  1289  		},
  1290  	})
  1291  	test(m2, `{"data":null,"errors":[{"message":"Variable \"$ks\" got invalid value [{}].\nIn element #1: In field \"n\": Expected \"String!\", found null.","locations":[{"line":1,"column":12}]}]}`,
  1292  		q,
  1293  		map[string]interface{}{
  1294  			"ks": []interface{}{
  1295  				map[string]interface{}{},
  1296  			},
  1297  		},
  1298  	)
  1299  	test(m2, `{"data":null,"errors":[{"message":"Variable \"$ks\" got invalid value [{\"m\":\"b\",\"n\":\"a\"}].\nIn element #1: In field \"m\": Unknown field.","locations":[{"line":1,"column":12}]}]}`,
  1300  		q,
  1301  		map[string]interface{}{
  1302  			"ks": []interface{}{
  1303  				map[string]interface{}{
  1304  					"n": "a",
  1305  					"m": "b",
  1306  				},
  1307  			},
  1308  		},
  1309  	)
  1310  	test(m2, `{"data":null,"errors":[{"message":"Variable \"$ks\" got invalid value [{\"n\":null}].\nIn element #1: In field \"n\": Expected \"String!\", found null.","locations":[{"line":1,"column":12}]}]}`,
  1311  		q,
  1312  		map[string]interface{}{
  1313  			"ks": []interface{}{
  1314  				map[string]interface{}{
  1315  					"n": nil,
  1316  				},
  1317  			},
  1318  		},
  1319  	)
  1320  	test(m2, `{"data":null,"errors":[{"message":"Variable \"$ks\" got invalid value [null].\nIn element #1: Expected \"SInput_cgmdbo!\", found null.","locations":[{"line":1,"column":12}]}]}`,
  1321  		q,
  1322  		map[string]interface{}{
  1323  			"ks": []interface{}{
  1324  				nil,
  1325  			},
  1326  		},
  1327  	)
  1328  
  1329  	m3 := types.NewMap(suite.vs,
  1330  		types.NewMap(suite.vs, types.Number(0), types.String("zero")), types.Bool(false),
  1331  		types.NewMap(suite.vs, types.Number(1), types.String("one")), types.Bool(true),
  1332  	)
  1333  	keyNomsType := types.TypeOf(m3).Desc.(types.CompoundDesc).ElemTypes[0]
  1334  	tc := NewTypeConverter()
  1335  	keyGraphQLInputType, err := tc.NomsTypeToGraphQLInputType(keyNomsType)
  1336  	suite.NoError(err)
  1337  	q = fmt.Sprintf(`query Test($k: %s!) { root { values(key: $k) } }`, keyGraphQLInputType.String())
  1338  	test(m3, `{"data":{"root":{"values":[false]}}}`, q, map[string]interface{}{
  1339  		"k": []interface{}{
  1340  			map[string]interface{}{
  1341  				"key":   float64(0),
  1342  				"value": "zero",
  1343  			},
  1344  		},
  1345  	})
  1346  	test(m3, `{"data":null,"errors":[{"message":"Variable \"$k\" got invalid value [{\"key\":0}].\nIn element #1: In field \"value\": Expected \"String!\", found null.","locations":[{"line":1,"column":12}]}]}`,
  1347  		q,
  1348  		map[string]interface{}{
  1349  			"k": []interface{}{
  1350  				map[string]interface{}{
  1351  					"key": float64(0),
  1352  				},
  1353  			},
  1354  		})
  1355  	test(m3, `{"data":null,"errors":[{"message":"Variable \"$k\" got invalid value [{\"key\":\"zero\"}].\nIn element #1: In field \"key\": Expected type \"Float\", found \"zero\".\nIn element #2: In field \"value\": Expected \"String!\", found null.","locations":[{"line":1,"column":12}]}]}`,
  1356  		q,
  1357  		map[string]interface{}{
  1358  			"k": []interface{}{
  1359  				map[string]interface{}{
  1360  					"key": "zero",
  1361  				},
  1362  			},
  1363  		})
  1364  	test(m3, `{"data":null,"errors":[{"message":"Variable \"$k\" got invalid value [{\"extra\":false,\"key\":0,\"value\":\"zero\"}].\nIn element #1: In field \"extra\": Unknown field.","locations":[{"line":1,"column":12}]}]}`,
  1365  		q,
  1366  		map[string]interface{}{
  1367  			"k": []interface{}{
  1368  				map[string]interface{}{
  1369  					"key":   float64(0),
  1370  					"value": "zero",
  1371  					"extra": false,
  1372  				},
  1373  			},
  1374  		})
  1375  	test(m3, `{"data":null,"errors":[{"message":"Variable \"$k\" got invalid value [null].\nIn element #1: Expected \"NumberStringEntryInput!\", found null.","locations":[{"line":1,"column":12}]}]}`,
  1376  		q,
  1377  		map[string]interface{}{
  1378  			"k": []interface{}{
  1379  				nil,
  1380  			},
  1381  		})
  1382  }
  1383  
  1384  func (suite *QueryGraphQLSuite) TestNameFunc() {
  1385  	test := func(tc *TypeConverter, rootValue types.Value, expected string, query string, vars map[string]interface{}) {
  1386  		ctx := NewContext(suite.vs)
  1387  		schema, err := graphql.NewSchema(graphql.SchemaConfig{
  1388  			Query: tc.NewRootQueryObject(rootValue),
  1389  		})
  1390  		suite.NoError(err)
  1391  
  1392  		r := graphql.Do(graphql.Params{
  1393  			Schema:         schema,
  1394  			RequestString:  query,
  1395  			Context:        ctx,
  1396  			VariableValues: vars,
  1397  		})
  1398  
  1399  		b, err := json.Marshal(r)
  1400  		suite.NoError(err)
  1401  		suite.JSONEq(expected, string(b))
  1402  	}
  1403  
  1404  	aVal := types.NewStruct("A", types.StructData{
  1405  		"a": types.Number(1),
  1406  	})
  1407  	bVal := types.NewStruct("B", types.StructData{
  1408  		"b": types.Number(2),
  1409  	})
  1410  
  1411  	list := types.NewList(suite.vs, aVal, bVal)
  1412  
  1413  	tc := NewTypeConverter()
  1414  	tc.NameFunc = func(nomsType *types.Type, isInputType bool) string {
  1415  		if nomsType.Equals(types.TypeOf(aVal)) {
  1416  			return "A"
  1417  		}
  1418  		if nomsType.Equals(types.TypeOf(bVal)) {
  1419  			return "BBB"
  1420  		}
  1421  		return DefaultNameFunc(nomsType, isInputType)
  1422  	}
  1423  
  1424  	query := `query {
  1425                  root {
  1426                          values {
  1427                                  ... on A {
  1428                                          a
  1429                                  }
  1430                                  ... on BBB {
  1431                                          b
  1432                                  }
  1433                          }
  1434                  }
  1435          }`
  1436  	expected := `{
  1437                  "data": {
  1438                          "root": {
  1439                                  "values": [
  1440                                          {"a": 1},
  1441                                          {"b": 2}
  1442                                  ]
  1443                          }
  1444                  }
  1445          }`
  1446  	test(tc, list, expected, query, nil)
  1447  
  1448  	set := types.NewSet(suite.vs, aVal,
  1449  		types.NewStruct("A", types.StructData{
  1450  			"a": types.Number(2),
  1451  		}),
  1452  		types.NewStruct("A", types.StructData{
  1453  			"a": types.Number(3),
  1454  		}),
  1455  	)
  1456  	tc = NewTypeConverter()
  1457  	tc.NameFunc = func(nomsType *types.Type, isInputType bool) string {
  1458  		if nomsType.Equals(types.TypeOf(aVal)) {
  1459  			if isInputType {
  1460  				return "AI"
  1461  			}
  1462  			return "A"
  1463  		}
  1464  		return DefaultNameFunc(nomsType, isInputType)
  1465  	}
  1466  
  1467  	query = `query ($key: AI!) {
  1468                  root {
  1469                          values(key: $key) {
  1470                                  a
  1471                          }
  1472                  }
  1473          }`
  1474  	expected = `{
  1475                  "data": {
  1476                          "root": {
  1477                                  "values": [
  1478                                          {"a": 2}
  1479                                  ]
  1480                          }
  1481                  }
  1482          }`
  1483  	test(tc, set, expected, query, map[string]interface{}{
  1484  		"key": map[string]interface{}{"a": 2},
  1485  	})
  1486  }
  1487  
  1488  func TestGetListElementsWithSet(t *testing.T) {
  1489  	assert := assert.New(t)
  1490  	vs := newTestValueStore()
  1491  	v := types.NewSet(vs, types.Number(0), types.Number(1), types.Number(2))
  1492  	r := getListElements(vs, v, map[string]interface{}{})
  1493  	assert.Equal([]interface{}{float64(0), float64(1), float64(2)}, r)
  1494  
  1495  	r = getListElements(vs, v, map[string]interface{}{
  1496  		atKey: 1,
  1497  	})
  1498  	assert.Equal([]interface{}{float64(1), float64(2)}, r)
  1499  
  1500  	r = getListElements(vs, v, map[string]interface{}{
  1501  		countKey: 2,
  1502  	})
  1503  	assert.Equal([]interface{}{float64(0), float64(1)}, r)
  1504  }
  1505  
  1506  func TestNoErrorOnNonCyclicTypeRefsInputType(t *testing.T) {
  1507  	assert := assert.New(t)
  1508  
  1509  	type User struct {
  1510  		ID string `noms:"id"`
  1511  	}
  1512  	type Account struct {
  1513  		PendingUsers map[string]User
  1514  		Users        map[string]User
  1515  	}
  1516  
  1517  	var a Account
  1518  	typ := marshal.MustMarshalType(a)
  1519  	tc := NewTypeConverter()
  1520  	_, err := tc.NomsTypeToGraphQLInputType(typ)
  1521  	assert.NoError(err)
  1522  }
  1523  
  1524  func TestErrorOnCyclicTypeRefsInputType(t *testing.T) {
  1525  	assert := assert.New(t)
  1526  
  1527  	type Node struct {
  1528  		Children map[string]Node
  1529  	}
  1530  
  1531  	var n Node
  1532  	typ := marshal.MustMarshalType(n)
  1533  	tc := NewTypeConverter()
  1534  	_, err := tc.NomsTypeToGraphQLInputType(typ)
  1535  	assert.Error(err)
  1536  }