mirror of
https://github.com/schollz/cowyo.git
synced 2023-08-10 21:13:00 +03:00
Vendoring
This commit is contained in:
127
vendor/github.com/shurcooL/graphql/internal/jsonutil/benchmark_test.go
generated
vendored
Normal file
127
vendor/github.com/shurcooL/graphql/internal/jsonutil/benchmark_test.go
generated
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
package jsonutil_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/shurcooL/graphql"
|
||||
"github.com/shurcooL/graphql/internal/jsonutil"
|
||||
)
|
||||
|
||||
func TestUnmarshalGraphQL_benchmark(t *testing.T) {
|
||||
/*
|
||||
query {
|
||||
viewer {
|
||||
login
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
*/
|
||||
type query struct {
|
||||
Viewer struct {
|
||||
Login graphql.String
|
||||
CreatedAt time.Time
|
||||
}
|
||||
}
|
||||
var got query
|
||||
err := jsonutil.UnmarshalGraphQL([]byte(`{
|
||||
"viewer": {
|
||||
"login": "shurcooL-test",
|
||||
"createdAt": "2017-06-29T04:12:01Z"
|
||||
}
|
||||
}`), &got)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var want query
|
||||
want.Viewer.Login = "shurcooL-test"
|
||||
want.Viewer.CreatedAt = time.Unix(1498709521, 0).UTC()
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Error("not equal")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkUnmarshalGraphQL(b *testing.B) {
|
||||
type query struct {
|
||||
Viewer struct {
|
||||
Login graphql.String
|
||||
CreatedAt time.Time
|
||||
}
|
||||
}
|
||||
for i := 0; i < b.N; i++ {
|
||||
now := time.Now().UTC()
|
||||
var got query
|
||||
err := jsonutil.UnmarshalGraphQL([]byte(`{
|
||||
"viewer": {
|
||||
"login": "shurcooL-test",
|
||||
"createdAt": "`+now.Format(time.RFC3339Nano)+`"
|
||||
}
|
||||
}`), &got)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
var want query
|
||||
want.Viewer.Login = "shurcooL-test"
|
||||
want.Viewer.CreatedAt = now
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
b.Error("not equal")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkJSONUnmarshal(b *testing.B) {
|
||||
type query struct {
|
||||
Viewer struct {
|
||||
Login graphql.String
|
||||
CreatedAt time.Time
|
||||
}
|
||||
}
|
||||
for i := 0; i < b.N; i++ {
|
||||
now := time.Now().UTC()
|
||||
var got query
|
||||
err := json.Unmarshal([]byte(`{
|
||||
"viewer": {
|
||||
"login": "shurcooL-test",
|
||||
"createdAt": "`+now.Format(time.RFC3339Nano)+`"
|
||||
}
|
||||
}`), &got)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
var want query
|
||||
want.Viewer.Login = "shurcooL-test"
|
||||
want.Viewer.CreatedAt = now
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
b.Error("not equal")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkJSONTokenize(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
now := time.Now().UTC()
|
||||
dec := json.NewDecoder(strings.NewReader(`{
|
||||
"viewer": {
|
||||
"login": "shurcooL-test",
|
||||
"createdAt": "` + now.Format(time.RFC3339Nano) + `"
|
||||
}
|
||||
}`))
|
||||
var tokens int
|
||||
for {
|
||||
_, err := dec.Token()
|
||||
if err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
tokens++
|
||||
}
|
||||
if tokens != 9 {
|
||||
b.Error("not 9 tokens")
|
||||
}
|
||||
}
|
||||
}
|
||||
308
vendor/github.com/shurcooL/graphql/internal/jsonutil/graphql.go
generated
vendored
Normal file
308
vendor/github.com/shurcooL/graphql/internal/jsonutil/graphql.go
generated
vendored
Normal file
@@ -0,0 +1,308 @@
|
||||
// Package jsonutil provides a function for decoding JSON
|
||||
// into a GraphQL query data structure.
|
||||
package jsonutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// UnmarshalGraphQL parses the JSON-encoded GraphQL response data and stores
|
||||
// the result in the GraphQL query data structure pointed to by v.
|
||||
//
|
||||
// The implementation is created on top of the JSON tokenizer available
|
||||
// in "encoding/json".Decoder.
|
||||
func UnmarshalGraphQL(data []byte, v interface{}) error {
|
||||
dec := json.NewDecoder(bytes.NewReader(data))
|
||||
dec.UseNumber()
|
||||
err := (&decoder{tokenizer: dec}).Decode(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tok, err := dec.Token()
|
||||
switch err {
|
||||
case io.EOF:
|
||||
// Expect to get io.EOF. There shouldn't be any more
|
||||
// tokens left after we've decoded v successfully.
|
||||
return nil
|
||||
case nil:
|
||||
return fmt.Errorf("invalid token '%v' after top-level value", tok)
|
||||
default:
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// decoder is a JSON decoder that performs custom unmarshaling behavior
|
||||
// for GraphQL query data structures. It's implemented on top of a JSON tokenizer.
|
||||
type decoder struct {
|
||||
tokenizer interface {
|
||||
Token() (json.Token, error)
|
||||
}
|
||||
|
||||
// Stack of what part of input JSON we're in the middle of - objects, arrays.
|
||||
parseState []json.Delim
|
||||
|
||||
// Stacks of values where to unmarshal.
|
||||
// The top of each stack is the reflect.Value where to unmarshal next JSON value.
|
||||
//
|
||||
// The reason there's more than one stack is because we might be unmarshaling
|
||||
// a single JSON value into multiple GraphQL fragments or embedded structs, so
|
||||
// we keep track of them all.
|
||||
vs [][]reflect.Value
|
||||
}
|
||||
|
||||
// Decode decodes a single JSON value from d.tokenizer into v.
|
||||
func (d *decoder) Decode(v interface{}) error {
|
||||
rv := reflect.ValueOf(v)
|
||||
if rv.Kind() != reflect.Ptr {
|
||||
return fmt.Errorf("cannot decode into non-pointer %T", v)
|
||||
}
|
||||
d.vs = [][]reflect.Value{{rv.Elem()}}
|
||||
return d.decode()
|
||||
}
|
||||
|
||||
// decode decodes a single JSON value from d.tokenizer into d.vs.
|
||||
func (d *decoder) decode() error {
|
||||
// The loop invariant is that the top of each d.vs stack
|
||||
// is where we try to unmarshal the next JSON value we see.
|
||||
for len(d.vs) > 0 {
|
||||
tok, err := d.tokenizer.Token()
|
||||
if err == io.EOF {
|
||||
return errors.New("unexpected end of JSON input")
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch {
|
||||
|
||||
// Are we inside an object and seeing next key (rather than end of object)?
|
||||
case d.state() == '{' && tok != json.Delim('}'):
|
||||
key, ok := tok.(string)
|
||||
if !ok {
|
||||
return errors.New("unexpected non-key in JSON input")
|
||||
}
|
||||
someFieldExist := false
|
||||
for i := range d.vs {
|
||||
v := d.vs[i][len(d.vs[i])-1]
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
var f reflect.Value
|
||||
if v.Kind() == reflect.Struct {
|
||||
f = fieldByGraphQLName(v, key)
|
||||
if f.IsValid() {
|
||||
someFieldExist = true
|
||||
}
|
||||
}
|
||||
d.vs[i] = append(d.vs[i], f)
|
||||
}
|
||||
if !someFieldExist {
|
||||
return fmt.Errorf("struct field for %s doesn't exist in any of %v places to unmarshal", key, len(d.vs))
|
||||
}
|
||||
|
||||
// We've just consumed the current token, which was the key.
|
||||
// Read the next token, which should be the value, and let the rest of code process it.
|
||||
tok, err = d.tokenizer.Token()
|
||||
if err == io.EOF {
|
||||
return errors.New("unexpected end of JSON input")
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Are we inside an array and seeing next value (rather than end of array)?
|
||||
case d.state() == '[' && tok != json.Delim(']'):
|
||||
someSliceExist := false
|
||||
for i := range d.vs {
|
||||
v := d.vs[i][len(d.vs[i])-1]
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
var f reflect.Value
|
||||
if v.Kind() == reflect.Slice {
|
||||
v.Set(reflect.Append(v, reflect.Zero(v.Type().Elem()))) // v = append(v, T).
|
||||
f = v.Index(v.Len() - 1)
|
||||
someSliceExist = true
|
||||
}
|
||||
d.vs[i] = append(d.vs[i], f)
|
||||
}
|
||||
if !someSliceExist {
|
||||
return fmt.Errorf("slice doesn't exist in any of %v places to unmarshal", len(d.vs))
|
||||
}
|
||||
}
|
||||
|
||||
switch tok := tok.(type) {
|
||||
case string, json.Number, bool, nil:
|
||||
// Value.
|
||||
|
||||
for i := range d.vs {
|
||||
v := d.vs[i][len(d.vs[i])-1]
|
||||
if !v.IsValid() {
|
||||
continue
|
||||
}
|
||||
err := unmarshalValue(tok, v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
d.popAllVs()
|
||||
|
||||
case json.Delim:
|
||||
switch tok {
|
||||
case '{':
|
||||
// Start of object.
|
||||
|
||||
d.pushState(tok)
|
||||
|
||||
frontier := make([]reflect.Value, len(d.vs)) // Places to look for GraphQL fragments/embedded structs.
|
||||
for i := range d.vs {
|
||||
v := d.vs[i][len(d.vs[i])-1]
|
||||
frontier[i] = v
|
||||
// TODO: Do this recursively or not? Add a test case if needed.
|
||||
if v.Kind() == reflect.Ptr && v.IsNil() {
|
||||
v.Set(reflect.New(v.Type().Elem())) // v = new(T).
|
||||
}
|
||||
}
|
||||
// Find GraphQL fragments/embedded structs recursively, adding to frontier
|
||||
// as new ones are discovered and exploring them further.
|
||||
for len(frontier) > 0 {
|
||||
v := frontier[0]
|
||||
frontier = frontier[1:]
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
if v.Kind() != reflect.Struct {
|
||||
continue
|
||||
}
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
if isGraphQLFragment(v.Type().Field(i)) || v.Type().Field(i).Anonymous {
|
||||
// Add GraphQL fragment or embedded struct.
|
||||
d.vs = append(d.vs, []reflect.Value{v.Field(i)})
|
||||
frontier = append(frontier, v.Field(i))
|
||||
}
|
||||
}
|
||||
}
|
||||
case '[':
|
||||
// Start of array.
|
||||
|
||||
d.pushState(tok)
|
||||
|
||||
for i := range d.vs {
|
||||
v := d.vs[i][len(d.vs[i])-1]
|
||||
// TODO: Confirm this is needed, write a test case.
|
||||
//if v.Kind() == reflect.Ptr && v.IsNil() {
|
||||
// v.Set(reflect.New(v.Type().Elem())) // v = new(T).
|
||||
//}
|
||||
|
||||
// Reset slice to empty (in case it had non-zero initial value).
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
if v.Kind() != reflect.Slice {
|
||||
continue
|
||||
}
|
||||
v.Set(reflect.MakeSlice(v.Type(), 0, 0)) // v = make(T, 0, 0).
|
||||
}
|
||||
case '}', ']':
|
||||
// End of object or array.
|
||||
d.popAllVs()
|
||||
d.popState()
|
||||
default:
|
||||
return errors.New("unexpected delimiter in JSON input")
|
||||
}
|
||||
default:
|
||||
return errors.New("unexpected token in JSON input")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// pushState pushes a new parse state s onto the stack.
|
||||
func (d *decoder) pushState(s json.Delim) {
|
||||
d.parseState = append(d.parseState, s)
|
||||
}
|
||||
|
||||
// popState pops a parse state (already obtained) off the stack.
|
||||
// The stack must be non-empty.
|
||||
func (d *decoder) popState() {
|
||||
d.parseState = d.parseState[:len(d.parseState)-1]
|
||||
}
|
||||
|
||||
// state reports the parse state on top of stack, or 0 if empty.
|
||||
func (d *decoder) state() json.Delim {
|
||||
if len(d.parseState) == 0 {
|
||||
return 0
|
||||
}
|
||||
return d.parseState[len(d.parseState)-1]
|
||||
}
|
||||
|
||||
// popAllVs pops from all d.vs stacks, keeping only non-empty ones.
|
||||
func (d *decoder) popAllVs() {
|
||||
var nonEmpty [][]reflect.Value
|
||||
for i := range d.vs {
|
||||
d.vs[i] = d.vs[i][:len(d.vs[i])-1]
|
||||
if len(d.vs[i]) > 0 {
|
||||
nonEmpty = append(nonEmpty, d.vs[i])
|
||||
}
|
||||
}
|
||||
d.vs = nonEmpty
|
||||
}
|
||||
|
||||
// fieldByGraphQLName returns a struct field of struct v that matches GraphQL name,
|
||||
// or invalid reflect.Value if none found.
|
||||
func fieldByGraphQLName(v reflect.Value, name string) reflect.Value {
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
if hasGraphQLName(v.Type().Field(i), name) {
|
||||
return v.Field(i)
|
||||
}
|
||||
}
|
||||
return reflect.Value{}
|
||||
}
|
||||
|
||||
// hasGraphQLName reports whether struct field f has GraphQL name.
|
||||
func hasGraphQLName(f reflect.StructField, name string) bool {
|
||||
value, ok := f.Tag.Lookup("graphql")
|
||||
if !ok {
|
||||
// TODO: caseconv package is relatively slow. Optimize it, then consider using it here.
|
||||
//return caseconv.MixedCapsToLowerCamelCase(f.Name) == name
|
||||
return strings.EqualFold(f.Name, name)
|
||||
}
|
||||
value = strings.TrimSpace(value) // TODO: Parse better.
|
||||
if strings.HasPrefix(value, "...") {
|
||||
// GraphQL fragment. It doesn't have a name.
|
||||
return false
|
||||
}
|
||||
if i := strings.Index(value, "("); i != -1 {
|
||||
value = value[:i]
|
||||
}
|
||||
if i := strings.Index(value, ":"); i != -1 {
|
||||
value = value[:i]
|
||||
}
|
||||
return strings.TrimSpace(value) == name
|
||||
}
|
||||
|
||||
// isGraphQLFragment reports whether struct field f is a GraphQL fragment.
|
||||
func isGraphQLFragment(f reflect.StructField) bool {
|
||||
value, ok := f.Tag.Lookup("graphql")
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
value = strings.TrimSpace(value) // TODO: Parse better.
|
||||
return strings.HasPrefix(value, "...")
|
||||
}
|
||||
|
||||
// unmarshalValue unmarshals JSON value into v.
|
||||
func unmarshalValue(value json.Token, v reflect.Value) error {
|
||||
b, err := json.Marshal(value) // TODO: Short-circuit (if profiling says it's worth it).
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !v.CanAddr() {
|
||||
return fmt.Errorf("value %v is not addressable", v)
|
||||
}
|
||||
return json.Unmarshal(b, v.Addr().Interface())
|
||||
}
|
||||
382
vendor/github.com/shurcooL/graphql/internal/jsonutil/graphql_test.go
generated
vendored
Normal file
382
vendor/github.com/shurcooL/graphql/internal/jsonutil/graphql_test.go
generated
vendored
Normal file
@@ -0,0 +1,382 @@
|
||||
package jsonutil_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/shurcooL/graphql"
|
||||
"github.com/shurcooL/graphql/internal/jsonutil"
|
||||
)
|
||||
|
||||
func TestUnmarshalGraphQL(t *testing.T) {
|
||||
/*
|
||||
query {
|
||||
me {
|
||||
name
|
||||
height
|
||||
}
|
||||
}
|
||||
*/
|
||||
type query struct {
|
||||
Me struct {
|
||||
Name graphql.String
|
||||
Height graphql.Float
|
||||
}
|
||||
}
|
||||
var got query
|
||||
err := jsonutil.UnmarshalGraphQL([]byte(`{
|
||||
"me": {
|
||||
"name": "Luke Skywalker",
|
||||
"height": 1.72
|
||||
}
|
||||
}`), &got)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var want query
|
||||
want.Me.Name = "Luke Skywalker"
|
||||
want.Me.Height = 1.72
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Error("not equal")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalGraphQL_graphqlTag(t *testing.T) {
|
||||
type query struct {
|
||||
Foo graphql.String `graphql:"baz"`
|
||||
}
|
||||
var got query
|
||||
err := jsonutil.UnmarshalGraphQL([]byte(`{
|
||||
"baz": "bar"
|
||||
}`), &got)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
want := query{
|
||||
Foo: "bar",
|
||||
}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Error("not equal")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalGraphQL_jsonTag(t *testing.T) {
|
||||
type query struct {
|
||||
Foo graphql.String `json:"baz"`
|
||||
}
|
||||
var got query
|
||||
err := jsonutil.UnmarshalGraphQL([]byte(`{
|
||||
"foo": "bar"
|
||||
}`), &got)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
want := query{
|
||||
Foo: "bar",
|
||||
}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Error("not equal")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalGraphQL_array(t *testing.T) {
|
||||
type query struct {
|
||||
Foo []graphql.String
|
||||
Bar []graphql.String
|
||||
Baz []graphql.String
|
||||
}
|
||||
var got query
|
||||
err := jsonutil.UnmarshalGraphQL([]byte(`{
|
||||
"foo": [
|
||||
"bar",
|
||||
"baz"
|
||||
],
|
||||
"bar": [],
|
||||
"baz": null
|
||||
}`), &got)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
want := query{
|
||||
Foo: []graphql.String{"bar", "baz"},
|
||||
Bar: []graphql.String{},
|
||||
Baz: []graphql.String(nil),
|
||||
}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Error("not equal")
|
||||
}
|
||||
}
|
||||
|
||||
// When unmarshaling into an array, its initial value should be overwritten
|
||||
// (rather than appended to).
|
||||
func TestUnmarshalGraphQL_arrayReset(t *testing.T) {
|
||||
var got = []string{"initial"}
|
||||
err := jsonutil.UnmarshalGraphQL([]byte(`["bar", "baz"]`), &got)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
want := []string{"bar", "baz"}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Error("not equal")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalGraphQL_objectArray(t *testing.T) {
|
||||
type query struct {
|
||||
Foo []struct {
|
||||
Name graphql.String
|
||||
}
|
||||
}
|
||||
var got query
|
||||
err := jsonutil.UnmarshalGraphQL([]byte(`{
|
||||
"foo": [
|
||||
{"name": "bar"},
|
||||
{"name": "baz"}
|
||||
]
|
||||
}`), &got)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
want := query{
|
||||
Foo: []struct{ Name graphql.String }{
|
||||
{"bar"},
|
||||
{"baz"},
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Error("not equal")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalGraphQL_pointer(t *testing.T) {
|
||||
type query struct {
|
||||
Foo *graphql.String
|
||||
Bar *graphql.String
|
||||
}
|
||||
var got query
|
||||
got.Bar = new(graphql.String) // Test that got.Bar gets set to nil.
|
||||
err := jsonutil.UnmarshalGraphQL([]byte(`{
|
||||
"foo": "foo",
|
||||
"bar": null
|
||||
}`), &got)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
want := query{
|
||||
Foo: graphql.NewString("foo"),
|
||||
Bar: nil,
|
||||
}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Error("not equal")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalGraphQL_objectPointerArray(t *testing.T) {
|
||||
type query struct {
|
||||
Foo []*struct {
|
||||
Name graphql.String
|
||||
}
|
||||
}
|
||||
var got query
|
||||
err := jsonutil.UnmarshalGraphQL([]byte(`{
|
||||
"foo": [
|
||||
{"name": "bar"},
|
||||
null,
|
||||
{"name": "baz"}
|
||||
]
|
||||
}`), &got)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
want := query{
|
||||
Foo: []*struct{ Name graphql.String }{
|
||||
{"bar"},
|
||||
nil,
|
||||
{"baz"},
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Error("not equal")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalGraphQL_pointerWithInlineFragment(t *testing.T) {
|
||||
type actor struct {
|
||||
User struct {
|
||||
DatabaseID uint64
|
||||
} `graphql:"... on User"`
|
||||
Login string
|
||||
}
|
||||
type query struct {
|
||||
Author actor
|
||||
Editor *actor
|
||||
}
|
||||
var got query
|
||||
err := jsonutil.UnmarshalGraphQL([]byte(`{
|
||||
"author": {
|
||||
"databaseId": 1,
|
||||
"login": "test1"
|
||||
},
|
||||
"editor": {
|
||||
"databaseId": 2,
|
||||
"login": "test2"
|
||||
}
|
||||
}`), &got)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var want query
|
||||
want.Author = actor{
|
||||
User: struct{ DatabaseID uint64 }{1},
|
||||
Login: "test1",
|
||||
}
|
||||
want.Editor = &actor{
|
||||
User: struct{ DatabaseID uint64 }{2},
|
||||
Login: "test2",
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Error("not equal")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalGraphQL_multipleValues(t *testing.T) {
|
||||
type query struct {
|
||||
Foo graphql.String
|
||||
}
|
||||
err := jsonutil.UnmarshalGraphQL([]byte(`{"foo": "bar"}{"foo": "baz"}`), new(query))
|
||||
if err == nil {
|
||||
t.Fatal("got error: nil, want: non-nil")
|
||||
}
|
||||
if got, want := err.Error(), "invalid token '{' after top-level value"; got != want {
|
||||
t.Errorf("got error: %v, want: %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalGraphQL_union(t *testing.T) {
|
||||
/*
|
||||
{
|
||||
__typename
|
||||
... on ClosedEvent {
|
||||
createdAt
|
||||
actor {login}
|
||||
}
|
||||
... on ReopenedEvent {
|
||||
createdAt
|
||||
actor {login}
|
||||
}
|
||||
}
|
||||
*/
|
||||
type actor struct{ Login graphql.String }
|
||||
type closedEvent struct {
|
||||
Actor actor
|
||||
CreatedAt time.Time
|
||||
}
|
||||
type reopenedEvent struct {
|
||||
Actor actor
|
||||
CreatedAt time.Time
|
||||
}
|
||||
type issueTimelineItem struct {
|
||||
Typename string `graphql:"__typename"`
|
||||
ClosedEvent closedEvent `graphql:"... on ClosedEvent"`
|
||||
ReopenedEvent reopenedEvent `graphql:"... on ReopenedEvent"`
|
||||
}
|
||||
var got issueTimelineItem
|
||||
err := jsonutil.UnmarshalGraphQL([]byte(`{
|
||||
"__typename": "ClosedEvent",
|
||||
"createdAt": "2017-06-29T04:12:01Z",
|
||||
"actor": {
|
||||
"login": "shurcooL-test"
|
||||
}
|
||||
}`), &got)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
want := issueTimelineItem{
|
||||
Typename: "ClosedEvent",
|
||||
ClosedEvent: closedEvent{
|
||||
Actor: actor{
|
||||
Login: "shurcooL-test",
|
||||
},
|
||||
CreatedAt: time.Unix(1498709521, 0).UTC(),
|
||||
},
|
||||
ReopenedEvent: reopenedEvent{
|
||||
Actor: actor{
|
||||
Login: "shurcooL-test",
|
||||
},
|
||||
CreatedAt: time.Unix(1498709521, 0).UTC(),
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Error("not equal")
|
||||
}
|
||||
}
|
||||
|
||||
// Issue https://github.com/shurcooL/githubql/issues/18.
|
||||
func TestUnmarshalGraphQL_arrayInsideInlineFragment(t *testing.T) {
|
||||
/*
|
||||
query {
|
||||
search(type: ISSUE, first: 1, query: "type:pr repo:owner/name") {
|
||||
nodes {
|
||||
... on PullRequest {
|
||||
commits(last: 1) {
|
||||
nodes {
|
||||
url
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
type query struct {
|
||||
Search struct {
|
||||
Nodes []struct {
|
||||
PullRequest struct {
|
||||
Commits struct {
|
||||
Nodes []struct {
|
||||
URL string `graphql:"url"`
|
||||
}
|
||||
} `graphql:"commits(last: 1)"`
|
||||
} `graphql:"... on PullRequest"`
|
||||
}
|
||||
} `graphql:"search(type: ISSUE, first: 1, query: \"type:pr repo:owner/name\")"`
|
||||
}
|
||||
var got query
|
||||
err := jsonutil.UnmarshalGraphQL([]byte(`{
|
||||
"search": {
|
||||
"nodes": [
|
||||
{
|
||||
"commits": {
|
||||
"nodes": [
|
||||
{
|
||||
"url": "https://example.org/commit/49e1"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}`), &got)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var want query
|
||||
want.Search.Nodes = make([]struct {
|
||||
PullRequest struct {
|
||||
Commits struct {
|
||||
Nodes []struct {
|
||||
URL string `graphql:"url"`
|
||||
}
|
||||
} `graphql:"commits(last: 1)"`
|
||||
} `graphql:"... on PullRequest"`
|
||||
}, 1)
|
||||
want.Search.Nodes[0].PullRequest.Commits.Nodes = make([]struct {
|
||||
URL string `graphql:"url"`
|
||||
}, 1)
|
||||
want.Search.Nodes[0].PullRequest.Commits.Nodes[0].URL = "https://example.org/commit/49e1"
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Error("not equal")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user