Skip to content

Commit e45ed86

Browse files
committed
invoices: fix and correctly cover paginated queries
Previously paginated queries offseted the add_index_get, add_index_let, settle_index_get and settle_index_let parameters with the paginators current page offset, however this was incorrect as we can just use SQL's LIMIT/OFFSET to paginate. This commit fixes this issue and adds an optional parameter to the constructor of the invoice SQL store to set page size. This is useful when testing as we can now cover pagination correctly with our existing unit tests.
1 parent 71ba355 commit e45ed86

File tree

2 files changed

+59
-41
lines changed

2 files changed

+59
-41
lines changed

invoices/invoices_test.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,14 @@ func TestInvoices(t *testing.T) {
249249

250250
testClock := clock.NewTestClock(testNow)
251251

252-
return invpkg.NewSQLStore(executor, testClock)
252+
// We'll use a pagination limit of 3 for all tests to ensure
253+
// that we also cover query pagination.
254+
const testPaginationLimit = 3
255+
256+
return invpkg.NewSQLStore(
257+
executor, testClock,
258+
invpkg.WithPaginationLimit(testPaginationLimit),
259+
)
253260
}
254261

255262
for _, test := range testList {

invoices/sql_store.go

Lines changed: 51 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ import (
2020
)
2121

2222
const (
23-
// queryPaginationLimit is used in the LIMIT clause of the SQL queries
24-
// to limit the number of rows returned.
25-
queryPaginationLimit = 100
23+
// defaultQueryPaginationLimit is used in the LIMIT clause of the SQL
24+
// queries to limit the number of rows returned.
25+
defaultQueryPaginationLimit = 100
2626
)
2727

2828
// SQLInvoiceQueries is an interface that defines the set of operations that can
@@ -152,16 +152,47 @@ type BatchedSQLInvoiceQueries interface {
152152
type SQLStore struct {
153153
db BatchedSQLInvoiceQueries
154154
clock clock.Clock
155+
opts SQLStoreOptions
156+
}
157+
158+
// SQLStoreOptions holds the options for the SQL store.
159+
type SQLStoreOptions struct {
160+
paginationLimit int
161+
}
162+
163+
// defaultSQLStoreOptions returns the default options for the SQL store.
164+
func defaultSQLStoreOptions() SQLStoreOptions {
165+
return SQLStoreOptions{
166+
paginationLimit: defaultQueryPaginationLimit,
167+
}
168+
}
169+
170+
// SQLStoreOption is a functional option that can be used to optionally modify
171+
// the behavior of the SQL store.
172+
type SQLStoreOption func(*SQLStoreOptions)
173+
174+
// WithPaginationLimit sets the pagination limit for the SQL store queries that
175+
// paginate results.
176+
func WithPaginationLimit(limit int) SQLStoreOption {
177+
return func(o *SQLStoreOptions) {
178+
o.paginationLimit = limit
179+
}
155180
}
156181

157182
// NewSQLStore creates a new SQLStore instance given a open
158183
// BatchedSQLInvoiceQueries storage backend.
159184
func NewSQLStore(db BatchedSQLInvoiceQueries,
160-
clock clock.Clock) *SQLStore {
185+
clock clock.Clock, options ...SQLStoreOption) *SQLStore {
186+
187+
opts := defaultSQLStoreOptions()
188+
for _, applyOption := range options {
189+
applyOption(&opts)
190+
}
161191

162192
return &SQLStore{
163193
db: db,
164194
clock: clock,
195+
opts: opts,
165196
}
166197
}
167198

@@ -617,13 +648,11 @@ func (i *SQLStore) FetchPendingInvoices(ctx context.Context) (
617648

618649
readTxOpt := NewSQLInvoiceQueryReadTx()
619650
err := i.db.ExecTx(ctx, &readTxOpt, func(db SQLInvoiceQueries) error {
620-
limit := queryPaginationLimit
621-
622651
return queryWithLimit(func(offset int) (int, error) {
623652
params := sqlc.FilterInvoicesParams{
624653
PendingOnly: true,
625654
NumOffset: int32(offset),
626-
NumLimit: int32(limit),
655+
NumLimit: int32(i.opts.paginationLimit),
627656
Reverse: false,
628657
}
629658

@@ -646,7 +675,7 @@ func (i *SQLStore) FetchPendingInvoices(ctx context.Context) (
646675
}
647676

648677
return len(rows), nil
649-
}, limit)
678+
}, i.opts.paginationLimit)
650679
}, func() {
651680
invoices = make(map[lntypes.Hash]Invoice)
652681
})
@@ -660,8 +689,7 @@ func (i *SQLStore) FetchPendingInvoices(ctx context.Context) (
660689

661690
// InvoicesSettledSince can be used by callers to catch up any settled invoices
662691
// they missed within the settled invoice time series. We'll return all known
663-
// settled invoice that have a settle index higher than the passed
664-
// sinceSettleIndex.
692+
// settled invoice that have a settle index higher than the passed idx.
665693
//
666694
// NOTE: The index starts from 1. As a result we enforce that specifying a value
667695
// below the starting index value is a noop.
@@ -676,14 +704,11 @@ func (i *SQLStore) InvoicesSettledSince(ctx context.Context, idx uint64) (
676704

677705
readTxOpt := NewSQLInvoiceQueryReadTx()
678706
err := i.db.ExecTx(ctx, &readTxOpt, func(db SQLInvoiceQueries) error {
679-
settleIdx := idx
680-
limit := queryPaginationLimit
681-
682707
err := queryWithLimit(func(offset int) (int, error) {
683708
params := sqlc.FilterInvoicesParams{
684-
SettleIndexGet: sqldb.SQLInt64(settleIdx + 1),
685-
NumLimit: int32(limit),
709+
SettleIndexGet: sqldb.SQLInt64(idx + 1),
686710
NumOffset: int32(offset),
711+
NumLimit: int32(i.opts.paginationLimit),
687712
Reverse: false,
688713
}
689714

@@ -707,10 +732,8 @@ func (i *SQLStore) InvoicesSettledSince(ctx context.Context, idx uint64) (
707732
invoices = append(invoices, *invoice)
708733
}
709734

710-
settleIdx += uint64(limit)
711-
712735
return len(rows), nil
713-
}, limit)
736+
}, i.opts.paginationLimit)
714737
if err != nil {
715738
return err
716739
}
@@ -777,7 +800,7 @@ func (i *SQLStore) InvoicesSettledSince(ctx context.Context, idx uint64) (
777800

778801
// InvoicesAddedSince can be used by callers to seek into the event time series
779802
// of all the invoices added in the database. This method will return all
780-
// invoices with an add index greater than the specified sinceAddIndex.
803+
// invoices with an add index greater than the specified idx.
781804
//
782805
// NOTE: The index starts from 1. As a result we enforce that specifying a value
783806
// below the starting index value is a noop.
@@ -792,14 +815,11 @@ func (i *SQLStore) InvoicesAddedSince(ctx context.Context, idx uint64) (
792815

793816
readTxOpt := NewSQLInvoiceQueryReadTx()
794817
err := i.db.ExecTx(ctx, &readTxOpt, func(db SQLInvoiceQueries) error {
795-
addIdx := idx
796-
limit := queryPaginationLimit
797-
798818
return queryWithLimit(func(offset int) (int, error) {
799819
params := sqlc.FilterInvoicesParams{
800-
AddIndexGet: sqldb.SQLInt64(addIdx + 1),
801-
NumLimit: int32(limit),
820+
AddIndexGet: sqldb.SQLInt64(idx + 1),
802821
NumOffset: int32(offset),
822+
NumLimit: int32(i.opts.paginationLimit),
803823
Reverse: false,
804824
}
805825

@@ -821,10 +841,8 @@ func (i *SQLStore) InvoicesAddedSince(ctx context.Context, idx uint64) (
821841
result = append(result, *invoice)
822842
}
823843

824-
addIdx += uint64(limit)
825-
826844
return len(rows), nil
827-
}, limit)
845+
}, i.opts.paginationLimit)
828846
}, func() {
829847
result = nil
830848
})
@@ -851,41 +869,34 @@ func (i *SQLStore) QueryInvoices(ctx context.Context,
851869

852870
readTxOpt := NewSQLInvoiceQueryReadTx()
853871
err := i.db.ExecTx(ctx, &readTxOpt, func(db SQLInvoiceQueries) error {
854-
limit := queryPaginationLimit
855-
856872
return queryWithLimit(func(offset int) (int, error) {
857873
params := sqlc.FilterInvoicesParams{
858874
NumOffset: int32(offset),
859-
NumLimit: int32(limit),
875+
NumLimit: int32(i.opts.paginationLimit),
860876
PendingOnly: q.PendingOnly,
877+
Reverse: q.Reversed,
861878
}
862879

863880
if q.Reversed {
864-
idx := int32(q.IndexOffset)
865-
866881
// If the index offset was not set, we want to
867882
// fetch from the lastest invoice.
868-
if idx == 0 {
883+
if q.IndexOffset == 0 {
869884
params.AddIndexLet = sqldb.SQLInt64(
870885
int64(math.MaxInt64),
871886
)
872887
} else {
873888
// The invoice with index offset id must
874889
// not be included in the results.
875890
params.AddIndexLet = sqldb.SQLInt64(
876-
idx - int32(offset) - 1,
891+
q.IndexOffset - 1,
877892
)
878893
}
879-
880-
params.Reverse = true
881894
} else {
882895
// The invoice with index offset id must not be
883896
// included in the results.
884897
params.AddIndexGet = sqldb.SQLInt64(
885-
q.IndexOffset + uint64(offset) + 1,
898+
q.IndexOffset + 1,
886899
)
887-
888-
params.Reverse = false
889900
}
890901

891902
if q.CreationDateStart != 0 {
@@ -923,7 +934,7 @@ func (i *SQLStore) QueryInvoices(ctx context.Context,
923934
}
924935

925936
return len(rows), nil
926-
}, limit)
937+
}, i.opts.paginationLimit)
927938
}, func() {
928939
invoices = nil
929940
})

0 commit comments

Comments
 (0)