Skip to content

Commit

Permalink
star wars example: friendsConnection
Browse files Browse the repository at this point in the history
  • Loading branch information
neelance committed Oct 24, 2016
1 parent bec4536 commit 746da4b
Show file tree
Hide file tree
Showing 4 changed files with 200 additions and 23 deletions.
104 changes: 84 additions & 20 deletions example/starwars/starwars.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@
// Source: https://github.com/graphql/graphql.github.io/blob/source/site/_core/swapiSchema.js
package starwars

import "strings"
import (
"encoding/base64"
"fmt"
"strconv"
"strings"
)

var Schema = `
schema {
Expand Down Expand Up @@ -343,7 +348,7 @@ type characterResolver interface {
ID() string
Name() string
Friends() *[]characterResolver
FriendsConnection(friendsConenctionArgs) *friendsConnectionResolver
FriendsConnection(friendsConenctionArgs) (*friendsConnectionResolver, error)
AppearsIn() []string
ToHuman() (*humanResolver, bool)
ToDroid() (*droidResolver, bool)
Expand Down Expand Up @@ -377,8 +382,8 @@ func (r *humanResolver) Friends() *[]characterResolver {
return resolveCharacters(r.h.Friends)
}

func (r *humanResolver) FriendsConnection(args friendsConenctionArgs) *friendsConnectionResolver {
panic("TODO")
func (r *humanResolver) FriendsConnection(args friendsConenctionArgs) (*friendsConnectionResolver, error) {
return newFriendsConnectionResolver(r.h.Friends, args)
}

func (r *humanResolver) AppearsIn() []string {
Expand Down Expand Up @@ -421,8 +426,8 @@ func (r *droidResolver) Friends() *[]characterResolver {
return resolveCharacters(r.d.Friends)
}

func (r *droidResolver) FriendsConnection(args friendsConenctionArgs) *friendsConnectionResolver {
panic("TODO")
func (r *droidResolver) FriendsConnection(args friendsConenctionArgs) (*friendsConnectionResolver, error) {
return newFriendsConnectionResolver(r.d.Friends, args)
}

func (r *droidResolver) AppearsIn() []string {
Expand Down Expand Up @@ -496,16 +501,23 @@ func convertLength(meters float64, unit string) float64 {
func resolveCharacters(ids []string) *[]characterResolver {
var characters []characterResolver
for _, id := range ids {
if h, ok := humanData[id]; ok {
characters = append(characters, &humanResolver{h})
}
if d, ok := droidData[id]; ok {
characters = append(characters, &droidResolver{d})
if c := resolveCharacter(id); c != nil {
characters = append(characters, c)
}
}
return &characters
}

func resolveCharacter(id string) characterResolver {
if h, ok := humanData[id]; ok {
return &humanResolver{h}
}
if d, ok := droidData[id]; ok {
return &droidResolver{d}
}
return nil
}

type reviewResolver struct {
}

Expand All @@ -518,46 +530,98 @@ func (r *reviewResolver) Commentary() *string {
}

type friendsConnectionResolver struct {
ids []string
from int
to int
}

func newFriendsConnectionResolver(ids []string, args friendsConenctionArgs) (*friendsConnectionResolver, error) {
from := 0
if args.After != "" {
b, err := base64.StdEncoding.DecodeString(args.After)
if err != nil {
return nil, err
}
i, err := strconv.Atoi(strings.TrimPrefix(string(b), "cursor"))
if err != nil {
return nil, err
}
from = i
}

to := len(ids)
if args.First != 0 {
to = from + int(args.First)
}
if to > len(ids)-from {
to = len(ids) - from
}

return &friendsConnectionResolver{
ids: ids,
from: from,
to: to,
}, nil
}

func (r *friendsConnectionResolver) TotalCount() int32 {
panic("TODO")
return int32(len(r.ids))
}

func (r *friendsConnectionResolver) Edges() *[]*friendsEdgeResolver {
panic("TODO")
l := make([]*friendsEdgeResolver, r.to-r.from)
for i := range l {
l[i] = &friendsEdgeResolver{
cursor: encodeCursor(r.from + i),
id: r.ids[r.from+i],
}
}
return &l
}

func (r *friendsConnectionResolver) Friends() *[]characterResolver {
panic("TODO")
return resolveCharacters(r.ids[r.from:r.to])
}

func (r *friendsConnectionResolver) PageInfo() *pageInfoResolver {
panic("TODO")
return &pageInfoResolver{
startCursor: encodeCursor(r.from),
endCursor: encodeCursor(r.to - 1),
hasNextPage: r.to < len(r.ids),
}
}

func encodeCursor(i int) string {
return base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("cursor%d", i+1)))
}

type friendsEdgeResolver struct {
cursor string
id string
}

func (r *friendsEdgeResolver) Cursor() string {
panic("TODO")
return r.cursor
}

func (r *friendsEdgeResolver) Node() characterResolver {
panic("TODO")
return resolveCharacter(r.id)
}

type pageInfoResolver struct {
startCursor string
endCursor string
hasNextPage bool
}

func (r *pageInfoResolver) StartCursor() *string {
panic("TODO")
return &r.startCursor
}

func (r *pageInfoResolver) EndCursor() *string {
panic("TODO")
return &r.endCursor
}

func (r *pageInfoResolver) HasNextPage() bool {
panic("TODO")
return r.hasNextPage
}
116 changes: 116 additions & 0 deletions graphql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,118 @@ var tests = []struct {
`,
},

