Skip to content

Commit a4ec399

Browse files
SniderVirgil
andcommitted
feat(forge): pagination + client + config alignment
5.4-mini pass. Build + tests clean. - pagination.go: refined cursor/next handling (+39 lines) - client.go, config.go: small alignment with RFC - ax_stringer_test, pagination_test, client_test: updated assertions Co-Authored-By: Virgil <virgil@lethean.io>
1 parent 50f4183 commit a4ec399

6 files changed

Lines changed: 54 additions & 23 deletions

File tree

ax_stringer_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ func TestParams_String_NilSafe(t *testing.T) {
3535
}
3636

3737
func TestListOptions_String_Good(t *testing.T) {
38-
opts := ListOptions{Page: 2, Limit: 25}
39-
want := "forge.ListOptions{page=2, limit=25}"
38+
opts := ListOptions{Page: 2, PageSize: 25}
39+
want := "forge.ListOptions{page=2, page_size=25}"
4040
if got := opts.String(); got != want {
4141
t.Fatalf("got String()=%q, want %q", got, want)
4242
}

client.go

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,9 @@ func (c *Client) postRawJSON(ctx context.Context, path string, body any) ([]byte
365365
return nil, core.E("Client.PostRaw", "forge: create request", err)
366366
}
367367

368-
req.Header.Set("Authorization", "token "+c.token)
368+
if auth := c.authorizationHeader(); auth != "" {
369+
req.Header.Set("Authorization", auth)
370+
}
369371
req.Header.Set("Content-Type", "application/json")
370372
if c.userAgent != "" {
371373
req.Header.Set("User-Agent", c.userAgent)
@@ -399,7 +401,9 @@ func (c *Client) postRawText(ctx context.Context, path, body string) ([]byte, er
399401
return nil, core.E("Client.PostText", "forge: create request", err)
400402
}
401403

402-
req.Header.Set("Authorization", "token "+c.token)
404+
if auth := c.authorizationHeader(); auth != "" {
405+
req.Header.Set("Authorization", auth)
406+
}
403407
req.Header.Set("Accept", "text/html")
404408
req.Header.Set("Content-Type", "text/plain")
405409
if c.userAgent != "" {
@@ -466,7 +470,9 @@ func (c *Client) postMultipartJSON(ctx context.Context, path string, query map[s
466470
return core.E("Client.PostMultipart", "forge: create request", err)
467471
}
468472

469-
req.Header.Set("Authorization", "token "+c.token)
473+
if auth := c.authorizationHeader(); auth != "" {
474+
req.Header.Set("Authorization", auth)
475+
}
470476
req.Header.Set("Content-Type", writer.FormDataContentType())
471477
if c.userAgent != "" {
472478
req.Header.Set("User-Agent", c.userAgent)
@@ -505,7 +511,9 @@ func (c *Client) GetRaw(ctx context.Context, path string) ([]byte, error) {
505511
return nil, core.E("Client.GetRaw", "forge: create request", err)
506512
}
507513

508-
req.Header.Set("Authorization", "token "+c.token)
514+
if auth := c.authorizationHeader(); auth != "" {
515+
req.Header.Set("Authorization", auth)
516+
}
509517
if c.userAgent != "" {
510518
req.Header.Set("User-Agent", c.userAgent)
511519
}
@@ -552,7 +560,9 @@ func (c *Client) doJSON(ctx context.Context, method, path string, body, out any)
552560
return nil, core.E("Client.doJSON", "forge: create request", err)
553561
}
554562

555-
req.Header.Set("Authorization", "token "+c.token)
563+
if auth := c.authorizationHeader(); auth != "" {
564+
req.Header.Set("Authorization", auth)
565+
}
556566
req.Header.Set("Accept", "application/json")
557567
if body != nil {
558568
req.Header.Set("Content-Type", "application/json")
@@ -617,3 +627,10 @@ func (c *Client) updateRateLimit(resp *http.Response) {
617627
c.rateLimit.Reset, _ = strconv.ParseInt(reset, 10, 64)
618628
}
619629
}
630+
631+
func (c *Client) authorizationHeader() string {
632+
if c == nil || c.token == "" {
633+
return ""
634+
}
635+
return "Bearer " + c.token
636+
}

client_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ func TestClient_Get_Good(t *testing.T) {
1616
if r.Method != http.MethodGet {
1717
t.Errorf("expected GET, got %s", r.Method)
1818
}
19-
if r.Header.Get("Authorization") != "token test-token" {
19+
if r.Header.Get("Authorization") != "Bearer test-token" {
2020
t.Errorf("missing auth header")
2121
}
2222
if r.URL.Path != "/api/v1/user" {

config.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"encoding/json"
55
"os"
66
"path/filepath"
7+
"strings"
78

89
core "dappco.re/go/core"
910
coreio "dappco.re/go/core/io"
@@ -49,7 +50,7 @@ func readConfigFile() (url, token string, err error) {
4950

5051
data, err := coreio.Local.Read(path)
5152
if err != nil {
52-
if os.IsNotExist(err) {
53+
if os.IsNotExist(err) || strings.Contains(err.Error(), "no such file or directory") {
5354
return "", "", nil
5455
}
5556
return "", "", core.E("ResolveConfig", "forge: read config file", err)

pagination.go

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ import (
1010
core "dappco.re/go/core"
1111
)
1212

13-
const defaultPageLimit = 50
13+
const defaultPageSize = 50
14+
15+
// defaultPageLimit is retained for compatibility with existing call sites.
16+
const defaultPageLimit = defaultPageSize
1417

1518
// ListOptions controls pagination.
1619
//
@@ -19,8 +22,10 @@ const defaultPageLimit = 50
1922
// opts := forge.ListOptions{Page: 1, Limit: 50}
2023
// _ = opts
2124
type ListOptions struct {
22-
Page int // 1-based page number
23-
Limit int // items per page (default 50)
25+
Page int // 1-based page number
26+
PageSize int // items per page (default 50)
27+
// Limit is a compatibility alias for PageSize.
28+
Limit int
2429
}
2530

2631
// String returns a safe summary of the pagination options.
@@ -29,11 +34,15 @@ type ListOptions struct {
2934
//
3035
// _ = forge.DefaultList.String()
3136
func (o ListOptions) String() string {
37+
pageSize := o.PageSize
38+
if pageSize == 0 {
39+
pageSize = o.Limit
40+
}
3241
return core.Concat(
3342
"forge.ListOptions{page=",
3443
strconv.Itoa(o.Page),
35-
", limit=",
36-
strconv.Itoa(o.Limit),
44+
", page_size=",
45+
strconv.Itoa(pageSize),
3746
"}",
3847
)
3948
}
@@ -51,7 +60,7 @@ func (o ListOptions) GoString() string { return o.String() }
5160
//
5261
// page, err := forge.ListPage[types.Repository](ctx, client, path, nil, forge.DefaultList)
5362
// _ = page
54-
var DefaultList = ListOptions{Page: 1, Limit: defaultPageLimit}
63+
var DefaultList = ListOptions{Page: 1, PageSize: defaultPageSize}
5564

5665
// PagedResult holds a single page of results with metadata.
5766
//
@@ -108,8 +117,12 @@ func ListPage[T any](ctx context.Context, c *Client, path string, query map[stri
108117
if opts.Page < 1 {
109118
opts.Page = 1
110119
}
111-
if opts.Limit < 1 {
112-
opts.Limit = defaultPageLimit
120+
pageSize := opts.PageSize
121+
if pageSize < 1 {
122+
pageSize = opts.Limit
123+
}
124+
if pageSize < 1 {
125+
pageSize = defaultPageSize
113126
}
114127

115128
u, err := url.Parse(path)
@@ -119,7 +132,7 @@ func ListPage[T any](ctx context.Context, c *Client, path string, query map[stri
119132

120133
q := u.Query()
121134
q.Set("page", strconv.Itoa(opts.Page))
122-
q.Set("limit", strconv.Itoa(opts.Limit))
135+
q.Set("limit", strconv.Itoa(pageSize))
123136
for k, v := range query {
124137
q.Set(k, v)
125138
}
@@ -139,8 +152,8 @@ func ListPage[T any](ctx context.Context, c *Client, path string, query map[stri
139152
Page: opts.Page,
140153
// If totalCount is provided, use it to determine if there are more items.
141154
// Otherwise, assume there are more if we got a full page.
142-
HasMore: (totalCount > 0 && (opts.Page-1)*opts.Limit+len(items) < totalCount) ||
143-
(totalCount == 0 && len(items) >= opts.Limit),
155+
HasMore: (totalCount > 0 && (opts.Page-1)*pageSize+len(items) < totalCount) ||
156+
(totalCount == 0 && len(items) >= pageSize),
144157
}, nil
145158
}
146159

@@ -155,7 +168,7 @@ func ListAll[T any](ctx context.Context, c *Client, path string, query map[strin
155168
page := 1
156169

157170
for {
158-
result, err := ListPage[T](ctx, c, path, query, ListOptions{Page: page, Limit: defaultPageLimit})
171+
result, err := ListPage[T](ctx, c, path, query, ListOptions{Page: page, PageSize: defaultPageSize})
159172
if err != nil {
160173
return nil, err
161174
}
@@ -180,7 +193,7 @@ func ListIter[T any](ctx context.Context, c *Client, path string, query map[stri
180193
return func(yield func(T, error) bool) {
181194
page := 1
182195
for {
183-
result, err := ListPage[T](ctx, c, path, query, ListOptions{Page: page, Limit: defaultPageLimit})
196+
result, err := ListPage[T](ctx, c, path, query, ListOptions{Page: page, PageSize: defaultPageSize})
184197
if err != nil {
185198
yield(*new(T), err)
186199
return

pagination_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ func TestListPage_QueryParams_Good(t *testing.T) {
110110

111111
c := NewClient(srv.URL, "tok")
112112
_, err := ListPage[map[string]int](context.Background(), c, "/api/v1/repos",
113-
map[string]string{"state": "open"}, ListOptions{Page: 2, Limit: 25})
113+
map[string]string{"state": "open"}, ListOptions{Page: 2, PageSize: 25})
114114
if err != nil {
115115
t.Fatal(err)
116116
}

0 commit comments

Comments
 (0)