54 lines
2.0 KiB
TypeScript
54 lines
2.0 KiB
TypeScript
import type { Prisma } from '../../../generated/prisma/client';
|
|
import type { TbankSyncAttempt } from './tbank-access.service';
|
|
|
|
const NO_UPDATED_ROWS = 0;
|
|
|
|
// Shared owners for the tbank-sync DB claim/lock protocol.
|
|
// Both helpers are CAS fences: they run inside the caller's transaction and
|
|
// keep the exact where/data shapes they replaced. Callers keep deciding
|
|
// success from the claim count exactly as before.
|
|
|
|
// Claims the active TbankSyncWork row: only the still-running attempt of a
|
|
// valid connection may transition. `data` is the state transition to apply.
|
|
export type ClaimOptions = {
|
|
// Overrides the default 'running' fence (e.g. an initiator row also
|
|
// accepts 'complete').
|
|
state: Prisma.TbankSyncWorkWhereInput['state'] | undefined;
|
|
// true drops the `connection: { invalidToken: false }` guard for fences
|
|
// that must also fire on an invalidated connection.
|
|
withoutConnectionFence: boolean | undefined;
|
|
};
|
|
export async function claimSyncWork(
|
|
tx: Prisma.TransactionClient,
|
|
attempt: TbankSyncAttempt,
|
|
data: Prisma.TbankSyncWorkUpdateManyMutationInput,
|
|
options: Partial<ClaimOptions> = {},
|
|
): Promise<number> {
|
|
const result = await tx.tbankSyncWork.updateMany({
|
|
where: {
|
|
...attempt,
|
|
state: options.state ?? 'running',
|
|
...(options.withoutConnectionFence
|
|
? {}
|
|
: { connection: { invalidToken: false } }),
|
|
},
|
|
data,
|
|
});
|
|
return result.count;
|
|
}
|
|
|
|
// Locks the connection generation before reserving or publishing work: the
|
|
// row must still be the current revision with a valid token. `extra`
|
|
// (e.g. account membership) is merged into the where clause.
|
|
export async function lockConnectionGeneration(
|
|
tx: Prisma.TransactionClient,
|
|
owner: { revision: string; userId: string },
|
|
extra: Prisma.TbankConnectionWhereInput = {},
|
|
): Promise<boolean> {
|
|
const result = await tx.tbankConnection.updateMany({
|
|
where: { ...owner, ...extra, invalidToken: false },
|
|
data: { membershipRevision: { increment: 0 } },
|
|
});
|
|
return result.count > NO_UPDATED_ROWS;
|
|
}
|