-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathconnection.go
142 lines (118 loc) · 3.32 KB
/
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
package cursor
import (
"errors"
)
var (
ErrConflictingArguments = errors.New("first and last cannot be used together")
ErrInvalidFirst = errors.New("first argument must be a non-negative integer")
ErrInvalidLast = errors.New("last argument must be a non-negative integer")
)
// Connection is a generic connection type that is used to paginate results.
type Connection[T any] struct {
edges Edges[T]
pageInfo PageInfo
}
// New creates a new Pages object. The pages object is used to paginate
func New[T any](nodes []T, cursor func(T) string, args ...Argument) (Connection[T], error) {
var err error
var arguments arguments
for _, arg := range args {
if argErr := arg(&arguments); argErr != nil {
err = errors.Join(err, argErr)
}
}
if err != nil {
// We want to parse all the arguments before returning the error.
return Connection[T]{
edges: Edges[T]{},
}, err
}
edges := newEdges(nodes, cursor)
trimmed := edges.applyCursor(arguments.after, arguments.before)
trimmed, err = trimmed.trimEdges(arguments.first, arguments.last)
if err != nil {
return Connection[T]{
edges: Edges[T]{},
}, err
}
return Connection[T]{
edges: trimmed,
pageInfo: PageInfo{
startCursor: trimmed.startCursor(),
endCursor: trimmed.endCursor(),
hasPreviousPage: trimmed.hasPreviousPage(edges, arguments),
hasNextPage: trimmed.hasNextPage(edges, arguments),
},
}, nil
}
// PageInfo returns the page info for the connection.
func (p *Connection[T]) PageInfo() PageInfo {
return p.pageInfo
}
// Edges returns the edges for the connection.
func (p *Connection[T]) Edges() []Edge[T] {
return p.edges
}
type PageInfo struct {
startCursor *string
endCursor *string
hasPreviousPage bool
hasNextPage bool
}
// StartCursor returns the start cursor for the connection.
func (p *PageInfo) StartCursor() *string {
return p.startCursor
}
// EndCursor returns the end cursor for the connection.
func (p *PageInfo) EndCursor() *string {
return p.endCursor
}
// HasPreviousPage returns true if there is a previous page.
func (p *PageInfo) HasPreviousPage() bool {
return p.hasPreviousPage
}
// HasNextPage returns true if there is a next page.
func (p *PageInfo) HasNextPage() bool {
return p.hasNextPage
}
type Argument func(*arguments) error
type arguments struct {
first *int // first limits the number of results returned from the after cursor.
after *string // after is the cursor to start from.
last *int // last limits the number of results returned up to the the before cursor.
before *string // before is the cursor to start from.
}
// Before sets the before option for the connection.
func Before(before *string) Argument {
return func(p *arguments) error {
p.before = before
return nil
}
}
// After sets the after option for the connection.
func After(after *string) Argument {
return func(p *arguments) error {
p.after = after
return nil
}
}
// First sets the first option for the connection.
func First(first *int) Argument {
return func(p *arguments) error {
if p.last != nil {
return ErrConflictingArguments
}
p.first = first
return nil
}
}
// Last sets the last option for the connection.
func Last(last *int) Argument {
return func(p *arguments) error {
if p.first != nil {
return ErrConflictingArguments
}
p.last = last
return nil
}
}