1
- //go:generate genny -in=connection_template.go -out=gen_lazy_bug.go gen "Name=LazyBug NodeType=entity.Id EdgeType=LazyBugEdge ConnectionType=models.BugConnection"
2
- //go:generate genny -in=connection_template.go -out=gen_lazy_identity.go gen "Name=LazyIdentity NodeType=entity.Id EdgeType=LazyIdentityEdge ConnectionType=models.IdentityConnection"
3
- //go:generate genny -in=connection_template.go -out=gen_identity.go gen "Name=Identity NodeType=models.IdentityWrapper EdgeType=models.IdentityEdge ConnectionType=models.IdentityConnection"
4
- //go:generate genny -in=connection_template.go -out=gen_operation.go gen "Name=Operation NodeType=dag.Operation EdgeType=models.OperationEdge ConnectionType=models.OperationConnection"
5
- //go:generate genny -in=connection_template.go -out=gen_comment.go gen "Name=Comment NodeType=bug.Comment EdgeType=models.CommentEdge ConnectionType=models.CommentConnection"
6
- //go:generate genny -in=connection_template.go -out=gen_timeline.go gen "Name=TimelineItem NodeType=bug.TimelineItem EdgeType=models.TimelineItemEdge ConnectionType=models.TimelineItemConnection"
7
- //go:generate genny -in=connection_template.go -out=gen_label.go gen "Name=Label NodeType=bug.Label EdgeType=models.LabelEdge ConnectionType=models.LabelConnection"
8
-
9
1
// Package connections implement a generic GraphQL relay connection
10
2
package connections
11
3
@@ -14,6 +6,8 @@ import (
14
6
"fmt"
15
7
"strconv"
16
8
"strings"
9
+
10
+ "github.com/git-bug/git-bug/api/graphql/models"
17
11
)
18
12
19
13
const cursorPrefix = "cursor:"
@@ -43,3 +37,109 @@ func CursorToOffset(cursor string) (int, error) {
43
37
}
44
38
return offset , nil
45
39
}
40
+
41
+ // EdgeMaker defines a function that takes a NodeType and an offset and
42
+ // create an Edge.
43
+ type EdgeMaker [NodeType any ] func (value NodeType , offset int ) Edge
44
+
45
+ // ConMaker defines a function that creates a ConnectionType
46
+ type ConMaker [NodeType any , EdgeType Edge , ConType any ] func (
47
+ edges []* EdgeType ,
48
+ nodes []NodeType ,
49
+ info * models.PageInfo ,
50
+ totalCount int ) (* ConType , error )
51
+
52
+ // Connection will paginate a source according to the input of a relay connection
53
+ func Connection [NodeType any , EdgeType Edge , ConType any ](
54
+ source []NodeType ,
55
+ edgeMaker EdgeMaker [NodeType ],
56
+ conMaker ConMaker [NodeType , EdgeType , ConType ],
57
+ input models.ConnectionInput ) (* ConType , error ) {
58
+
59
+ var nodes []NodeType
60
+ var edges []* EdgeType
61
+ var cursors []string
62
+ var pageInfo = & models.PageInfo {}
63
+ var totalCount = len (source )
64
+
65
+ emptyCon , _ := conMaker (edges , nodes , pageInfo , 0 )
66
+
67
+ offset := 0
68
+
69
+ if input .After != nil {
70
+ for i , value := range source {
71
+ edge := edgeMaker (value , i )
72
+ if edge .GetCursor () == * input .After {
73
+ // remove all previous element including the "after" one
74
+ source = source [i + 1 :]
75
+ offset = i + 1
76
+ pageInfo .HasPreviousPage = true
77
+ break
78
+ }
79
+ }
80
+ }
81
+
82
+ if input .Before != nil {
83
+ for i , value := range source {
84
+ edge := edgeMaker (value , i + offset )
85
+
86
+ if edge .GetCursor () == * input .Before {
87
+ // remove all after element including the "before" one
88
+ pageInfo .HasNextPage = true
89
+ break
90
+ }
91
+
92
+ e := edge .(EdgeType )
93
+ edges = append (edges , & e )
94
+ cursors = append (cursors , edge .GetCursor ())
95
+ nodes = append (nodes , value )
96
+ }
97
+ } else {
98
+ edges = make ([]* EdgeType , len (source ))
99
+ cursors = make ([]string , len (source ))
100
+ nodes = source
101
+
102
+ for i , value := range source {
103
+ edge := edgeMaker (value , i + offset )
104
+ e := edge .(EdgeType )
105
+ edges [i ] = & e
106
+ cursors [i ] = edge .GetCursor ()
107
+ }
108
+ }
109
+
110
+ if input .First != nil {
111
+ if * input .First < 0 {
112
+ return emptyCon , fmt .Errorf ("first less than zero" )
113
+ }
114
+
115
+ if len (edges ) > * input .First {
116
+ // Slice result to be of length first by removing edges from the end
117
+ edges = edges [:* input .First ]
118
+ cursors = cursors [:* input .First ]
119
+ nodes = nodes [:* input .First ]
120
+ pageInfo .HasNextPage = true
121
+ }
122
+ }
123
+
124
+ if input .Last != nil {
125
+ if * input .Last < 0 {
126
+ return emptyCon , fmt .Errorf ("last less than zero" )
127
+ }
128
+
129
+ if len (edges ) > * input .Last {
130
+ // Slice result to be of length last by removing edges from the start
131
+ edges = edges [len (edges )- * input .Last :]
132
+ cursors = cursors [len (cursors )- * input .Last :]
133
+ nodes = nodes [len (nodes )- * input .Last :]
134
+ pageInfo .HasPreviousPage = true
135
+ }
136
+ }
137
+
138
+ // Fill up pageInfo cursors
139
+ if len (cursors ) > 0 {
140
+ pageInfo .StartCursor = cursors [0 ]
141
+ pageInfo .EndCursor = cursors [len (cursors )- 1 ]
142
+ }
143
+
144
+ return conMaker (edges , nodes , pageInfo , totalCount )
145
+ }
0 commit comments