GraphQL map set at (#3229)

Add support for at arguments to Map and Set elements

Towards #3227
This commit is contained in:
Erik Arvidsson
2017-02-24 17:34:43 -08:00
committed by GitHub
parent cc77359e65
commit 68de09f8db
3 changed files with 81 additions and 60 deletions

View File

@@ -9,16 +9,18 @@ import (
"encoding/json"
"io"
"github.com/attic-labs/noms/go/d"
"github.com/attic-labs/noms/go/types"
"github.com/attic-labs/graphql"
"github.com/attic-labs/graphql/gqlerrors"
"github.com/attic-labs/noms/go/d"
"github.com/attic-labs/noms/go/types"
)
const (
atKey = "at"
countKey = "count"
elementsKey = "elements"
keyKey = "key"
rootKey = "root"
rootQueryKey = "Root"
scalarValue = "scalarValue"
sizeKey = "size"
@@ -26,8 +28,6 @@ const (
targetValueKey = "targetValue"
tmKey = "tm"
valueKey = "value"
rootKey = "root"
elementsKey = "elements"
vrKey = "vr"
)

View File

@@ -104,6 +104,12 @@ func (suite *QueryGraphQLSuite) TestListBasic() {
suite.assertQueryResult(list, "{root{elements}}", `{"data":{"root":{"elements":[1,1.1,-100]}}}`)
suite.assertQueryResult(list, "{root{elements(at:1,count:2)}}", `{"data":{"root":{"elements":[1.1,-100]}}}`)
list = types.NewList(types.String("a"), types.String("b"), types.String("c"))
suite.assertQueryResult(list, "{root{elements(at:4)}}", `{"data":{"root":{"elements":[]}}}`)
suite.assertQueryResult(list, "{root{elements(count:0)}}", `{"data":{"root":{"elements":[]}}}`)
suite.assertQueryResult(list, "{root{elements(count:10)}}", `{"data":{"root":{"elements":["a","b","c"]}}}`)
suite.assertQueryResult(list, "{root{elements(at:-1)}}", `{"data":{"root":{"elements":["a","b","c"]}}}`)
}
func (suite *QueryGraphQLSuite) TestListOfStruct() {
@@ -147,6 +153,18 @@ func (suite *QueryGraphQLSuite) TestSetBasic() {
suite.assertQueryResult(set, "{root{elements}}", `{"data":{"root":{"elements":[-100,1,1.1]}}}`)
suite.assertQueryResult(set, "{root{elements(count:2)}}", `{"data":{"root":{"elements":[-100,1]}}}`)
set = types.NewSet(types.String("a"), types.String("b"), types.String("c"), types.String("d"))
suite.assertQueryResult(set, "{root{elements(count:0)}}", `{"data":{"root":{"elements":[]}}}`)
suite.assertQueryResult(set, "{root{elements(count:2)}}", `{"data":{"root":{"elements":["a","b"]}}}`)
suite.assertQueryResult(set, "{root{elements(at:0,count:2)}}", `{"data":{"root":{"elements":["a","b"]}}}`)
suite.assertQueryResult(set, "{root{elements(at:-1,count:2)}}", `{"data":{"root":{"elements":["a","b"]}}}`)
suite.assertQueryResult(set, "{root{elements(at:1,count:2)}}", `{"data":{"root":{"elements":["b","c"]}}}`)
suite.assertQueryResult(set, "{root{elements(at:2)}}", `{"data":{"root":{"elements":["c","d"]}}}`)
suite.assertQueryResult(set, "{root{elements(at:2,count:1)}}", `{"data":{"root":{"elements":["c"]}}}`)
suite.assertQueryResult(set, "{root{elements(at:2,count:0)}}", `{"data":{"root":{"elements":[]}}}`)
suite.assertQueryResult(set, "{root{elements(at:2,count:10)}}", `{"data":{"root":{"elements":["c","d"]}}}`)
}
func (suite *QueryGraphQLSuite) TestSetOfStruct() {
@@ -175,15 +193,29 @@ func (suite *QueryGraphQLSuite) TestMapBasic() {
suite.assertQueryResult(m, "{root{elements}}", `{"data":{"root":{}}}`)
m = types.NewMap(
types.String("foo"), types.Number(1),
types.String("bar"), types.Number(2),
types.String("baz"), types.Number(3),
types.String("a"), types.Number(1),
types.String("b"), types.Number(2),
types.String("c"), types.Number(3),
types.String("d"), types.Number(4),
)
suite.assertQueryResult(m, "{root{elements{key value}}}", `{"data":{"root":{"elements":[{"key":"bar","value":2},{"key":"baz","value":3},{"key":"foo","value":1}]}}}`)
suite.assertQueryResult(m, "{root{size}}", `{"data":{"root":{"size":3}}}`)
suite.assertQueryResult(m, "{root{elements(count:2){value}}}", `{"data":{"root":{"elements":[{"value":2},{"value":3}]}}}`)
suite.assertQueryResult(m, "{root{elements(count:3){key}}}", `{"data":{"root":{"elements":[{"key":"bar"},{"key":"baz"},{"key":"foo"}]}}}`)
suite.assertQueryResult(m, "{root{elements{key value}}}", `{"data":{"root":{"elements":[{"key":"a","value":1},{"key":"b","value":2},{"key":"c","value":3},{"key":"d","value":4}]}}}`)
suite.assertQueryResult(m, "{root{size}}", `{"data":{"root":{"size":4}}}`)
suite.assertQueryResult(m, "{root{elements(count:0){value}}}", `{"data":{"root":{"elements":[]}}}`)
suite.assertQueryResult(m, "{root{elements(count:2){value}}}", `{"data":{"root":{"elements":[{"value":1},{"value":2}]}}}`)
suite.assertQueryResult(m, "{root{elements(count:3){key}}}", `{"data":{"root":{"elements":[{"key":"a"},{"key":"b"},{"key":"c"}]}}}`)
suite.assertQueryResult(m, "{root{elements(count: -1){key}}}", `{"data":{"root":{"elements":[]}}}`)
suite.assertQueryResult(m, "{root{elements(count:5){value}}}", `{"data":{"root":{"elements":[{"value":1},{"value":2},{"value":3},{"value":4}]}}}`)
suite.assertQueryResult(m, "{root{elements(at:-1,count:2){value}}}", `{"data":{"root":{"elements":[{"value":1},{"value":2}]}}}`)
suite.assertQueryResult(m, "{root{elements(at:0,count:2){value}}}", `{"data":{"root":{"elements":[{"value":1},{"value":2}]}}}`)
suite.assertQueryResult(m, "{root{elements(at:1,count:2){value}}}", `{"data":{"root":{"elements":[{"value":2},{"value":3}]}}}`)
suite.assertQueryResult(m, "{root{elements(at:2){value}}}", `{"data":{"root":{"elements":[{"value":3},{"value":4}]}}}`)
suite.assertQueryResult(m, "{root{elements(at:2,count:1){value}}}", `{"data":{"root":{"elements":[{"value":3}]}}}`)
suite.assertQueryResult(m, "{root{elements(at:2,count:0){value}}}", `{"data":{"root":{"elements":[]}}}`)
suite.assertQueryResult(m, "{root{elements(at:5){value}}}", `{"data":{"root":{"elements":[]}}}`)
suite.assertQueryResult(m, "{root{elements(at:2,count:10){value}}}", `{"data":{"root":{"elements":[{"value":3},{"value":4}]}}}`)
}
func (suite *QueryGraphQLSuite) TestMapOfStruct() {

View File

@@ -10,10 +10,10 @@ import (
"strings"
"github.com/attic-labs/graphql"
"github.com/attic-labs/noms/go/d"
"github.com/attic-labs/noms/go/hash"
"github.com/attic-labs/noms/go/types"
"github.com/attic-labs/graphql"
)
type typeMap map[typeMapKey]graphql.Type
@@ -222,29 +222,35 @@ var listArgs = graphql.FieldConfigArgument{
countKey: &graphql.ArgumentConfig{Type: graphql.Int},
}
func getListValues(v types.Value, args map[string]interface{}) (interface{}, error) {
l := v.(types.List)
idx := uint64(0)
count := l.Len()
func getBounds(l uint64, args map[string]interface{}) (uint64, uint64, bool) {
len := int64(l)
idx := int64(0)
count := int64(len)
if at, ok := args[atKey].(int); ok {
idx = uint64(at)
idx = int64(at)
}
if c, ok := args[countKey].(int); ok {
count = uint64(c)
count = int64(c)
}
// Clamp ranges
if count <= 0 || idx >= len {
return 0, 0, true
}
if idx < 0 {
idx = 0
}
if idx > l.Len() {
idx = l.Len()
if idx+count > len {
count = len - idx
}
if count < 0 {
count = 0
}
if idx+count > l.Len() {
count = l.Len() - idx
return uint64(idx), uint64(count), false
}
func getListValues(v types.Value, args map[string]interface{}) (interface{}, error) {
l := v.(types.List)
idx, count, empty := getBounds(l.Len(), args)
if empty {
return ([]interface{})(nil), nil
}
values := make([]interface{}, count)
@@ -257,63 +263,46 @@ func getListValues(v types.Value, args map[string]interface{}) (interface{}, err
}
var setArgs = graphql.FieldConfigArgument{
atKey: &graphql.ArgumentConfig{Type: graphql.Int},
countKey: &graphql.ArgumentConfig{Type: graphql.Int},
}
func getSetValues(v types.Value, args map[string]interface{}) (interface{}, error) {
// TODO: Refactor to share code between the collections.
s := v.(types.Set)
count := s.Len()
if c, ok := args[countKey].(int); ok {
count = uint64(c)
}
// Clamp ranges
if count < 0 {
count = 0
}
if count > s.Len() {
count = s.Len()
idx, count, empty := getBounds(s.Len(), args)
if empty {
return ([]interface{})(nil), nil
}
values := make([]interface{}, count)
i := uint64(0)
s.Iter(func(v types.Value) bool {
values[i] = maybeGetScalar(v)
i++
return i >= count
})
iter := s.IteratorAt(idx)
for i := uint64(0); i < count; i++ {
values[i] = maybeGetScalar(iter.Next())
}
return values, nil
}
var mapArgs = graphql.FieldConfigArgument{
atKey: &graphql.ArgumentConfig{Type: graphql.Int},
countKey: &graphql.ArgumentConfig{Type: graphql.Int},
}
func getMapValues(v types.Value, args map[string]interface{}) (interface{}, error) {
// TODO: Refactor to share code between the collections.
m := v.(types.Map)
count := m.Len()
if c, ok := args[countKey].(int); ok {
count = uint64(c)
}
// Clamp ranges
if count < 0 {
count = 0
}
if count > m.Len() {
count = m.Len()
idx, count, empty := getBounds(m.Len(), args)
if empty {
return ([]interface{})(nil), nil
}
values := make([]mapEntry, count)
i := uint64(0)
m.Iter(func(k, v types.Value) bool {
iter := m.IteratorAt(idx)
for i := uint64(0); i < count; i++ {
k, v := iter.Next()
values[i] = mapEntry{k, v}
i++
return i >= count
})
}
return values, nil
}