Skip to content

Commit 1947b90

Browse files
committed
multi: typed callback in ExecTx
Provide a wrapped store type, exposing ExecTx method with a subset interface in the callback argument. BaseDB interfaces in instantout, reservation and sweepbatcher use ExecTx with their subset Querier instead of whole sqlc.Querier (*sqlc.Queries). This is needed to make the packages more reusable, so they don't depend on methods of *sqlc.Queries they don't use.
1 parent d341448 commit 1947b90

File tree

8 files changed

+75
-17
lines changed

8 files changed

+75
-17
lines changed

instantout/reservation/manager_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ func newManagerTestContext(t *testing.T) *ManagerTestContext {
112112

113113
dbFixture := loopdb.NewTestDB(t)
114114

115-
store := NewSQLStore(dbFixture)
115+
store := NewSQLStore(loopdb.NewTypedStore[Querier](dbFixture))
116116

117117
mockReservationClient := new(mockReservationClient)
118118

instantout/reservation/store.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ type BaseDB interface {
5252
// ExecTx allows for executing a function in the context of a database
5353
// transaction.
5454
ExecTx(ctx context.Context, txOptions loopdb.TxOptions,
55-
txBody func(*sqlc.Queries) error) error
55+
txBody func(Querier) error) error
5656
}
5757

5858
// SQLStore manages the reservations in the database.
@@ -92,7 +92,7 @@ func (r *SQLStore) CreateReservation(ctx context.Context,
9292
}
9393

