This commit is contained in:
@@ -81,6 +81,14 @@ func (e *Executor) Execute(
|
||||
request Request,
|
||||
operation func(context.Context, pgx.Tx) (Result, error),
|
||||
) (Result, error) {
|
||||
return e.ExecuteGuarded(ctx, request, nil, operation)
|
||||
}
|
||||
|
||||
// Guard executes in the operation transaction before mutation or replay. On
|
||||
// replay it also receives the stored resource for current authorization checks.
|
||||
type Guard func(context.Context, pgx.Tx, *Result) error
|
||||
|
||||
func (e *Executor) ExecuteGuarded(ctx context.Context, request Request, guard Guard, operation func(context.Context, pgx.Tx) (Result, error)) (Result, error) {
|
||||
if err := validateRequest(request); err != nil {
|
||||
return Result{}, err
|
||||
}
|
||||
@@ -89,6 +97,11 @@ func (e *Executor) Execute(
|
||||
return Result{}, fmt.Errorf("begin idempotency transaction: %w", err)
|
||||
}
|
||||
defer func() { _ = tx.Rollback(context.Background()) }()
|
||||
if guard != nil {
|
||||
if err := guard(ctx, tx, nil); err != nil {
|
||||
return Result{}, err
|
||||
}
|
||||
}
|
||||
|
||||
tag, err := tx.Exec(ctx, `
|
||||
INSERT INTO idempotency_record (
|
||||
@@ -103,7 +116,7 @@ func (e *Executor) Execute(
|
||||
return Result{}, fmt.Errorf("claim idempotency key: %w", err)
|
||||
}
|
||||
if tag.RowsAffected() == 0 {
|
||||
return e.replay(ctx, tx, request)
|
||||
return e.replay(ctx, tx, request, guard)
|
||||
}
|
||||
|
||||
result, err := operation(ctx, tx)
|
||||
@@ -129,7 +142,7 @@ func (e *Executor) Execute(
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (e *Executor) replay(ctx context.Context, tx pgx.Tx, request Request) (Result, error) {
|
||||
func (e *Executor) replay(ctx context.Context, tx pgx.Tx, request Request, guard Guard) (Result, error) {
|
||||
var storedHash, state string
|
||||
var result Result
|
||||
err := tx.QueryRow(ctx, `
|
||||
@@ -148,6 +161,11 @@ func (e *Executor) replay(ctx context.Context, tx pgx.Tx, request Request) (Resu
|
||||
return Result{}, ErrInProgress
|
||||
}
|
||||
result.Replayed = true
|
||||
if guard != nil {
|
||||
if err := guard(ctx, tx, &result); err != nil {
|
||||
return Result{}, err
|
||||
}
|
||||
}
|
||||
if err := tx.Commit(ctx); err != nil {
|
||||
return Result{}, fmt.Errorf("commit idempotency replay: %w", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user