@@ -101,24 +101,25 @@ type structDef struct {
101101}
102102
103103type method struct {
104- RecvType string
105- RecvVar string
106- ClientField string
107- MethodName string
108- IterMethod string
109- Args string
110- CallArgs string
111- TestCallArgs string
112- ZeroArgs string
113- ReturnType string
114- OptsType string
115- OptsName string
116- OptsIsPtr bool
117- UseListOptions bool
118- UsePage bool
119- TestJSON1 string
120- TestJSON2 string
121- TestJSON3 string
104+ RecvType string
105+ RecvVar string
106+ ClientField string
107+ MethodName string
108+ IterMethod string
109+ Args string
110+ CallArgs string
111+ TestCallArgs string
112+ ZeroArgs string
113+ ReturnType string
114+ OptsType string
115+ OptsName string
116+ OptsIsPtr bool
117+ UseListCursorOptions bool
118+ UseListOptions bool
119+ UsePage bool
120+ TestJSON1 string
121+ TestJSON2 string
122+ TestJSON3 string
122123}
123124
124125// customTestJSON maps method names to the JSON response they expect in tests.
@@ -164,16 +165,24 @@ func (t *templateData) processStructs(f *ast.File) {
164165 }
165166}
166167
168+ func (t * templateData ) hasListCursorOptions (structName string ) bool {
169+ return t .hasOptions (structName , "ListCursorOptions" )
170+ }
171+
167172func (t * templateData ) hasListOptions (structName string ) bool {
173+ return t .hasOptions (structName , "ListOptions" )
174+ }
175+
176+ func (t * templateData ) hasOptions (structName , optionsType string ) bool {
168177 sd , ok := t .Structs [structName ]
169178 if ! ok {
170179 return false
171180 }
172181 for _ , embed := range sd .Embeds {
173- if embed == "ListOptions" {
182+ if embed == optionsType {
174183 return true
175184 }
176- if t .hasListOptions (embed ) {
185+ if t .hasOptions (embed , optionsType ) {
177186 return true
178187 }
179188 }
@@ -290,11 +299,12 @@ func (t *templateData) processMethods(f *ast.File) error {
290299 continue
291300 }
292301
302+ useListCursorOptions := t .hasListCursorOptions (optsType )
293303 useListOptions := t .hasListOptions (optsType )
294304 usePage := t .hasIntPage (optsType )
295305
296- if ! useListOptions && ! usePage {
297- logf ("Skipping %s.%s: opts %s does not have ListOptions or Page int" , recvType , fd .Name .Name , optsType )
306+ if ! useListCursorOptions && ! useListOptions && ! usePage {
307+ logf ("Skipping %s.%s: opts %s does not have ListCursorOptions, ListOptions, or Page int" , recvType , fd .Name .Name , optsType )
298308 continue
299309 }
300310
@@ -316,24 +326,25 @@ func (t *templateData) processMethods(f *ast.File) error {
316326 testJSON3 := strings .ReplaceAll (testJSON , "[]" , "[{},{}]" ) // Call 2 - return 2 items
317327
318328 m := & method {
319- RecvType : recType ,
320- RecvVar : recvVar ,
321- ClientField : clientField ,
322- MethodName : fd .Name .Name ,
323- IterMethod : fd .Name .Name + "Iter" ,
324- Args : strings .Join (args , ", " ),
325- CallArgs : strings .Join (callArgs , ", " ),
326- TestCallArgs : strings .Join (testCallArgs , ", " ),
327- ZeroArgs : strings .Join (zeroArgs , ", " ),
328- ReturnType : eltType ,
329- OptsType : optsType ,
330- OptsName : optsName ,
331- OptsIsPtr : optsIsPtr ,
332- UseListOptions : useListOptions ,
333- UsePage : usePage ,
334- TestJSON1 : testJSON1 ,
335- TestJSON2 : testJSON2 ,
336- TestJSON3 : testJSON3 ,
329+ RecvType : recType ,
330+ RecvVar : recvVar ,
331+ ClientField : clientField ,
332+ MethodName : fd .Name .Name ,
333+ IterMethod : fd .Name .Name + "Iter" ,
334+ Args : strings .Join (args , ", " ),
335+ CallArgs : strings .Join (callArgs , ", " ),
336+ TestCallArgs : strings .Join (testCallArgs , ", " ),
337+ ZeroArgs : strings .Join (zeroArgs , ", " ),
338+ ReturnType : eltType ,
339+ OptsType : optsType ,
340+ OptsName : optsName ,
341+ OptsIsPtr : optsIsPtr ,
342+ UseListCursorOptions : useListCursorOptions ,
343+ UseListOptions : useListOptions ,
344+ UsePage : usePage ,
345+ TestJSON1 : testJSON1 ,
346+ TestJSON2 : testJSON2 ,
347+ TestJSON3 : testJSON3 ,
337348 }
338349 t .Methods = append (t .Methods , m )
339350 }
@@ -432,12 +443,26 @@ func ({{.RecvVar}} *{{.RecvType}}) {{.IterMethod}}({{.Args}}) iter.Seq2[{{.Retur
432443 }
433444 }
434445
446+ {{if and .UseListCursorOptions .UseListOptions}}
447+ if resp.Cursor == "" && resp.NextPage == 0 {
448+ break
449+ }
450+ {{.OptsName}}.ListCursorOptions.Cursor = resp.Cursor
451+ {{.OptsName}}.ListOptions.Page = resp.NextPage
452+ {{else if .UseListCursorOptions}}
453+ if resp.Cursor == "" {
454+ break
455+ }
456+ {{.OptsName}}.ListCursorOptions.Cursor = resp.Cursor
457+ {{else if .UseListOptions}}
435458 if resp.NextPage == 0 {
436459 break
437460 }
438- {{if .UseListOptions}}
439461 {{.OptsName}}.ListOptions.Page = resp.NextPage
440462 {{else}}
463+ if resp.NextPage == 0 {
464+ break
465+ }
441466 {{.OptsName}}.Page = resp.NextPage
442467 {{end -}}
443468 }
@@ -464,20 +489,23 @@ func Test{{.RecvType}}_{{.IterMethod}}(t *testing.T) {
464489 callNum++
465490 switch callNum {
466491 case 1:
492+ {{- if .UseListCursorOptions}}
493+ w.Header().Set("Link", ` + "`" + `<https://api.github.com/?cursor=yo>; rel="next"` + "`" + `)
494+ {{else}}
467495 w.Header().Set("Link", ` + "`" + `<https://api.github.com/?page=1>; rel="next"` + "`" + `)
468- fmt.Fprint(w, ` + "`" + `{{.TestJSON1}}` + "`" + `) // Call 1 below: return 3 items, NextPage=1, no errors
496+ {{end -}}
497+ fmt.Fprint(w, ` + "`" + `{{.TestJSON1}}` + "`" + `)
469498 case 2:
470- fmt.Fprint(w, ` + "`" + `{{.TestJSON2}}` + "`" + `) // still Call 1 below: return 4 more items, no next page, no errors
499+ fmt.Fprint(w, ` + "`" + `{{.TestJSON2}}` + "`" + `)
471500 case 3:
472- fmt.Fprint(w, ` + "`" + `{{.TestJSON3}}` + "`" + `) // Call 2 below: return 2 items, no next page, no errors
501+ fmt.Fprint(w, ` + "`" + `{{.TestJSON3}}` + "`" + `)
473502 case 4:
474- w.WriteHeader(http.StatusNotFound) // Call 3 below: endpoint returns an error
503+ w.WriteHeader(http.StatusNotFound)
475504 case 5:
476- fmt.Fprint(w, ` + "`" + `{{.TestJSON3}}` + "`" + `) // Call 4 below: return 2 items, no next page, no errors
505+ fmt.Fprint(w, ` + "`" + `{{.TestJSON3}}` + "`" + `)
477506 }
478507 })
479508
480- // Call 1: iterator using zero values
481509 iter := client.{{.ClientField}}.{{.IterMethod}}({{.ZeroArgs}})
482510 var gotItems int
483511 for _, err := range iter {
@@ -490,10 +518,9 @@ func Test{{.RecvType}}_{{.IterMethod}}(t *testing.T) {
490518 t.Errorf("client.{{.ClientField}}.{{.IterMethod}} call 1 got %v items; want %v", gotItems, want)
491519 }
492520
493- // Call 2: iterator using non-nil opts
494521 {{.OptsName}} := &{{.OptsType}}{}
495522 iter = client.{{.ClientField}}.{{.IterMethod}}({{.TestCallArgs}})
496- gotItems = 0 // reset
523+ gotItems = 0
497524 for _, err := range iter {
498525 gotItems++
499526 if err != nil {
@@ -504,9 +531,8 @@ func Test{{.RecvType}}_{{.IterMethod}}(t *testing.T) {
504531 t.Errorf("client.{{.ClientField}}.{{.IterMethod}} call 2 got %v items; want %v", gotItems, want)
505532 }
506533
507- // Call 3: iterator returns an error
508534 iter = client.{{.ClientField}}.{{.IterMethod}}({{.ZeroArgs}})
509- gotItems = 0 // reset
535+ gotItems = 0
510536 for _, err := range iter {
511537 gotItems++
512538 if err == nil {
@@ -517,16 +543,13 @@ func Test{{.RecvType}}_{{.IterMethod}}(t *testing.T) {
517543 t.Errorf("client.{{.ClientField}}.{{.IterMethod}} call 3 got %v items; want 1 (an error)", gotItems)
518544 }
519545
520- // Call 4: iterator returns false
521546 iter = client.{{.ClientField}}.{{.IterMethod}}({{.ZeroArgs}})
522- gotItems = 0 // reset
547+ gotItems = 0
523548 iter(func(item {{.ReturnType}}, err error) bool {
524549 gotItems++
525550 if err != nil {
526551 t.Errorf("Unexpected error: %v", err)
527552 }
528- // Force the iterator to hit:
529- // if !yield(item, nil) { return }
530553 return false
531554 })
532555 if gotItems != 1 {
0 commit comments