From 2e0f0939b384fa5b6eb8a226602886a1e4ce562e Mon Sep 17 00:00:00 2001 From: Jan Bader Date: Mon, 13 Jul 2026 23:02:24 +0200 Subject: [PATCH] Fix Docspell search pagination --- docspell_client.go | 3 ++- docspell_client_test.go | 59 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 docspell_client_test.go diff --git a/docspell_client.go b/docspell_client.go index f55ec2b..ab61c24 100644 --- a/docspell_client.go +++ b/docspell_client.go @@ -122,9 +122,10 @@ func (c *DocspellClient) SearchItems(ctx context.Context, query string, limit in all = append(all, group.Items...) count += len(group.Items) } - if count == 0 || count < limit { + if count == 0 { return all, nil } + offset += count - limit } } diff --git a/docspell_client_test.go b/docspell_client_test.go new file mode 100644 index 0000000..1f6797e --- /dev/null +++ b/docspell_client_test.go @@ -0,0 +1,59 @@ +package main + +import ( + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "strconv" + "testing" +) + +func TestSearchItemsContinuesWhenServerCapsLimit(t *testing.T) { + var offsets []int + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/api/v1/sec/item/search" { + t.Fatalf("unexpected path: %s", r.URL.Path) + } + var req struct { + Offset int `json:"offset"` + Limit int `json:"limit"` + } + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + t.Fatal(err) + } + offsets = append(offsets, req.Offset) + count := 200 + if req.Offset >= 400 { + count = 0 + } + items := make([]SearchItem, count) + for i := range items { + items[i] = SearchItem{ID: strconv.Itoa(req.Offset + i)} + } + _ = json.NewEncoder(w).Encode(map[string]any{ + "groups": []map[string]any{{"items": items}}, + "limit": 200, + "offset": req.Offset, + }) + })) + defer server.Close() + + client := NewDocspellClient(server.URL, "") + items, err := client.SearchItems(context.Background(), "*", 1000) + if err != nil { + t.Fatal(err) + } + if len(items) != 400 { + t.Fatalf("expected 400 items, got %d", len(items)) + } + wantOffsets := []int{0, 200, 400} + if len(offsets) != len(wantOffsets) { + t.Fatalf("expected offsets %v, got %v", wantOffsets, offsets) + } + for i := range wantOffsets { + if offsets[i] != wantOffsets[i] { + t.Fatalf("expected offsets %v, got %v", wantOffsets, offsets) + } + } +}