Skip to content

Commit 0545e6a

Browse files
committed
feat: add some pagination options
1 parent 858712a commit 0545e6a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+336
-83
lines changed

docs/api/README.md

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ Accept: application/json
136136
|---|---|---|---|---|
137137
|pageSize|query|integer(int64)|false|The maximum number of results to return per page.|
138138
|cursor|query|string|false|Parameter used in pagination requests. Maximum page size is set to 15.|
139+
|sort|query|string|false|Sort results using a field name and order (ascending or descending). |
139140
|body|body|object|true|none|
140141

141142
#### Detailed descriptions
@@ -147,6 +148,9 @@ Set to the value of next for the next page of results.
147148
Set to the value of previous for the previous page of results.
148149
No other parameters can be set when this parameter is set.
149150

151+
**sort**: Sort results using a field name and order (ascending or descending).
152+
Format: `<field>:<order>`, where `<field>` is the field name and `<order>` is either `asc` or `desc`.
153+
150154
> Example responses
151155
152156
> 200 Response
@@ -737,6 +741,7 @@ List accounts from a ledger, sorted by address in descending order.
737741
|cursor|query|string|false|Parameter used in pagination requests. Maximum page size is set to 15.|
738742
|expand|query|string|false|none|
739743
|pit|query|string(date-time)|false|none|
744+
|sort|query|string|false|Sort results using a field name and order (ascending or descending). |
740745
|body|body|object|true|none|
741746

742747
#### Detailed descriptions
@@ -748,6 +753,9 @@ Set to the value of next for the next page of results.
748753
Set to the value of previous for the previous page of results.
749754
No other parameters can be set when this parameter is set.
750755

