215 lines
5.5 KiB
Go
215 lines
5.5 KiB
Go
// Code generated by sqlc. DO NOT EDIT.
|
|
// versions:
|
|
// sqlc v1.31.1
|
|
// source: idempotency.sql
|
|
|
|
package pgstore
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
)
|
|
|
|
const completeIdempotencyKey = `-- name: CompleteIdempotencyKey :execrows
|
|
update idempotency_keys
|
|
set status = $1, location = $2, body = $3,
|
|
finished_at = $4, content_sha256 = $5
|
|
where user_id = $6 and method = $7
|
|
and path_sha256 = $8 and key = $9
|
|
and claim_token = $10 and finished_at is null
|
|
`
|
|
|
|
type CompleteIdempotencyKeyParams struct {
|
|
Status *int32
|
|
Location string
|
|
Body []byte
|
|
FinishedAt *time.Time
|
|
ContentSha256 []byte
|
|
UserID string
|
|
Method string
|
|
PathSha256 []byte
|
|
Key string
|
|
ClaimToken string
|
|
}
|
|
|
|
// Only the attempt that still HOLDS the claim may write the receipt.
|
|
func (q *Queries) CompleteIdempotencyKey(ctx context.Context, arg CompleteIdempotencyKeyParams) (int64, error) {
|
|
result, err := q.db.Exec(ctx, completeIdempotencyKey,
|
|
arg.Status,
|
|
arg.Location,
|
|
arg.Body,
|
|
arg.FinishedAt,
|
|
arg.ContentSha256,
|
|
arg.UserID,
|
|
arg.Method,
|
|
arg.PathSha256,
|
|
arg.Key,
|
|
arg.ClaimToken,
|
|
)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return result.RowsAffected(), nil
|
|
}
|
|
|
|
const insertIdempotencyClaim = `-- name: InsertIdempotencyClaim :execrows
|
|
insert into idempotency_keys (user_id, method, path, path_sha256, key, request_sha256, claimed_at, claim_token)
|
|
values ($1, $2, $3, $4, $5,
|
|
$6, $7, $8)
|
|
on conflict (user_id, method, path_sha256, key) do nothing
|
|
`
|
|
|
|
type InsertIdempotencyClaimParams struct {
|
|
UserID string
|
|
Method string
|
|
Path string
|
|
PathSha256 []byte
|
|
Key string
|
|
RequestSha256 []byte
|
|
ClaimedAt time.Time
|
|
ClaimToken string
|
|
}
|
|
|
|
// `do nothing` plus a re-read decides between two simultaneous first attempts; a bare insert made
|
|
// the loser raise a unique violation — a 500 on the one case this header exists for.
|
|
func (q *Queries) InsertIdempotencyClaim(ctx context.Context, arg InsertIdempotencyClaimParams) (int64, error) {
|
|
result, err := q.db.Exec(ctx, insertIdempotencyClaim,
|
|
arg.UserID,
|
|
arg.Method,
|
|
arg.Path,
|
|
arg.PathSha256,
|
|
arg.Key,
|
|
arg.RequestSha256,
|
|
arg.ClaimedAt,
|
|
arg.ClaimToken,
|
|
)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return result.RowsAffected(), nil
|
|
}
|
|
|
|
const readIdempotencyKey = `-- name: ReadIdempotencyKey :one
|
|
|
|
select request_sha256, status, location, body, claimed_at, finished_at, content_sha256
|
|
from idempotency_keys
|
|
where user_id = $1 and method = $2
|
|
and path_sha256 = $3 and key = $4 for update
|
|
`
|
|
|
|
type ReadIdempotencyKeyParams struct {
|
|
UserID string
|
|
Method string
|
|
PathSha256 []byte
|
|
Key string
|
|
}
|
|
|
|
type ReadIdempotencyKeyRow struct {
|
|
RequestSha256 []byte
|
|
Status *int32
|
|
Location string
|
|
Body []byte
|
|
ClaimedAt time.Time
|
|
FinishedAt *time.Time
|
|
ContentSha256 []byte
|
|
}
|
|
|
|
// The storage half of `Idempotency-Key`.
|
|
// `for update` on a MISSING row locks nothing, which is why the caller has an insert-then-re-read
|
|
// path behind this and not a bare insert.
|
|
func (q *Queries) ReadIdempotencyKey(ctx context.Context, arg ReadIdempotencyKeyParams) (ReadIdempotencyKeyRow, error) {
|
|
row := q.db.QueryRow(ctx, readIdempotencyKey,
|
|
arg.UserID,
|
|
arg.Method,
|
|
arg.PathSha256,
|
|
arg.Key,
|
|
)
|
|
var i ReadIdempotencyKeyRow
|
|
err := row.Scan(
|
|
&i.RequestSha256,
|
|
&i.Status,
|
|
&i.Location,
|
|
&i.Body,
|
|
&i.ClaimedAt,
|
|
&i.FinishedAt,
|
|
&i.ContentSha256,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const releaseIdempotencyKey = `-- name: ReleaseIdempotencyKey :execrows
|
|
delete from idempotency_keys
|
|
where user_id = $1 and method = $2
|
|
and path_sha256 = $3 and key = $4
|
|
and claim_token = $5 and finished_at is null
|
|
`
|
|
|
|
type ReleaseIdempotencyKeyParams struct {
|
|
UserID string
|
|
Method string
|
|
PathSha256 []byte
|
|
Key string
|
|
ClaimToken string
|
|
}
|
|
|
|
// On the token for the same reason as the completion: a slow attempt that finally failed used to
|
|
// delete the row of the successor which had taken the key over and was already doing the work.
|
|
func (q *Queries) ReleaseIdempotencyKey(ctx context.Context, arg ReleaseIdempotencyKeyParams) (int64, error) {
|
|
result, err := q.db.Exec(ctx, releaseIdempotencyKey,
|
|
arg.UserID,
|
|
arg.Method,
|
|
arg.PathSha256,
|
|
arg.Key,
|
|
arg.ClaimToken,
|
|
)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return result.RowsAffected(), nil
|
|
}
|
|
|
|
const retakeIdempotencyClaim = `-- name: RetakeIdempotencyClaim :exec
|
|
update idempotency_keys
|
|
set claimed_at = $1, request_sha256 = $2,
|
|
claim_token = $3
|
|
where user_id = $4 and method = $5
|
|
and path_sha256 = $6 and key = $7
|
|
`
|
|
|
|
type RetakeIdempotencyClaimParams struct {
|
|
ClaimedAt time.Time
|
|
RequestSha256 []byte
|
|
ClaimToken string
|
|
UserID string
|
|
Method string
|
|
PathSha256 []byte
|
|
Key string
|
|
}
|
|
|
|
// The NEW token is what stops the old attempt — which may still be alive and merely slow — from
|
|
// completing or releasing what is no longer its claim.
|
|
func (q *Queries) RetakeIdempotencyClaim(ctx context.Context, arg RetakeIdempotencyClaimParams) error {
|
|
_, err := q.db.Exec(ctx, retakeIdempotencyClaim,
|
|
arg.ClaimedAt,
|
|
arg.RequestSha256,
|
|
arg.ClaimToken,
|
|
arg.UserID,
|
|
arg.Method,
|
|
arg.PathSha256,
|
|
arg.Key,
|
|
)
|
|
return err
|
|
}
|
|
|
|
const sweepIdempotency = `-- name: SweepIdempotency :execrows
|
|
delete from idempotency_keys where claimed_at < $1
|
|
`
|
|
|
|
// Forgets records past the window the contract promises ("at least 24 hours").
|
|
func (q *Queries) SweepIdempotency(ctx context.Context, before time.Time) (int64, error) {
|
|
result, err := q.db.Exec(ctx, sweepIdempotency, before)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return result.RowsAffected(), nil
|
|
}
|