Skip to content

Commit

Permalink
Avoid using pointers when not needed.
Browse files Browse the repository at this point in the history
  • Loading branch information
marcelosalloum committed Dec 10, 2024
1 parent c741b96 commit a15b635
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 69 deletions.
74 changes: 51 additions & 23 deletions internal/data/circle_recipient.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,37 @@ import (
)

type CircleRecipient struct {
ReceiverWalletID string `db:"receiver_wallet_id"`
IdempotencyKey string `db:"idempotency_key"`
CircleRecipientID *string `db:"circle_recipient_id"`
Status *CircleRecipientStatus `db:"status"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
SyncAttempts int `db:"sync_attempts"`
LastSyncAttemptAt *time.Time `db:"last_sync_attempt_at"`
ResponseBody []byte `db:"response_body"`
ReceiverWalletID string `db:"receiver_wallet_id"`
IdempotencyKey string `db:"idempotency_key"`
CircleRecipientID string `db:"circle_recipient_id"`
Status CircleRecipientStatus `db:"status"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
SyncAttempts int `db:"sync_attempts"`
LastSyncAttemptAt time.Time `db:"last_sync_attempt_at"`
ResponseBody []byte `db:"response_body"`
}

type CircleRecipientStatus string

func (s *CircleRecipientStatus) Scan(value interface{}) error {
if value == nil {
*s = ""
return nil
}

switch v := value.(type) {
case string:
*s = CircleRecipientStatus(v)
case []uint8:
*s = CircleRecipientStatus(string(v)) // Convert byte slice to string
default:
return fmt.Errorf("invalid type for CircleRecipientStatus: %T", value)
}

return nil
}

