-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathuser-pet-connection.go
143 lines (122 loc) · 3.32 KB
/
user-pet-connection.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package main
import (
"context"
"encoding/base64"
"strconv"
"strings"
graphql "github.com/graph-gophers/graphql-go"
)
type petsConnArgs struct {
First *int32
After *graphql.ID
}
// PetsConnection returns nodes (pets) connected by edges (relationships)
func (u *UserResolver) PetsConnection(ctx context.Context, args petsConnArgs) (*UserPetsConnectionResolver, error) {
// query only the ID fields from the pets otherwise it would be wasteful
ids, err := u.db.getUserPetIDs(ctx, u.m.ID)
if err != nil {
return nil, err
}
from := 0
if args.After != nil {
b, err := base64.StdEncoding.DecodeString(string(*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 + 1
}
to := len(ids)
if args.First != nil {
to = from + int(*args.First)
if to > len(ids) {
to = len(ids)
}
}
upc := UserPetsConnectionResolver{
ids: ids,
from: from,
to: to,
}
return &upc, nil
}
// UserPetEdge is an edge (related node) that is returned in pagination
type UserPetEdge struct {
cursor graphql.ID
node PetResolver
}
// Cursor resolves the cursor for pagination
func (u *UserPetEdge) Cursor(ctx context.Context) graphql.ID {
return u.cursor
}
// Node resolves the node for pagination
func (u *UserPetEdge) Node(ctx context.Context) *PetResolver {
return &u.node
}
// PageInfo gives page info for pagination
type PageInfo struct {
startCursor graphql.ID
endCursor graphql.ID
hasNextPage bool
hasPreviousPage bool
}
// StartCursor ...
func (u *PageInfo) StartCursor(ctx context.Context) *graphql.ID {
return &u.startCursor
}
// EndCursor ...
func (u *PageInfo) EndCursor(ctx context.Context) *graphql.ID {
return &u.endCursor
}
// HasNextPage returns true if there are more results to show
func (u *PageInfo) HasNextPage(ctx context.Context) bool {
return u.hasNextPage
}
// HasPreviousPage returns true if there are results behind the current cursor position
func (u *PageInfo) HasPreviousPage(ctx context.Context) bool {
return u.hasPreviousPage
}
// UserPetsConnectionResolver is all the pets that are connected to a certain user
type UserPetsConnectionResolver struct {
db *DB
ids []int
from int
to int
}
// TotalCount gives the total amount of pets in UserPetsConnection
func (u UserPetsConnectionResolver) TotalCount(ctx context.Context) int32 {
return int32(len(u.ids))
}
// Edges gives a list of all the edges (related pets) that belong to a user
func (u *UserPetsConnectionResolver) Edges(ctx context.Context) (*[]*UserPetEdge, error) {
// query goes here because I know all of the ids that are needed. If I queried in the
// UserPetEdge resolver method, it would run multiple single queries
pets, err := u.db.getPetsByID(ctx, u.ids, u.from, u.to)
if err != nil {
return nil, err
}
l := make([]*UserPetEdge, u.to-u.from)
for i := range l {
l[i] = &UserPetEdge{
cursor: encodeCursor(u.from + i),
node: PetResolver{
db: u.db,
m: pets[i],
},
}
}
return &l, nil
}
// PageInfo resolves page info
func (u *UserPetsConnectionResolver) PageInfo(ctx context.Context) (*PageInfo, error) {
p := PageInfo{
startCursor: encodeCursor(u.from),
endCursor: encodeCursor(u.to - 1),
hasNextPage: u.to < len(u.ids),
hasPreviousPage: u.from > 0,
}
return &p, nil
}