756+
**sort**: Sort results using a field name and order (ascending or descending).
757+
Format: `<field>:<order>`, where `<field>` is the field name and `<order>` is either `asc` or `desc`.
758+
751759
> Example responses
752760
753761
> 200 Response
@@ -765,6 +773,7 @@ No other parameters can be set when this parameter is set.
765773
"metadata": {
766774
"admin": "true"
767775
},
776+
"firstUsage": "2023-01-01T00:00:00Z",
768777
"volumes": {
769778
"USD": {
770779
"input": 100,
@@ -849,6 +858,7 @@ Accept: application/json
849858
"metadata": {
850859
"admin": "true"
851860
},
861+
"firstUsage": "2023-01-01T00:00:00Z",
852862
"volumes": {
853863
"USD": {
854864
"input": 100,
@@ -1151,8 +1161,9 @@ List transactions from a ledger, sorted by id in descending order.
11511161
|cursor|query|string|false|Parameter used in pagination requests. Maximum page size is set to 15.|
11521162
|expand|query|string|false|none|
11531163
|pit|query|string(date-time)|false|none|
1154-
|order|query|string|false|none|
1164+
|order|query|string|false|Deprecated: Use sort param|
11551165
|reverse|query|boolean|false|none|
1166+
|sort|query|string|false|Sort results using a field name and order (ascending or descending). |
11561167
|body|body|object|true|none|
11571168

11581169
#### Detailed descriptions
@@ -1164,6 +1175,9 @@ Set to the value of next for the next page of results.
11641175
Set to the value of previous for the previous page of results.
11651176
No other parameters can be set when this parameter is set.
11661177

1178+
**sort**: Sort results using a field name and order (ascending or descending).
1179+
Format: `<field>:<order>`, where `<field>` is the field name and `<order>` is either `asc` or `desc`.
1180+
11671181
#### Enumerated Values
11681182

11691183
|Parameter|Value|
@@ -1862,6 +1876,7 @@ Accept: application/json
18621876
|startTime|query|string(date-time)|false|none|
18631877
|insertionDate|query|boolean|false|Use insertion date instead of effective date|
18641878
|groupBy|query|integer(int64)|false|Group volumes and balance by the level of the segment of the address|
1879+
|sort|query|string|false|Sort results using a field name and order (ascending or descending). |
18651880
|body|body|object|true|none|
18661881

18671882
#### Detailed descriptions
@@ -1873,6 +1888,9 @@ Set to the value of next for the next page of results.
18731888
Set to the value of previous for the previous page of results.
18741889
No other parameters can be set when this parameter is set.
18751890

1891+
**sort**: Sort results using a field name and order (ascending or descending).
1892+
Format: `<field>:<order>`, where `<field>` is the field name and `<order>` is either `asc` or `desc`.
1893+
18761894
> Example responses
18771895
18781896
> 200 Response
@@ -1941,6 +1959,7 @@ List the logs from a ledger, sorted by ID in descending order.
19411959
|pageSize|query|integer(int64)|false|The maximum number of results to return per page.|
19421960
|cursor|query|string|false|Parameter used in pagination requests. Maximum page size is set to 15.|
19431961
|pit|query|string(date-time)|false|none|
1962+
|sort|query|string|false|Sort results using a field name and order (ascending or descending). |
19441963
|body|body|object|true|none|
19451964

19461965
#### Detailed descriptions
@@ -1952,6 +1971,9 @@ Set to the value of next for the next page of results.
19521971
Set to the value of previous for the previous page of results.
19531972
No other parameters can be set when this parameter is set.
19541973

1974+
**sort**: Sort results using a field name and order (ascending or descending).
1975+
Format: `<field>:<order>`, where `<field>` is the field name and `<order>` is either `asc` or `desc`.
1976+
19551977
> Example responses
19561978
19571979
> 200 Response
@@ -2101,6 +2123,7 @@ Authorization ( Scopes: ledger:write )
21012123
"metadata": {
21022124
"admin": "true"
21032125
},
2126+
"firstUsage": "2023-01-01T00:00:00Z",
21042127
"volumes": {
21052128
"USD": {
21062129
"input": 100,
@@ -2311,6 +2334,7 @@ Authorization ( Scopes: ledger:write )
23112334
"metadata": {
23122335
"admin": "true"
23132336
},
2337+
"firstUsage": "2023-01-01T00:00:00Z",
23142338
"volumes": {
23152339
"USD": {
23162340
"input": 100,
@@ -2491,6 +2515,7 @@ Authorization ( Scopes: ledger:write )
24912515
"metadata": {
24922516
"admin": "true"
24932517
},
2518+
"firstUsage": "2023-01-01T00:00:00Z",
24942519
"volumes": {
24952520
"USD": {
24962521
"input": 100,
@@ -2526,6 +2551,7 @@ Authorization ( Scopes: ledger:write )
25262551
|address|string|true|none|none|
25272552
|metadata|object|true|none|none|
25282553
|» **additionalProperties**|string|false|none|none|
2554+
|firstUsage|string(date-time)|false|none|none|
25292555
|volumes|[V2Volumes](#schemav2volumes)|false|none|none|
25302556
|effectiveVolumes|[V2Volumes](#schemav2volumes)|false|none|none|
25312557

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ require (
5151

5252
require (
5353
github.com/formancehq/go-libs/v3 v3.0.0-20250610201819-3bfa67aab0e2
54+
github.com/iancoleman/strcase v0.3.0
5455
github.com/robfig/cron/v3 v3.0.1
5556
github.com/spf13/viper v1.20.1
5657
gopkg.in/yaml.v3 v3.0.1

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,8 @@ github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFO
194194
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
195195
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
196196
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
197+
github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI=
198+
github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
197199
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
198200
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
199201
github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E=

internal/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ type Account struct {
232232

233233
Address string `json:"address" bun:"address"`
234234
Metadata metadata.Metadata `json:"metadata" bun:"metadata,type:jsonb,default:'{}'"`
235-
FirstUsage time.Time `json:"-" bun:"first_usage,nullzero"`
235+
FirstUsage time.Time `json:"firstUsage" bun:"first_usage,nullzero"`
236236
InsertionDate time.Time `json:"-" bun:"insertion_date,nullzero"`
237237
UpdatedAt time.Time `json:"-" bun:"updated_at,nullzero"`
238238
Volumes VolumesByAssets `json:"volumes,omitempty" bun:"volumes,scanonly"`

internal/account.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ type Account struct {
1616

1717
Address string `json:"address" bun:"address"`
1818
Metadata metadata.Metadata `json:"metadata" bun:"metadata,type:jsonb,default:'{}'"`
19-
FirstUsage time.Time `json:"-" bun:"first_usage,nullzero"`
19+
FirstUsage time.Time `json:"firstUsage" bun:"first_usage,nullzero"`
2020
InsertionDate time.Time `json:"-" bun:"insertion_date,nullzero"`
2121
UpdatedAt time.Time `json:"-" bun:"updated_at,nullzero"`
2222
Volumes VolumesByAssets `json:"volumes,omitempty" bun:"volumes,scanonly"`

internal/api/common/errors.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package common
22

33
import (
44
"errors"
5+
storagecommon "github.com/formancehq/ledger/internal/storage/common"
56
"net/http"
67

78
"github.com/formancehq/go-libs/v3/api"
@@ -52,6 +53,18 @@ func HandleCommonWriteErrors(w http.ResponseWriter, r *http.Request, err error)
5253
}
5354
}
5455

56+
func HandleCommonPaginationErrors(w http.ResponseWriter, r *http.Request, err error) {
57+
switch {
58+
case errors.Is(err, storagecommon.ErrInvalidQuery{}) ||
59+
errors.Is(err, ledgercontroller.ErrMissingFeature{}) ||
60+
errors.Is(err, storagecommon.ErrNotPaginatedField{}):
61+
api.BadRequest(w, ErrValidation, err)
62+
default:
63+
HandleCommonErrors(w, r, err)
64+
}
65+
}
66+
67+
5568
func InternalServerError(w http.ResponseWriter, r *http.Request, err error) {
5669
otlp.RecordError(r.Context(), err)
5770
logging.FromContext(r.Context()).Error(err)

internal/api/v2/common.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package v2
22

33
import (
4+
"fmt"
45
. "github.com/formancehq/go-libs/v3/collectionutils"
56
"github.com/formancehq/ledger/internal/api/common"
67
storagecommon "github.com/formancehq/ledger/internal/storage/common"
8+
"github.com/iancoleman/strcase"
79
"io"
810
"net/http"
911
"strings"
@@ -89,6 +91,21 @@ func getPaginatedQuery[Options any](
8991
return nil, err
9092
}
9193

94+
if sort := r.URL.Query().Get("sort"); sort != "" {
95+
parts := strings.SplitN(sort, ":", 2)
96+
column = strcase.ToSnake(parts[0])
97+
if len(parts) > 1 {
98+
switch {
99+
case strings.ToLower(parts[1]) == "desc":
100+
order = bunpaginate.OrderDesc
101+
case strings.ToLower(parts[1]) == "asc":
102+
order = bunpaginate.OrderAsc
103+
default:
104+
return nil, fmt.Errorf("invalid order: %s", parts[1])
105+
}
106+
}
107+
}
108+
92109
return &storagecommon.InitialPaginatedQuery[Options]{
93110
Column: column,
94111
Order: &order,

internal/api/v2/controllers_accounts_list.go

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
package v2
22

33
import (
4-
"errors"
54
"github.com/formancehq/go-libs/v3/api"
65
"github.com/formancehq/go-libs/v3/bun/bunpaginate"
76
ledger "github.com/formancehq/ledger/internal"
87
"github.com/formancehq/ledger/internal/api/common"
9-
ledgercontroller "github.com/formancehq/ledger/internal/controller/ledger"
10-
storagecommon "github.com/formancehq/ledger/internal/storage/common"
118
"net/http"
129
)
1310

@@ -23,12 +20,7 @@ func listAccounts(paginationConfig common.PaginationConfig) http.HandlerFunc {
2320

2421
cursor, err := l.ListAccounts(r.Context(), query)
2522
if err != nil {
26-
switch {
27-
case errors.Is(err, storagecommon.ErrInvalidQuery{}) || errors.Is(err, ledgercontroller.ErrMissingFeature{}):
28-
api.BadRequest(w, common.ErrValidation, err)
29-
default:
30-
common.HandleCommonErrors(w, r, err)
31-
}
23+
common.HandleCommonPaginationErrors(w, r, err)
3224
return
3325
}
3426

internal/api/v2/controllers_ledgers_list.go

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,10 @@ package v2
22

33
import (
44
"github.com/formancehq/ledger/internal/api/common"
5-
storagecommon "github.com/formancehq/ledger/internal/storage/common"
65
"net/http"
76

8-
"errors"
97
"github.com/formancehq/go-libs/v3/api"
108
"github.com/formancehq/go-libs/v3/bun/bunpaginate"
11-
ledgercontroller "github.com/formancehq/ledger/internal/controller/ledger"
129
"github.com/formancehq/ledger/internal/controller/system"
1310
)
1411

@@ -23,12 +20,7 @@ func listLedgers(b system.Controller, paginationConfig common.PaginationConfig)
2320

2421
ledgers, err := b.ListLedgers(r.Context(), rq)
2522
if err != nil {
26-
switch {
27-
case errors.Is(err, storagecommon.ErrInvalidQuery{}) || errors.Is(err, ledgercontroller.ErrMissingFeature{}):
28-
api.BadRequest(w, common.ErrValidation, err)
29-
default:
30-
common.HandleCommonErrors(w, r, err)
31-
}
23+
common.HandleCommonPaginationErrors(w, r, err)
3224
return
3325
}
3426

internal/api/v2/controllers_logs_list.go

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
package v2
22

33
import (
4-
"errors"
54
"github.com/formancehq/go-libs/v3/api"
65
"github.com/formancehq/go-libs/v3/bun/bunpaginate"
76
ledger "github.com/formancehq/ledger/internal"
87
"github.com/formancehq/ledger/internal/api/common"
9-
storagecommon "github.com/formancehq/ledger/internal/storage/common"
108
"net/http"
119
)
1210

@@ -22,12 +20,7 @@ func listLogs(paginationConfig common.PaginationConfig) http.HandlerFunc {
2220

2321
cursor, err := l.ListLogs(r.Context(), rq)
2422
if err != nil {
25-
switch {
26-
case errors.Is(err, storagecommon.ErrInvalidQuery{}):
27-
api.BadRequest(w, common.ErrValidation, err)
28-
default:
29-
common.HandleCommonErrors(w, r, err)
30-
}
23+
common.HandleCommonPaginationErrors(w, r, err)
3124
return
3225
}
3326

0 commit comments

Comments
 (0)