@@ -5,7 +5,6 @@ package fwserver
55
66import (
77 "context"
8- "iter"
98
109 "github.com/hashicorp/terraform-plugin-framework/diag"
1110 "github.com/hashicorp/terraform-plugin-framework/internal/logging"
@@ -33,17 +32,17 @@ type ListRequest struct {
3332
3433// ListResultsStream represents a streaming response to a ListRequest. An
3534// instance of this struct is supplied as an argument to the provider's List
36- // function. The provider should set a Results iterator function that yields
35+ // function. The provider should set a Results iterator function that pushes
3736// zero or more results of type ListResult.
3837//
3938// For convenience, a provider implementation may choose to convert a slice of
4039// results into an iterator using [slices.Values].
4140//
4241// [slices.Values]: https://pkg.go.dev/slices#Values
4342type ListResourceStream struct {
44- // Results is a function that emits ListResult values via its yield
43+ // Results is a function that emits ListResult values via its push
4544 // function argument.
46- Results iter. Seq [ ListResult ]
45+ Results ListResults
4746}
4847
4948// ListResult represents a listed managed resource instance.
@@ -69,6 +68,11 @@ type ListResult struct {
6968 Diagnostics diag.Diagnostics
7069}
7170
71+ // ListResults is a function type that accepts a function to push ListResult
72+ // values. This type can be used anywhere that an iterator of type
73+ // iter.Seq[ListResult] can be used.
74+ type ListResults func (push func (ListResult ) bool )
75+
7276// ListResource implements the framework server ListResource RPC.
7377func (s * Server ) ListResource (ctx context.Context , fwReq * ListRequest , fwStream * ListResourceStream ) {
7478 listResource := fwReq .ListResource
@@ -85,19 +89,40 @@ func (s *Server) ListResource(ctx context.Context, fwReq *ListRequest, fwStream
8589 logging .FrameworkTrace (ctx , "Called provider defined ListResource" )
8690
8791 if stream .Results == nil {
88- // If the provider returned a nil results stream, we treat it as an empty stream.
89- stream .Results = func ( func ( list.ListResult ) bool ) {}
92+ // If the provider returned a nil results stream, we return an empty stream.
93+ stream .Results = list .NoListResults
9094 }
9195
92- fwStream .Results = listResourceEventStreamAdapter (stream .Results )
96+ fwStream .Results = processListResults (req , stream .Results )
97+ }
98+
99+ func processListResults (req list.ListRequest , stream list.ListResults ) ListResults {
100+ return func (push func (ListResult ) bool ) {
101+ for result := range stream {
102+ if ! push (processListResult (req , result )) {
103+ return
104+ }
105+ }
106+ }
93107}
94108
95- func listResourceEventStreamAdapter (stream iter.Seq [list.ListResult ]) iter.Seq [ListResult ] {
96- // TODO: is this any more efficient than a for-range?
97- return func (yieldFw func (ListResult ) bool ) {
98- yield := func (event list.ListResult ) bool {
99- return yieldFw (ListResult (event ))
109+ // processListResult validates the content of a list.ListResult and returns a
110+ // ListResult
111+ func processListResult (req list.ListRequest , result list.ListResult ) ListResult {
112+ if result .Identity == nil {
113+ return ListResult {
114+ Diagnostics : diag.Diagnostics {
115+ diag .NewErrorDiagnostic ("Incomplete List Result" , "ListResult.Identity is nil." ),
116+ },
100117 }
101- stream (yield )
102118 }
119+
120+ if req .IncludeResource && result .Resource == nil {
121+ result .Diagnostics .AddWarning (
122+ "Incomplete List Result" ,
123+ "ListRequest.IncludeResource is true and ListResult.Resource is nil." ,
124+ )
125+ }
126+
127+ return ListResult (result )
103128}
0 commit comments