1package connections
2
3import (
4 "fmt"
5
6 "github.com/MichaelMure/git-bug/graphql/models"
7 "github.com/cheekybits/genny/generic"
8)
9
10// NodeType define the node type handled by this relay connection
11type NodeType generic.Type
12
13// EdgeType define the edge type handled by this relay connection
14type EdgeType generic.Type
15
16// ConnectionType define the connection type handled by this relay connection
17type ConnectionType generic.Type
18
19// NodeTypeEdger define a function that take a NodeType and an offset and
20// create an Edge.
21type NodeTypeEdger func(value NodeType, offset int) Edge
22
23// NodeTypeConMaker define a function that create a ConnectionType
24type NodeTypeConMaker func(
25 edges []EdgeType,
26 nodes []NodeType,
27 info models.PageInfo,
28 totalCount int) (ConnectionType, error)
29
30// NodeTypeCon will paginate a source according to the input of a relay connection
31func NodeTypeCon(source []NodeType, edger NodeTypeEdger, conMaker NodeTypeConMaker, input models.ConnectionInput) (ConnectionType, error) {
32 var nodes []NodeType
33 var edges []EdgeType
34 var pageInfo models.PageInfo
35
36 emptyCon, _ := conMaker(edges, nodes, pageInfo, 0)
37
38 offset := 0
39
40 if input.After != nil {
41 for i, value := range source {
42 edge := edger(value, i)
43 if edge.GetCursor() == *input.After {
44 // remove all previous element including the "after" one
45 source = source[i+1:]
46 offset = i + 1
47 break
48 }
49 }
50 }
51
52 if input.Before != nil {
53 for i, value := range source {
54 edge := edger(value, i+offset)
55
56 if edge.GetCursor() == *input.Before {
57 // remove all after element including the "before" one
58 break
59 }
60
61 edges = append(edges, edge.(EdgeType))
62 nodes = append(nodes, value)
63 }
64 } else {
65 edges = make([]EdgeType, len(source))
66 nodes = source
67
68 for i, value := range source {
69 edges[i] = edger(value, i+offset).(EdgeType)
70 }
71 }
72
73 if input.First != nil {
74 if *input.First < 0 {
75 return emptyCon, fmt.Errorf("first less than zero")
76 }
77
78 if len(edges) > *input.First {
79 // Slice result to be of length first by removing edges from the end
80 edges = edges[:*input.First]
81 nodes = nodes[:*input.First]
82 pageInfo.HasNextPage = true
83 }
84 }
85
86 if input.Last != nil {
87 if *input.Last < 0 {
88 return emptyCon, fmt.Errorf("last less than zero")
89 }
90
91 if len(edges) > *input.Last {
92 // Slice result to be of length last by removing edges from the start
93 edges = edges[len(edges)-*input.Last:]
94 nodes = nodes[len(nodes)-*input.Last:]
95 pageInfo.HasPreviousPage = true
96 }
97 }
98
99 return conMaker(edges, nodes, pageInfo, len(source))
100}