{
name: "StarWarsConnections1",
schema: starwars.Schema,
resolver: &starwars.Resolver{},
query: `
{
hero {
name
friendsConnection {
totalCount
pageInfo {
startCursor
endCursor
hasNextPage
}
edges {
cursor
node {
name
}
}
}
}
}
`,
result: `
{
"hero": {
"name": "R2-D2",
"friendsConnection": {
"totalCount": 3,
"pageInfo": {
"startCursor": "Y3Vyc29yMQ==",
"endCursor": "Y3Vyc29yMw==",
"hasNextPage": false
},
"edges": [
{
"cursor": "Y3Vyc29yMQ==",
"node": {
"name": "Luke Skywalker"
}
},
{
"cursor": "Y3Vyc29yMg==",
"node": {
"name": "Han Solo"
}
},
{
"cursor": "Y3Vyc29yMw==",
"node": {
"name": "Leia Organa"
}
}
]
}
}
}
`,
},

{
name: "StarWarsConnections2",
schema: starwars.Schema,
resolver: &starwars.Resolver{},
query: `
{
hero {
name
friendsConnection(first: 1, after: "Y3Vyc29yMQ==") {
totalCount
pageInfo {
startCursor
endCursor
hasNextPage
}
edges {
cursor
node {
name
}
}
}
}
}
`,
result: `
{
"hero": {
"name": "R2-D2",
"friendsConnection": {
"totalCount": 3,
"pageInfo": {
"startCursor": "Y3Vyc29yMg==",
"endCursor": "Y3Vyc29yMg==",
"hasNextPage": true
},
"edges": [
{
"cursor": "Y3Vyc29yMg==",
"node": {
"name": "Han Solo"
}
}
]
}
}
}
`,
},

{
name: "StarWarsIntrospection1",
schema: starwars.Schema,
Expand Down Expand Up @@ -845,6 +957,10 @@ func TestAll(t *testing.T) {
t.Fatal(err)
}

if len(result.Errors) != 0 {
t.Fatal(result.Errors[0])
}

got, err := json.Marshal(result.Data)
if err != nil {
t.Fatal(err)
Expand Down
2 changes: 0 additions & 2 deletions internal/exec/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,6 @@ func makeFieldExecs(s *schema.Schema, typeName string, fields map[string]*schema
return nil, fmt.Errorf("method %q of %s has too many return values", m.Name, resolverType)
}

// TODO type check result

hasError := m.Type.NumOut() == 2
if hasError {
if m.Type.Out(1) != errorType {
Expand Down
1 change: 0 additions & 1 deletion internal/query/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,6 @@ func parseArguments(l *lexer.Lexer) map[string]Value {
name, value := parseArgument(l)
args[name] = value
for l.Peek() != ')' {
l.ConsumeToken(',')
name, value := parseArgument(l)
args[name] = value
}
Expand Down

0 comments on commit 746da4b

Please sign in to comment.