-- The storage half of `Idempotency-Key`. -- name: ReadIdempotencyKey :one -- `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. select request_sha256, status, location, body, claimed_at, finished_at, content_sha256 from idempotency_keys where user_id = sqlc.arg(user_id) and method = sqlc.arg(method) and path_sha256 = sqlc.arg(path_sha256) and key = sqlc.arg(key) for update; -- name: InsertIdempotencyClaim :execrows -- `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. insert into idempotency_keys (user_id, method, path, path_sha256, key, request_sha256, claimed_at, claim_token) values (sqlc.arg(user_id), sqlc.arg(method), sqlc.arg(path), sqlc.arg(path_sha256), sqlc.arg(key), sqlc.arg(request_sha256), sqlc.arg(claimed_at), sqlc.arg(claim_token)) on conflict (user_id, method, path_sha256, key) do nothing; -- name: RetakeIdempotencyClaim :exec -- 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. update idempotency_keys set claimed_at = sqlc.arg(claimed_at), request_sha256 = sqlc.arg(request_sha256), claim_token = sqlc.arg(claim_token) where user_id = sqlc.arg(user_id) and method = sqlc.arg(method) and path_sha256 = sqlc.arg(path_sha256) and key = sqlc.arg(key); -- name: CompleteIdempotencyKey :execrows -- Only the attempt that still HOLDS the claim may write the receipt. update idempotency_keys set status = sqlc.arg(status), location = sqlc.arg(location), body = sqlc.arg(body), finished_at = sqlc.arg(finished_at), content_sha256 = sqlc.arg(content_sha256) where user_id = sqlc.arg(user_id) and method = sqlc.arg(method) and path_sha256 = sqlc.arg(path_sha256) and key = sqlc.arg(key) and claim_token = sqlc.arg(claim_token) and finished_at is null; -- name: ReleaseIdempotencyKey :execrows -- 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. delete from idempotency_keys where user_id = sqlc.arg(user_id) and method = sqlc.arg(method) and path_sha256 = sqlc.arg(path_sha256) and key = sqlc.arg(key) and claim_token = sqlc.arg(claim_token) and finished_at is null; -- name: SweepIdempotency :execrows -- Forgets records past the window the contract promises ("at least 24 hours"). delete from idempotency_keys where claimed_at < sqlc.arg(before);