import { sql } from "drizzle-orm"; import type { PayloadRequest } from "payload"; /** * Acquires a Postgres transaction-scoped advisory lock so that two * concurrent requests confirming a booking for the same day can't both pass * the "is this slot free?" check before either has committed (Payload's * default transaction isolation is READ COMMITTED, which alone would allow * that race). The lock is automatically released when the transaction ends. * * Must be called from inside a Payload hook/operation that already has an * active `req.transactionID` (true for collection create/update by default). */ export async function acquireBookingDayLock(req: PayloadRequest, dateKey: string): Promise { const txID = req.transactionID ? String(await req.transactionID) : undefined; if (!txID) return; // No active transaction — nothing to lock against. const adapter = req.payload.db as unknown as { sessions?: Record Promise } }>; drizzle: { execute: (query: unknown) => Promise }; }; const tx = adapter.sessions?.[txID]?.db ?? adapter.drizzle; await tx.execute(sql`SELECT pg_advisory_xact_lock(hashtext(${dateKey}))`); }