fix(decisions): wrap mutations in db.transaction() for audit atomicity
This commit is contained in:
parent
880c2a7018
commit
3b1b14e380
1 changed files with 41 additions and 37 deletions
|
|
@ -26,49 +26,53 @@ export class DecisionsService {
|
||||||
}
|
}
|
||||||
|
|
||||||
async create(session: AuthenticatedSession, dto: CreateDecisionDto) {
|
async create(session: AuthenticatedSession, dto: CreateDecisionDto) {
|
||||||
const [row] = await db
|
return db.transaction(async (tx) => {
|
||||||
.insert(decisions)
|
const [row] = await tx
|
||||||
.values({
|
.insert(decisions)
|
||||||
|
.values({
|
||||||
|
tenantId: session.tenantId,
|
||||||
|
ownerUserId: session.userId,
|
||||||
|
context: dto.context,
|
||||||
|
options: (dto.options ?? []) as unknown[],
|
||||||
|
assumptions: (dto.assumptions ?? []) as unknown[],
|
||||||
|
evidence: (dto.evidence ?? []) as unknown[],
|
||||||
|
reviewDueAt: dto.reviewDueAt ? new Date(dto.reviewDueAt) : undefined,
|
||||||
|
})
|
||||||
|
.returning();
|
||||||
|
await this.audit.record(tx, {
|
||||||
tenantId: session.tenantId,
|
tenantId: session.tenantId,
|
||||||
ownerUserId: session.userId,
|
actorId: session.userId,
|
||||||
context: dto.context,
|
action: 'decision.created',
|
||||||
options: (dto.options ?? []) as unknown[],
|
resource: `decision:${row.id}`,
|
||||||
assumptions: (dto.assumptions ?? []) as unknown[],
|
});
|
||||||
evidence: (dto.evidence ?? []) as unknown[],
|
return row;
|
||||||
reviewDueAt: dto.reviewDueAt ? new Date(dto.reviewDueAt) : undefined,
|
|
||||||
})
|
|
||||||
.returning();
|
|
||||||
await this.audit.record(null, {
|
|
||||||
tenantId: session.tenantId,
|
|
||||||
actorId: session.userId,
|
|
||||||
action: 'decision.created',
|
|
||||||
resource: `decision:${row.id}`,
|
|
||||||
});
|
});
|
||||||
return row;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async update(session: AuthenticatedSession, id: string, dto: UpdateDecisionDto) {
|
async update(session: AuthenticatedSession, id: string, dto: UpdateDecisionDto) {
|
||||||
await this.getById(session, id);
|
await this.getById(session, id);
|
||||||
const [row] = await db
|
return db.transaction(async (tx) => {
|
||||||
.update(decisions)
|
const [row] = await tx
|
||||||
.set({
|
.update(decisions)
|
||||||
...(dto.context !== undefined ? { context: dto.context } : {}),
|
.set({
|
||||||
...(dto.options !== undefined ? { options: dto.options as unknown[] } : {}),
|
...(dto.context !== undefined ? { context: dto.context } : {}),
|
||||||
...(dto.assumptions !== undefined ? { assumptions: dto.assumptions as unknown[] } : {}),
|
...(dto.options !== undefined ? { options: dto.options as unknown[] } : {}),
|
||||||
...(dto.evidence !== undefined ? { evidence: dto.evidence as unknown[] } : {}),
|
...(dto.assumptions !== undefined ? { assumptions: dto.assumptions as unknown[] } : {}),
|
||||||
...(dto.selectedOption !== undefined ? { selectedOption: dto.selectedOption } : {}),
|
...(dto.evidence !== undefined ? { evidence: dto.evidence as unknown[] } : {}),
|
||||||
...(dto.outcomeReview !== undefined ? { outcomeReview: dto.outcomeReview } : {}),
|
...(dto.selectedOption !== undefined ? { selectedOption: dto.selectedOption } : {}),
|
||||||
...(dto.reviewDueAt !== undefined ? { reviewDueAt: new Date(dto.reviewDueAt) } : {}),
|
...(dto.outcomeReview !== undefined ? { outcomeReview: dto.outcomeReview } : {}),
|
||||||
updatedAt: new Date(),
|
...(dto.reviewDueAt !== undefined ? { reviewDueAt: new Date(dto.reviewDueAt) } : {}),
|
||||||
})
|
updatedAt: new Date(),
|
||||||
.where(and(eq(decisions.id, id), eq(decisions.tenantId, session.tenantId)))
|
})
|
||||||
.returning();
|
.where(and(eq(decisions.id, id), eq(decisions.tenantId, session.tenantId)))
|
||||||
await this.audit.record(null, {
|
.returning();
|
||||||
tenantId: session.tenantId,
|
await this.audit.record(tx, {
|
||||||
actorId: session.userId,
|
tenantId: session.tenantId,
|
||||||
action: dto.selectedOption !== undefined ? 'decision.option_selected' : 'decision.updated',
|
actorId: session.userId,
|
||||||
resource: `decision:${id}`,
|
action: dto.selectedOption !== undefined ? 'decision.option_selected' : 'decision.updated',
|
||||||
|
resource: `decision:${id}`,
|
||||||
|
});
|
||||||
|
return row;
|
||||||
});
|
});
|
||||||
return row;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue