Skip to content

Commit fda80f6

Browse files
committed
fix iterators parsing
1 parent de9da0d commit fda80f6

File tree

6 files changed

+115
-21
lines changed

6 files changed

+115
-21
lines changed

core/interceptors_test.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,32 +16,32 @@ func TestDefaultResponseMutations_PaginationNotUnwrapped(t *testing.T) {
1616
"next": "https://example.com/api/v1/resources/?page=2",
1717
"previous": nil,
1818
}
19-
19+
2020
// Apply defaultResponseMutations
2121
result, err := defaultResponseMutations(paginationEnvelope)
2222
if err != nil {
2323
t.Fatalf("Expected no error, got: %v", err)
2424
}
25-
25+
2626
// Verify that the pagination envelope is NOT unwrapped
2727
resultRecord, ok := result.(Record)
2828
if !ok {
2929
t.Fatalf("Expected Record, got %T", result)
3030
}
31-
31+
3232
// Check that the envelope structure is preserved
3333
if _, hasResults := resultRecord["results"]; !hasResults {
3434
t.Error("Expected results field to be preserved")
3535
}
36-
36+
3737
if _, hasCount := resultRecord["count"]; !hasCount {
3838
t.Error("Expected count field to be preserved")
3939
}
40-
40+
4141
if _, hasNext := resultRecord["next"]; !hasNext {
4242
t.Error("Expected next field to be preserved")
4343
}
44-
44+
4545
if _, hasPrevious := resultRecord["previous"]; !hasPrevious {
4646
t.Error("Expected previous field to be preserved")
4747
}
@@ -53,19 +53,19 @@ func TestDefaultResponseMutations_RecordSetUnchanged(t *testing.T) {
5353
{"id": float64(1), "name": "item1"},
5454
{"id": float64(2), "name": "item2"},
5555
}
56-
56+
5757
// Apply defaultResponseMutations
5858
result, err := defaultResponseMutations(recordSet)
5959
if err != nil {
6060
t.Fatalf("Expected no error, got: %v", err)
6161
}
62-
62+
6363
// Verify that RecordSet is unchanged
6464
resultRecordSet, ok := result.(RecordSet)
6565
if !ok {
6666
t.Fatalf("Expected RecordSet, got %T", result)
6767
}
68-
68+
6969
if len(resultRecordSet) != 2 {
7070
t.Errorf("Expected 2 records, got %d", len(resultRecordSet))
7171
}
@@ -79,19 +79,19 @@ func TestDefaultResponseMutations_AsyncTask(t *testing.T) {
7979
"state": "RUNNING",
8080
},
8181
}
82-
82+
8383
// Apply defaultResponseMutations
8484
result, err := defaultResponseMutations(asyncTaskResponse)
8585
if err != nil {
8686
t.Fatalf("Expected no error, got: %v", err)
8787
}
88-
88+
8989
// Verify that async_task is normalized
9090
resultRecord, ok := result.(Record)
9191
if !ok {
9292
t.Fatalf("Expected Record, got %T", result)
9393
}
94-
94+
9595
// Check that ResourceTypeKey was added
9696
if resourceType, ok := resultRecord[ResourceTypeKey]; !ok || resourceType != "VTask" {
9797
t.Errorf("Expected ResourceTypeKey to be 'VTask', got: %v", resourceType)

core/iterator.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,12 +146,11 @@ func (it *ResourceIterator) fetchPage(url string, params Params) error {
146146
// processPaginationEnvelope extracts data from a pagination envelope using ToRecordSet.
147147
func (it *ResourceIterator) processPaginationEnvelope(envelope Record) error {
148148
// Check if this is a pagination envelope
149+
// Only results and count are required; next and previous are optional
149150
_, hasResults := envelope["results"]
150151
_, hasCount := envelope["count"]
151-
_, hasNext := envelope["next"]
152-
_, hasPrev := envelope["previous"]
153152

154-
if hasResults && hasCount && hasNext && hasPrev {
153+
if hasResults && hasCount {
155154
// This is a paginated response - use ToRecordSet to convert results
156155
if resultsRaw, ok := envelope["results"]; ok {
157156
// Try []map[string]any first
@@ -323,7 +322,7 @@ func (it *ResourceIterator) String() string {
323322
sb.WriteString(fmt.Sprintf(" Total Count: %d\n", it.totalCount))
324323

325324
// Show current records with count
326-
if it.current != nil && len(it.current) > 0 {
325+
if len(it.current) > 0 {
327326
sb.WriteString(fmt.Sprintf(" Current: [... (%d items)]\n", len(it.current)))
328327
} else {
329328
sb.WriteString(" Current: []\n")

core/iterator_test.go

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,102 @@ func TestIterator_NonPaginatedResponse(t *testing.T) {
213213
}
214214
}
215215

216+
// Test response with only count and results (no next/previous fields)
217+
// This is a common case when there are no results or only one page
218+
func TestIterator_CountAndResultsOnly(t *testing.T) {
219+
// Test case 1: Empty results
220+
emptyResponse := Record{
221+
"count": float64(0),
222+
"results": []any{},
223+
}
224+
225+
mockSession := &mockSessionForIterator{
226+
responses: map[string]Renderable{
227+
"https://test.example.com:443/api/v1/resources/?name=vastdb-volume&page_size=10": emptyResponse,
228+
},
229+
}
230+
231+
mockRest := &DummyRest{
232+
ctx: context.Background(),
233+
Session: mockSession,
234+
}
235+
236+
mockResource := &mockResourceForIterator{
237+
VastResource: &VastResource{
238+
resourcePath: "resources",
239+
resourceType: "TestResource",
240+
Rest: mockRest,
241+
},
242+
mockSession: mockSession,
243+
}
244+
245+
// Create iterator with query params
246+
iter := NewResourceIterator(context.Background(), mockResource, Params{"name": "vastdb-volume"}, 10)
247+
248+
// Should return empty RecordSet, not error
249+
records, err := iter.Next()
250+
if err != nil {
251+
t.Fatalf("Expected no error for empty results, got: %v", err)
252+
}
253+
if len(records) != 0 {
254+
t.Errorf("Expected 0 items, got %d", len(records))
255+
}
256+
if iter.Count() != 0 {
257+
t.Errorf("Expected count of 0, got %d", iter.Count())
258+
}
259+
if iter.HasNext() {
260+
t.Error("Expected HasNext to be false when no next field")
261+
}
262+
263+
// Test case 2: Single page with results (no next/previous)
264+
singlePageResponse := Record{
265+
"count": float64(2),
266+
"results": []any{
267+
map[string]any{"id": float64(1), "name": "item1"},
268+
map[string]any{"id": float64(2), "name": "item2"},
269+
},
270+
}
271+
272+
mockSession2 := &mockSessionForIterator{
273+
responses: map[string]Renderable{
274+
"https://test.example.com:443/api/v1/resources/?page_size=10": singlePageResponse,
275+
},
276+
}
277+
278+
mockRest2 := &DummyRest{
279+
ctx: context.Background(),
280+
Session: mockSession2,
281+
}
282+
283+
mockResource2 := &mockResourceForIterator{
284+
VastResource: &VastResource{
285+
resourcePath: "resources",
286+
resourceType: "TestResource",
287+
Rest: mockRest2,
288+
},
289+
mockSession: mockSession2,
290+
}
291+
292+
iter2 := NewResourceIterator(context.Background(), mockResource2, Params{}, 10)
293+
294+
records, err = iter2.Next()
295+
if err != nil {
296+
t.Fatalf("Expected no error, got: %v", err)
297+
}
298+
if len(records) != 2 {
299+
t.Errorf("Expected 2 items, got %d", len(records))
300+
}
301+
if iter2.Count() != 2 {
302+
t.Errorf("Expected count of 2, got %d", iter2.Count())
303+
}
304+
if iter2.HasNext() {
305+
t.Error("Expected HasNext to be false when no next field")
306+
}
307+
if iter2.HasPrevious() {
308+
t.Error("Expected HasPrevious to be false when no previous field")
309+
}
310+
}
311+
216312
// Test All() method
217313
func TestIterator_All(t *testing.T) {
218314
// Create mock responses with multiple pages

core/vast_resource.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -173,10 +173,8 @@ func (e *VastResource) EnsureWithContext(ctx context.Context, searchParams Param
173173
// GetWithContext retrieves a single resource that matches the given parameters using the provided context.
174174
// Returns a NotFoundError if no resource is found.
175175
func (e *VastResource) GetWithContext(ctx context.Context, params Params) (Record, error) {
176-
result, err := Request[RecordSet](ctx, e, http.MethodGet, e.resourcePath, params, nil)
177-
if !e.resourceOps.has(L) && ExpectStatusCodes(err, http.StatusNotFound) {
178-
err.(*ApiError).hints = e.describeResourceFrom(e)
179-
}
176+
result, err := e.ListWithContext(ctx, params)
177+
180178
if err != nil {
181179
return nil, err
182180
}

core/version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.104.0
1+
0.105.0

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ nav:
2525
- Session: session.md
2626
- Response: response.md
2727
- Resource Lock: resource-lock.md
28+
- Iterators: iterators.md
2829
- Errors: errors.md
2930

3031
plugins:

0 commit comments

Comments
 (0)