From dbf54019103259e94ce9bab93b148dcb50ece694 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hartmut=20N=C3=B6renberg?= Date: Tue, 31 Mar 2026 22:21:30 +0200 Subject: [PATCH] refactor(api): extract allocation assignment mutation effects --- .../router/allocation-assignment-effects.ts | 79 ++++++++++++ .../allocation-assignment-procedures.ts | 115 ++++++------------ 2 files changed, 116 insertions(+), 78 deletions(-) create mode 100644 packages/api/src/router/allocation-assignment-effects.ts diff --git a/packages/api/src/router/allocation-assignment-effects.ts b/packages/api/src/router/allocation-assignment-effects.ts new file mode 100644 index 0000000..a2d75ea --- /dev/null +++ b/packages/api/src/router/allocation-assignment-effects.ts @@ -0,0 +1,79 @@ +import { + emitAllocationCreated, + emitAllocationDeleted, + emitAllocationUpdated, +} from "../sse/event-bus.js"; +import { + checkBudgetThresholdsInBackground, + dispatchAllocationWebhookInBackground, + invalidateDashboardCacheInBackground, +} from "./allocation-effects.js"; + +type AllocationMutationDb = Parameters[0]; + +type AllocationMutationPayload = { + id: string; + projectId: string; + resourceId: string | null; +}; + +export function publishAllocationCreated( + db: AllocationMutationDb, + payload: AllocationMutationPayload, + options?: { dispatchWebhook?: boolean }, +) { + emitAllocationCreated(payload); + if (options?.dispatchWebhook) { + dispatchAllocationWebhookInBackground(db, "allocation.created", payload); + } + invalidateDashboardCacheInBackground(); + checkBudgetThresholdsInBackground(db, payload.projectId); +} + +export function publishAllocationUpdated( + db: AllocationMutationDb, + payload: AllocationMutationPayload & { resourceIds?: string[] }, + options?: { dispatchWebhook?: boolean }, +) { + emitAllocationUpdated(payload); + if (options?.dispatchWebhook) { + dispatchAllocationWebhookInBackground(db, "allocation.updated", payload); + } + invalidateDashboardCacheInBackground(); + checkBudgetThresholdsInBackground(db, payload.projectId); +} + +export function publishAllocationDeleted( + db: AllocationMutationDb, + payload: AllocationMutationPayload, +) { + emitAllocationDeleted(payload.id, payload.projectId, payload.resourceId); + invalidateDashboardCacheInBackground(); + checkBudgetThresholdsInBackground(db, payload.projectId); +} + +export function publishBatchAllocationDeletes( + db: AllocationMutationDb, + payloads: AllocationMutationPayload[], +) { + for (const payload of payloads) { + emitAllocationDeleted(payload.id, payload.projectId, payload.resourceId); + } + invalidateDashboardCacheInBackground(); + for (const projectId of new Set(payloads.map((payload) => payload.projectId))) { + checkBudgetThresholdsInBackground(db, projectId); + } +} + +export function publishBatchAllocationStatusUpdates( + db: AllocationMutationDb, + payloads: AllocationMutationPayload[], +) { + for (const payload of payloads) { + emitAllocationUpdated(payload); + } + invalidateDashboardCacheInBackground(); + for (const projectId of new Set(payloads.map((payload) => payload.projectId))) { + checkBudgetThresholdsInBackground(db, projectId); + } +} diff --git a/packages/api/src/router/allocation-assignment-procedures.ts b/packages/api/src/router/allocation-assignment-procedures.ts index 50df9a2..a19e592 100644 --- a/packages/api/src/router/allocation-assignment-procedures.ts +++ b/packages/api/src/router/allocation-assignment-procedures.ts @@ -20,15 +20,12 @@ import { TRPCError } from "@trpc/server"; import { z } from "zod"; import { findUniqueOrThrow } from "../db/helpers.js"; import { - emitAllocationCreated, - emitAllocationDeleted, - emitAllocationUpdated, -} from "../sse/event-bus.js"; -import { - checkBudgetThresholdsInBackground, - dispatchAllocationWebhookInBackground, - invalidateDashboardCacheInBackground, -} from "./allocation-effects.js"; + publishAllocationCreated, + publishAllocationDeleted, + publishAllocationUpdated, + publishBatchAllocationDeletes, + publishBatchAllocationStatusUpdates, +} from "./allocation-assignment-effects.js"; import { ASSIGNMENT_INCLUDE, toIsoDate, @@ -94,18 +91,11 @@ export const allocationAssignmentProcedures = { }).allocations[0]!; }); - emitAllocationCreated({ + publishAllocationCreated(ctx.db, { id: allocation.id, projectId: allocation.projectId, resourceId: allocation.resourceId, - }); - dispatchAllocationWebhookInBackground(ctx.db, "allocation.created", { - id: allocation.id, - projectId: allocation.projectId, - resourceId: allocation.resourceId, - }); - invalidateDashboardCacheInBackground(); - checkBudgetThresholdsInBackground(ctx.db, allocation.projectId); + }, { dispatchWebhook: true }); return allocation; }), @@ -121,13 +111,11 @@ export const allocationAssignmentProcedures = { ); }); - emitAllocationCreated({ + publishAllocationCreated(ctx.db, { id: assignment.id, projectId: assignment.projectId, resourceId: assignment.resourceId, }); - invalidateDashboardCacheInBackground(); - checkBudgetThresholdsInBackground(ctx.db, assignment.projectId); return assignment; }), @@ -184,18 +172,11 @@ export const allocationAssignmentProcedures = { }, )); - emitAllocationUpdated({ + publishAllocationUpdated(ctx.db, { id: updated.id, projectId: updated.projectId, resourceId: updated.resourceId, - }); - dispatchAllocationWebhookInBackground(ctx.db, "allocation.updated", { - id: updated.id, - projectId: updated.projectId, - resourceId: updated.resourceId, - }); - invalidateDashboardCacheInBackground(); - checkBudgetThresholdsInBackground(ctx.db, updated.projectId); + }, { dispatchWebhook: true }); return { assignment: updated, action: "reactivated" as const }; } @@ -215,13 +196,11 @@ export const allocationAssignmentProcedures = { }, )); - emitAllocationCreated({ + publishAllocationCreated(ctx.db, { id: assignment.id, projectId: assignment.projectId, resourceId: assignment.resourceId, }); - invalidateDashboardCacheInBackground(); - checkBudgetThresholdsInBackground(ctx.db, assignment.projectId); return { assignment, action: "created" as const }; }), @@ -246,19 +225,12 @@ export const allocationAssignmentProcedures = { ); }); - emitAllocationUpdated({ + publishAllocationUpdated(ctx.db, { id: updated.id, projectId: updated.projectId, resourceId: updated.resourceId, resourceIds: [existing.resourceId, updated.resourceId], - }); - dispatchAllocationWebhookInBackground(ctx.db, "allocation.updated", { - id: updated.id, - projectId: updated.projectId, - resourceId: updated.resourceId, - }); - invalidateDashboardCacheInBackground(); - checkBudgetThresholdsInBackground(ctx.db, updated.projectId); + }, { dispatchWebhook: true }); return updated; }), @@ -296,14 +268,13 @@ export const allocationAssignmentProcedures = { return updatedAllocation; }); - emitAllocationUpdated({ + publishAllocationUpdated(ctx.db, { id: updated.id, projectId: updated.projectId, resourceId: updated.resourceId, - resourceIds: [existing.entry.resourceId, updated.resourceId], + resourceIds: [existing.entry.resourceId, updated.resourceId] + .filter((resourceId): resourceId is string => Boolean(resourceId)), }); - invalidateDashboardCacheInBackground(); - checkBudgetThresholdsInBackground(ctx.db, updated.projectId); return updated; }), @@ -337,9 +308,11 @@ export const allocationAssignmentProcedures = { }); }); - emitAllocationDeleted(existing.id, existing.projectId, existing.resourceId); - invalidateDashboardCacheInBackground(); - checkBudgetThresholdsInBackground(ctx.db, existing.projectId); + publishAllocationDeleted(ctx.db, { + id: existing.id, + projectId: existing.projectId, + resourceId: existing.resourceId, + }); return { success: true }; }), @@ -366,9 +339,11 @@ export const allocationAssignmentProcedures = { }); }); - emitAllocationDeleted(existing.entry.id, existing.projectId, existing.entry.resourceId); - invalidateDashboardCacheInBackground(); - checkBudgetThresholdsInBackground(ctx.db, existing.projectId); + publishAllocationDeleted(ctx.db, { + id: existing.entry.id, + projectId: existing.projectId, + resourceId: existing.entry.resourceId, + }); return { success: true }; }), @@ -403,19 +378,11 @@ export const allocationAssignmentProcedures = { }); }); - for (const allocation of existing) { - emitAllocationDeleted( - allocation.entry.id, - allocation.projectId, - allocation.entry.resourceId, - ); - } - invalidateDashboardCacheInBackground(); - - const affectedProjectIds = [...new Set(existing.map((allocation) => allocation.projectId))]; - for (const projectId of affectedProjectIds) { - checkBudgetThresholdsInBackground(ctx.db, projectId); - } + publishBatchAllocationDeletes(ctx.db, existing.map((allocation) => ({ + id: allocation.entry.id, + projectId: allocation.projectId, + resourceId: allocation.entry.resourceId, + }))); return { count: existing.length }; }), @@ -457,19 +424,11 @@ export const allocationAssignmentProcedures = { }, }); - for (const allocation of updated) { - emitAllocationUpdated({ - id: allocation.id, - projectId: allocation.projectId, - resourceId: allocation.resourceId, - }); - } - invalidateDashboardCacheInBackground(); - - const affectedProjectIds = [...new Set(updated.map((allocation) => allocation.projectId))]; - for (const projectId of affectedProjectIds) { - checkBudgetThresholdsInBackground(ctx.db, projectId); - } + publishBatchAllocationStatusUpdates(ctx.db, updated.map((allocation) => ({ + id: allocation.id, + projectId: allocation.projectId, + resourceId: allocation.resourceId, + }))); return { count: updated.length }; }),