9494
return r.baseDb.ExecTx(ctx, loopdb.NewSqlWriteOpts(),
95-
func(q *sqlc.Queries) error {
95+
func(q Querier) error {
9696
err := q.CreateReservation(ctx, args)
9797
if err != nil {
9898
return err
@@ -132,7 +132,7 @@ func (r *SQLStore) UpdateReservation(ctx context.Context,
132132
}
133133

134134
return r.baseDb.ExecTx(ctx, loopdb.NewSqlWriteOpts(),
135-
func(q *sqlc.Queries) error {
135+
func(q Querier) error {
136136
err := q.UpdateReservation(ctx, updateArgs)
137137
if err != nil {
138138
return err
@@ -148,7 +148,7 @@ func (r *SQLStore) GetReservation(ctx context.Context,
148148

149149
var reservation *Reservation
150150
err := r.baseDb.ExecTx(ctx, loopdb.NewSqlReadOpts(),
151-
func(q *sqlc.Queries) error {
151+
func(q Querier) error {
152152
var err error
153153
reservationRow, err := q.GetReservation(
154154
ctx, reservationId[:],
@@ -192,7 +192,7 @@ func (r *SQLStore) ListReservations(ctx context.Context) ([]*Reservation,
192192
var result []*Reservation
193193

194194
err := r.baseDb.ExecTx(ctx, loopdb.NewSqlReadOpts(),
195-
func(q *sqlc.Queries) error {
195+
func(q Querier) error {
196196
var err error
197197

198198
reservations, err := q.GetReservations(ctx)

instantout/reservation/store_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ func TestSqlStore(t *testing.T) {
1919
testDb := loopdb.NewTestDB(t)
2020
defer testDb.Close()
2121

22-
store := NewSQLStore(testDb)
22+
store := NewSQLStore(loopdb.NewTypedStore[Querier](testDb))
2323

2424
// Create a reservation and store it.
2525
reservation := &Reservation{

instantout/store.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ type InstantOutBaseDB interface {
6363
// ExecTx allows for executing a function in the context of a database
6464
// transaction.
6565
ExecTx(ctx context.Context, txOptions loopdb.TxOptions,
66-
txBody func(*sqlc.Queries) error) error
66+
txBody func(Querier) error) error
6767
}
6868

6969
// ReservationStore is the interface that is required to load the reservations
@@ -139,7 +139,7 @@ func (s *SQLStore) CreateInstantLoopOut(ctx context.Context,
139139
}
140140

141141
return s.baseDb.ExecTx(ctx, loopdb.NewSqlWriteOpts(),
142-
func(q *sqlc.Queries) error {
142+
func(q Querier) error {
143143
err := q.InsertSwap(ctx, swapArgs)
144144
if err != nil {
145145
return err
@@ -211,7 +211,7 @@ func (s *SQLStore) UpdateInstantLoopOut(ctx context.Context,
211211
}
212212

213213
return s.baseDb.ExecTx(ctx, loopdb.NewSqlWriteOpts(),
214-
func(q *sqlc.Queries) error {
214+
func(q Querier) error {
215215
err := q.UpdateInstantOut(ctx, updateParams)
216216
if err != nil {
217217
return err

loopd/daemon.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,10 @@ func (d *Daemon) initialize(withMacaroonService bool) error {
417417
return err
418418
}
419419

420-
sweeperDb := sweepbatcher.NewSQLStore(baseDb, chainParams)
420+
sweeperDb := sweepbatcher.NewSQLStore(
421+
loopdb.NewTypedStore[sweepbatcher.Querier](baseDb),
422+
chainParams,
423+
)
421424

422425
// Create an instance of the loop client library.
423426
swapClient, clientCleanup, err := getClient(
@@ -501,7 +504,9 @@ func (d *Daemon) initialize(withMacaroonService bool) error {
501504
)
502505
// Create the reservation and instantout managers.
503506
if d.cfg.EnableExperimental {
504-
reservationStore := reservation.NewSQLStore(baseDb)
507+
reservationStore := reservation.NewSQLStore(
508+
loopdb.NewTypedStore[reservation.Querier](baseDb),
509+
)
505510
reservationConfig := &reservation.Config{
506511
Store: reservationStore,
507512
Wallet: d.lnd.WalletKit,
@@ -516,7 +521,8 @@ func (d *Daemon) initialize(withMacaroonService bool) error {
516521

517522
// Create the instantout services.
518523
instantOutStore := instantout.NewSQLStore(
519-
baseDb, clock.NewDefaultClock(), reservationStore,
524+
loopdb.NewTypedStore[instantout.Querier](baseDb),
525+
clock.NewDefaultClock(), reservationStore,
520526
d.lnd.ChainParams,
521527
)
522528
instantOutConfig := &instantout.Config{

loopd/view.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ func view(config *Config, lisCfg *ListenerCfg) error {
3232
return err
3333
}
3434

35-
sweeperDb := sweepbatcher.NewSQLStore(baseDb, chainParams)
35+
sweeperDb := sweepbatcher.NewSQLStore(
36+
loopdb.NewTypedStore[sweepbatcher.Querier](baseDb),
37+
chainParams,
38+
)
3639

3740
swapClient, cleanup, err := getClient(
3841
config, swapDb, sweeperDb, &lnd.LndServices,

loopdb/typed_store.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package loopdb
2+
3+
import (
4+
"context"
5+
6+
"github.com/lightninglabs/loop/loopdb/sqlc"
7+
)
8+
9+
// BatchedQuerier implements all DB queries and ExecTx on *sqlc.Queries.
10+
// It is implemented by BaseDB, SqliteSwapStore, etc.
11+
type BatchedQuerier interface {
12+
sqlc.Querier
13+
14+
// ExecTx is a wrapper for txBody to abstract the creation and commit of
15+
// a db transaction. The db transaction is embedded in a `*sqlc.Queries`
16+
// that txBody needs to use when executing each one of the queries that
17+
// need to be applied atomically.
18+
ExecTx(ctx context.Context, txOptions TxOptions,
19+
txBody func(*sqlc.Queries) error) error
20+
}
21+
22+
// TypedStore is similar to BaseDB but provides parameterized ExecTx.
23+
// It is used in other packages expecting ExecTx operating on subset of methods.
24+
type TypedStore[Q any] struct {
25+
BatchedQuerier
26+
}
27+
28+
// NewTypedStore wraps a db, replacing generic ExecTx method with the typed one.
29+
func NewTypedStore[Q any](db BatchedQuerier) *TypedStore[Q] {
30+
// Make sure *sqlc.Queries can be casted to Q.
31+
_ = any((*sqlc.Queries)(nil)).(Q)
32+
33+
return &TypedStore[Q]{
34+
BatchedQuerier: db,
35+
}
36+
}
37+
38+
// ExecTx will execute the passed txBody, operating upon generic parameter Q
39+
// (usually a storage interface) in a single transaction. The set of TxOptions
40+
// are passed in to allow the caller to specify if a transaction is read-only.
41+
func (s *TypedStore[Q]) ExecTx(ctx context.Context,
42+
txOptions TxOptions, txBody func(Q) error) error {
43+
44+
return s.BatchedQuerier.ExecTx(ctx, txOptions,
45+
func(q *sqlc.Queries) error {
46+
return txBody(any(q).(Q))
47+
},
48+
)
49+
}

sweepbatcher/store.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ type BaseDB interface {
6464
// ExecTx allows for executing a function in the context of a database
6565
// transaction.
6666
ExecTx(ctx context.Context, txOptions loopdb.TxOptions,
67-
txBody func(*sqlc.Queries) error) error
67+
txBody func(Querier) error) error
6868
}
6969

7070
// SQLStore manages the reservations in the database.
@@ -120,7 +120,7 @@ func (s *SQLStore) InsertSweepBatch(ctx context.Context, batch *dbBatch) (int32,
120120
// for batches that have no sweeps and so we'd not be able to resume.
121121
func (s *SQLStore) DropBatch(ctx context.Context, id int32) error {
122122
readOpts := loopdb.NewSqlWriteOpts()
123-
return s.baseDb.ExecTx(ctx, readOpts, func(tx *sqlc.Queries) error {
123+
return s.baseDb.ExecTx(ctx, readOpts, func(tx Querier) error {
124124
dbSweeps, err := tx.GetBatchSweeps(ctx, id)
125125
if err != nil {
126126
return err
@@ -151,7 +151,7 @@ func (s *SQLStore) FetchBatchSweeps(ctx context.Context, id int32) (
151151
readOpts := loopdb.NewSqlReadOpts()
152152
var sweeps []*dbSweep
153153

154-
err := s.baseDb.ExecTx(ctx, readOpts, func(tx *sqlc.Queries) error {
154+
err := s.baseDb.ExecTx(ctx, readOpts, func(tx Querier) error {
155155
dbSweeps, err := tx.GetBatchSweeps(ctx, id)
156156
if err != nil {
157157
return err

0 commit comments

Comments
 (0)