const (
CircleRecipientStatusPending CircleRecipientStatus = "pending"
CircleRecipientStatusActive CircleRecipientStatus = "active" // means success
Expand Down Expand Up @@ -59,18 +77,30 @@ func ParseRecipientStatus(statusStr string) (CircleRecipientStatus, error) {
}

type CircleRecipientUpdate struct {
IdempotencyKey string `db:"idempotency_key"`
CircleRecipientID *string `db:"circle_recipient_id"`
Status *CircleRecipientStatus `db:"status"`
SyncAttempts int `db:"sync_attempts"`
LastSyncAttemptAt *time.Time `db:"last_sync_attempt_at"`
ResponseBody []byte `db:"response_body"`
IdempotencyKey string `db:"idempotency_key"`
CircleRecipientID string `db:"circle_recipient_id"`
Status CircleRecipientStatus `db:"status"`
SyncAttempts int `db:"sync_attempts"`
LastSyncAttemptAt time.Time `db:"last_sync_attempt_at"`
ResponseBody []byte `db:"response_body"`
}

type CircleRecipientModel struct {
dbConnectionPool db.DBConnectionPool
}

const circleRecipientFields = `
receiver_wallet_id,
idempotency_key,
COALESCE(circle_recipient_id, '') AS circle_recipient_id,
status,
created_at,
updated_at,
sync_attempts,
COALESCE(last_sync_attempt_at, '0001-01-01 00:00:00+00') AS last_sync_attempt_at,
response_body
`

func (m CircleRecipientModel) Insert(ctx context.Context, receiverWalletID string) (*CircleRecipient, error) {
if receiverWalletID == "" {
return nil, fmt.Errorf("receiverWalletID is required")
Expand All @@ -82,8 +112,7 @@ func (m CircleRecipientModel) Insert(ctx context.Context, receiverWalletID strin
VALUES
($1)
RETURNING
*
`
` + circleRecipientFields

var circleRecipient CircleRecipient
err := m.dbConnectionPool.GetContext(ctx, &circleRecipient, query, receiverWalletID)
Expand Down Expand Up @@ -111,9 +140,8 @@ func (m CircleRecipientModel) Update(ctx context.Context, receiverWalletID strin
%s
WHERE
receiver_wallet_id = ?
RETURNING
*
`, setClause)
RETURNING `+circleRecipientFields,
setClause)
params = append(params, receiverWalletID)
query = m.dbConnectionPool.Rebind(query)

Expand All @@ -134,14 +162,14 @@ func (m CircleRecipientModel) GetByReceiverWalletID(ctx context.Context, receive
return nil, fmt.Errorf("receiverWalletID is required")
}

const query = `
query := fmt.Sprintf(`
SELECT
*
%s
FROM
circle_recipients c
WHERE
c.receiver_wallet_id = $1
`
`, circleRecipientFields)

var circleRecipient CircleRecipient
err := m.dbConnectionPool.GetContext(ctx, &circleRecipient, query, receiverWalletID)
Expand Down
10 changes: 4 additions & 6 deletions internal/data/circle_recipient_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (

"github.com/stellar/stellar-disbursement-platform-backend/db"
"github.com/stellar/stellar-disbursement-platform-backend/db/dbtest"
"github.com/stellar/stellar-disbursement-platform-backend/internal/utils"
)

func Test_CircleRecipientModel_Insert(t *testing.T) {
Expand Down Expand Up @@ -46,7 +45,7 @@ func Test_CircleRecipientModel_Insert(t *testing.T) {
assert.NotEmpty(t, circleRecipient.UpdatedAt)
assert.NotEmpty(t, circleRecipient.CreatedAt)
assert.Empty(t, circleRecipient.SyncAttempts)
assert.Nil(t, circleRecipient.LastSyncAttemptAt)
assert.Empty(t, circleRecipient.LastSyncAttemptAt)
assert.NoError(t, uuid.Validate(circleRecipient.IdempotencyKey), "idempotency key should be a valid UUID")
})

Expand Down Expand Up @@ -75,14 +74,13 @@ func Test_CircleRecipientModel_Update(t *testing.T) {
receiver := CreateReceiverFixture(t, ctx, dbConnectionPool, &Receiver{})
m := CircleRecipientModel{dbConnectionPool: dbConnectionPool}

synchedAt := time.Now()
updateRequest := CircleRecipientUpdate{
IdempotencyKey: "new-idempotency-key",
CircleRecipientID: utils.StringPtr("circle-recipient-id"),
Status: utils.Ptr(CircleRecipientStatusActive),
CircleRecipientID: "circle-recipient-id",
Status: CircleRecipientStatusActive,
ResponseBody: []byte(`{"foo":"bar"}`),
SyncAttempts: 1,
LastSyncAttemptAt: &synchedAt,
LastSyncAttemptAt: time.Now(),
}

t.Run("return an error if the receiverWalletID is empty", func(t *testing.T) {
Expand Down
9 changes: 4 additions & 5 deletions internal/data/fixtures.go
Original file line number Diff line number Diff line change
Expand Up @@ -463,19 +463,18 @@ func CreateCircleRecipientFixture(t *testing.T, ctx context.Context, sqlExec db.
VALUES
($1, $2, $3, $4, $5, $6, $7, $8)
RETURNING
*
`
` + circleRecipientFields

var circleRecipient CircleRecipient
err := sqlExec.GetContext(ctx, &circleRecipient, query,
insert.ReceiverWalletID,
insert.IdempotencyKey,
insert.CircleRecipientID,
insert.Status,
utils.SQLNullString(insert.CircleRecipientID),
utils.SQLNullString(string(insert.Status)),
insert.CreatedAt,
insert.UpdatedAt,
insert.SyncAttempts,
insert.LastSyncAttemptAt,
utils.SQLNullTime(insert.LastSyncAttemptAt),
)
require.NoError(t, err)

Expand Down
7 changes: 3 additions & 4 deletions internal/services/payment_to_submitter_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,10 @@ func Test_PaymentToSubmitterService_SendPaymentsMethods(t *testing.T) {

receiverRegistered := data.CreateReceiverFixture(t, ctx, dbConnectionPool, &data.Receiver{})
rwRegistered := data.CreateReceiverWalletFixture(t, ctx, dbConnectionPool, receiverRegistered.ID, wallet.ID, data.RegisteredReceiversWalletStatus)
recipientActiveStatus := data.CircleRecipientStatusActive
cRecipient := data.CreateCircleRecipientFixture(t, ctx, dbConnectionPool, data.CircleRecipient{
ReceiverWalletID: rwRegistered.ID,
Status: &recipientActiveStatus,
CircleRecipientID: &circleRecipientID,
Status: data.CircleRecipientStatusActive,
CircleRecipientID: circleRecipientID,
})
paymentRegistered := data.CreatePaymentFixture(t, ctx, dbConnectionPool, models.Payment, &data.Payment{
ReceiverWallet: rwRegistered,
Expand All @@ -172,7 +171,7 @@ func Test_PaymentToSubmitterService_SendPaymentsMethods(t *testing.T) {
if tc.distributionAccount.IsCircle() {
wantPaymentReques := circle.PaymentRequest{
SourceWalletID: tc.distributionAccount.CircleWalletID,
RecipientID: *cRecipient.CircleRecipientID,
RecipientID: cRecipient.CircleRecipientID,
Amount: paymentRegistered.Amount,
StellarAssetCode: paymentRegistered.Asset.Code,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func (c *CirclePaymentDispatcher) sendPaymentsToCircle(ctx context.Context, sdpD
// 2. Submit the payment to Circle
payout, err := c.circleService.SendPayment(ctx, circle.PaymentRequest{
SourceWalletID: circleWalletID,
RecipientID: *recipient.CircleRecipientID,
RecipientID: recipient.CircleRecipientID,
Amount: payment.Amount,
StellarAssetCode: payment.Asset.Code,
IdempotencyKey: transferRequest.IdempotencyKey,
Expand Down Expand Up @@ -167,7 +167,7 @@ func (c *CirclePaymentDispatcher) ensureRecipientIsReady(ctx context.Context, re
}

// SUCCESS
if dataRecipient != nil && dataRecipient.Status != nil && *dataRecipient.Status == data.CircleRecipientStatusActive {
if dataRecipient != nil && dataRecipient.Status == data.CircleRecipientStatusActive {
return dataRecipient, nil
}

Expand All @@ -182,7 +182,7 @@ func (c *CirclePaymentDispatcher) ensureRecipientIsReady(ctx context.Context, re

// FAILED or INACTIVE -> refresh the idempotency key
shouldBumpSyncAttempts := false
if dataRecipient.Status != nil && dataRecipient.Status.IsCompleted() {
if dataRecipient.Status.IsCompleted() {
shouldBumpSyncAttempts = true // Only bump sync_attempts when trying to re-register the recipient
if dataRecipient.SyncAttempts >= maxCircleRecipientCreationAttempts {
return nil, ErrCircleRecipientCreationFailedTooManyTimes
Expand Down Expand Up @@ -226,13 +226,13 @@ func (c *CirclePaymentDispatcher) ensureRecipientIsReady(ctx context.Context, re
}
updateDataRecipient := data.CircleRecipientUpdate{
IdempotencyKey: dataRecipient.IdempotencyKey,
CircleRecipientID: &recipient.ID,
Status: &dataRecipientStatus,
CircleRecipientID: recipient.ID,
Status: dataRecipientStatus,
ResponseBody: recipientJson,
}
if shouldBumpSyncAttempts {
updateDataRecipient.SyncAttempts = dataRecipient.SyncAttempts + 1
updateDataRecipient.LastSyncAttemptAt = utils.TimePtr(time.Now())
updateDataRecipient.LastSyncAttemptAt = time.Now()
}
dataRecipient, err = c.sdpModels.CircleRecipient.Update(ctx, dataRecipient.ReceiverWalletID, updateDataRecipient)
if err != nil {
Expand All @@ -258,9 +258,9 @@ func (c *CirclePaymentDispatcher) ensureRecipientIsReadyWithRetry(ctx context.Co
}

// Check the recipient status
if *recipient.Status != data.CircleRecipientStatusActive {
if recipient.Status != data.CircleRecipientStatusActive {
// Retry if the status isn't "completed"
return fmt.Errorf("recipient not ready, status: %s", *recipient.Status)
return fmt.Errorf("recipient not ready, status: %s", recipient.Status)
}

// Successful case, no retry needed
Expand Down
Loading

0 comments on commit a15b635

Please sign in to comment.