@@ -9,31 +9,50 @@ import (
9
9
"github.com/graphql-go/graphql/language/ast"
10
10
)
11
11
12
- type ResultIteratorFn func (count int64 , result * Result , doneFunc func ())
12
+ // ResultIteratorParams parameters passed to the result iterator handler
13
+ type ResultIteratorParams struct {
14
+ ResultCount int64 // number of results this iterator has processed
15
+ Result * Result // the current result
16
+ Done func () // Removes the current handler
17
+ Cancel func () // Cancels the iterator, same as iterator.Cancel()
18
+ }
19
+
20
+ // ResultIteratorFn a result iterator handler
21
+ type ResultIteratorFn func (p ResultIteratorParams )
22
+
23
+ // holds subscription handler data
24
+ type subscriptionHanlderConfig struct {
25
+ handler ResultIteratorFn
26
+ doneFunc func ()
27
+ }
13
28
29
+ // ResultIterator handles processing results from a chan *Result
14
30
type ResultIterator struct {
15
- count int64
16
- wg sync.WaitGroup
17
- ctx context.Context
18
- ch chan * Result
19
- cancelFunc context.CancelFunc
20
- cancelled bool
21
- handlers []ResultIteratorFn
31
+ currentHandlerID int64
32
+ count int64
33
+ wg sync.WaitGroup
34
+ ctx context.Context
35
+ ch chan * Result
36
+ cancelFunc context.CancelFunc
37
+ cancelled bool
38
+ handlers map [int64 ]* subscriptionHanlderConfig
22
39
}
23
40
41
+ // NewResultIterator creates a new iterator and starts handling message on the result channel
24
42
func NewResultIterator (ctx context.Context , ch chan * Result ) * ResultIterator {
25
43
if ctx == nil {
26
44
ctx = context .Background ()
27
45
}
28
46
29
47
cctx , cancelFunc := context .WithCancel (ctx )
30
48
iterator := & ResultIterator {
31
- count : 0 ,
32
- ctx : cctx ,
33
- ch : ch ,
34
- cancelFunc : cancelFunc ,
35
- cancelled : false ,
36
- handlers : []ResultIteratorFn {},
49
+ currentHandlerID : 0 ,
50
+ count : 0 ,
51
+ ctx : cctx ,
52
+ ch : ch ,
53
+ cancelFunc : cancelFunc ,
54
+ cancelled : false ,
55
+ handlers : map [int64 ]* subscriptionHanlderConfig {},
37
56
}
38
57
39
58
go func () {
@@ -49,9 +68,14 @@ func NewResultIterator(ctx context.Context, ch chan *Result) *ResultIterator {
49
68
iterator .wg .Add (1 )
50
69
iterator .count ++
51
70
iterator .wg .Done ()
52
- for _ , handler := range iterator .handlers {
71
+ for _ , h := range iterator .handlers {
53
72
iterator .wg .Wait ()
54
- handler (iterator .count , res , iterator .Done )
73
+ h .handler (ResultIteratorParams {
74
+ ResultCount : iterator .count ,
75
+ Result : res ,
76
+ Done : h .doneFunc ,
77
+ Cancel : iterator .Cancel ,
78
+ })
55
79
}
56
80
}
57
81
}
@@ -60,17 +84,42 @@ func NewResultIterator(ctx context.Context, ch chan *Result) *ResultIterator {
60
84
return iterator
61
85
}
62
86
63
- func (c * ResultIterator ) ForEach (handler ResultIteratorFn ) {
87
+ // adds a new handler
88
+ func (c * ResultIterator ) addHandler (handler ResultIteratorFn ) {
89
+ c .wg .Add (1 )
90
+ handlerID := c .currentHandlerID + 1
91
+ c .currentHandlerID = handlerID
92
+ c .handlers [handlerID ] = & subscriptionHanlderConfig {
93
+ handler : handler ,
94
+ doneFunc : func () {
95
+ c .removeHandler (handlerID )
96
+ },
97
+ }
98
+ c .wg .Done ()
99
+ }
100
+
101
+ // removes a handler and cancels if no more handlers exist
102
+ func (c * ResultIterator ) removeHandler (handlerID int64 ) {
64
103
c .wg .Add (1 )
65
- c .handlers = append (c .handlers , handler )
104
+ delete (c .handlers , handlerID )
105
+ if len (c .handlers ) == 0 {
106
+ c .Cancel ()
107
+ }
66
108
c .wg .Done ()
67
109
}
68
110
69
- func (c * ResultIterator ) Done () {
111
+ // ForEach adds a handler and handles each message as they come
112
+ func (c * ResultIterator ) ForEach (handler ResultIteratorFn ) {
113
+ c .addHandler (handler )
114
+ }
115
+
116
+ // Cancel cancels the iterator
117
+ func (c * ResultIterator ) Cancel () {
70
118
c .cancelled = true
71
119
c .cancelFunc ()
72
120
}
73
121
122
+ // SubscribeParams parameters for subscribing
74
123
type SubscribeParams struct {
75
124
Schema Schema
76
125
Document * ast.Document
0 commit comments