refactor(api): extract allocation assignment mutation effects

This commit is contained in:
2026-03-31 22:21:30 +02:00
parent 59690b86ac
commit dbf5401910
2 changed files with 116 additions and 78 deletions
@@ -0,0 +1,79 @@
import {
emitAllocationCreated,
emitAllocationDeleted,
emitAllocationUpdated,
} from "../sse/event-bus.js";
import {
checkBudgetThresholdsInBackground,
dispatchAllocationWebhookInBackground,
invalidateDashboardCacheInBackground,
} from "./allocation-effects.js";
type AllocationMutationDb = Parameters<typeof checkBudgetThresholdsInBackground>[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);
}
}
@@ -20,15 +20,12 @@ import { TRPCError } from "@trpc/server";
import { z } from "zod"; import { z } from "zod";
import { findUniqueOrThrow } from "../db/helpers.js"; import { findUniqueOrThrow } from "../db/helpers.js";
import { import {
emitAllocationCreated, publishAllocationCreated,
emitAllocationDeleted, publishAllocationDeleted,
emitAllocationUpdated, publishAllocationUpdated,
} from "../sse/event-bus.js"; publishBatchAllocationDeletes,
import { publishBatchAllocationStatusUpdates,
checkBudgetThresholdsInBackground, } from "./allocation-assignment-effects.js";
dispatchAllocationWebhookInBackground,
invalidateDashboardCacheInBackground,
} from "./allocation-effects.js";
import { import {
ASSIGNMENT_INCLUDE, ASSIGNMENT_INCLUDE,
toIsoDate, toIsoDate,
@@ -94,18 +91,11 @@ export const allocationAssignmentProcedures = {
}).allocations[0]!; }).allocations[0]!;
}); });
emitAllocationCreated({ publishAllocationCreated(ctx.db, {
id: allocation.id, id: allocation.id,
projectId: allocation.projectId, projectId: allocation.projectId,
resourceId: allocation.resourceId, resourceId: allocation.resourceId,
}); }, { dispatchWebhook: true });
dispatchAllocationWebhookInBackground(ctx.db, "allocation.created", {
id: allocation.id,
projectId: allocation.projectId,
resourceId: allocation.resourceId,
});
invalidateDashboardCacheInBackground();
checkBudgetThresholdsInBackground(ctx.db, allocation.projectId);
return allocation; return allocation;
}), }),
@@ -121,13 +111,11 @@ export const allocationAssignmentProcedures = {
); );
}); });
emitAllocationCreated({ publishAllocationCreated(ctx.db, {
id: assignment.id, id: assignment.id,
projectId: assignment.projectId, projectId: assignment.projectId,
resourceId: assignment.resourceId, resourceId: assignment.resourceId,
}); });
invalidateDashboardCacheInBackground();
checkBudgetThresholdsInBackground(ctx.db, assignment.projectId);
return assignment; return assignment;
}), }),
@@ -184,18 +172,11 @@ export const allocationAssignmentProcedures = {
}, },
)); ));
emitAllocationUpdated({ publishAllocationUpdated(ctx.db, {
id: updated.id, id: updated.id,
projectId: updated.projectId, projectId: updated.projectId,
resourceId: updated.resourceId, resourceId: updated.resourceId,
}); }, { dispatchWebhook: true });
dispatchAllocationWebhookInBackground(ctx.db, "allocation.updated", {
id: updated.id,
projectId: updated.projectId,
resourceId: updated.resourceId,
});
invalidateDashboardCacheInBackground();
checkBudgetThresholdsInBackground(ctx.db, updated.projectId);
return { assignment: updated, action: "reactivated" as const }; return { assignment: updated, action: "reactivated" as const };
} }
@@ -215,13 +196,11 @@ export const allocationAssignmentProcedures = {
}, },
)); ));
emitAllocationCreated({ publishAllocationCreated(ctx.db, {
id: assignment.id, id: assignment.id,
projectId: assignment.projectId, projectId: assignment.projectId,
resourceId: assignment.resourceId, resourceId: assignment.resourceId,
}); });
invalidateDashboardCacheInBackground();
checkBudgetThresholdsInBackground(ctx.db, assignment.projectId);
return { assignment, action: "created" as const }; return { assignment, action: "created" as const };
}), }),
@@ -246,19 +225,12 @@ export const allocationAssignmentProcedures = {
); );
}); });
emitAllocationUpdated({ publishAllocationUpdated(ctx.db, {
id: updated.id, id: updated.id,
projectId: updated.projectId, projectId: updated.projectId,
resourceId: updated.resourceId, resourceId: updated.resourceId,
resourceIds: [existing.resourceId, updated.resourceId], resourceIds: [existing.resourceId, updated.resourceId],
}); }, { dispatchWebhook: true });
dispatchAllocationWebhookInBackground(ctx.db, "allocation.updated", {
id: updated.id,
projectId: updated.projectId,
resourceId: updated.resourceId,
});
invalidateDashboardCacheInBackground();
checkBudgetThresholdsInBackground(ctx.db, updated.projectId);
return updated; return updated;
}), }),
@@ -296,14 +268,13 @@ export const allocationAssignmentProcedures = {
return updatedAllocation; return updatedAllocation;
}); });
emitAllocationUpdated({ publishAllocationUpdated(ctx.db, {
id: updated.id, id: updated.id,
projectId: updated.projectId, projectId: updated.projectId,
resourceId: updated.resourceId, 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; return updated;
}), }),
@@ -337,9 +308,11 @@ export const allocationAssignmentProcedures = {
}); });
}); });
emitAllocationDeleted(existing.id, existing.projectId, existing.resourceId); publishAllocationDeleted(ctx.db, {
invalidateDashboardCacheInBackground(); id: existing.id,
checkBudgetThresholdsInBackground(ctx.db, existing.projectId); projectId: existing.projectId,
resourceId: existing.resourceId,
});
return { success: true }; return { success: true };
}), }),
@@ -366,9 +339,11 @@ export const allocationAssignmentProcedures = {
}); });
}); });
emitAllocationDeleted(existing.entry.id, existing.projectId, existing.entry.resourceId); publishAllocationDeleted(ctx.db, {
invalidateDashboardCacheInBackground(); id: existing.entry.id,
checkBudgetThresholdsInBackground(ctx.db, existing.projectId); projectId: existing.projectId,
resourceId: existing.entry.resourceId,
});
return { success: true }; return { success: true };
}), }),
@@ -403,19 +378,11 @@ export const allocationAssignmentProcedures = {
}); });
}); });
for (const allocation of existing) { publishBatchAllocationDeletes(ctx.db, existing.map((allocation) => ({
emitAllocationDeleted( id: allocation.entry.id,
allocation.entry.id, projectId: allocation.projectId,
allocation.projectId, resourceId: allocation.entry.resourceId,
allocation.entry.resourceId, })));
);
}
invalidateDashboardCacheInBackground();
const affectedProjectIds = [...new Set(existing.map((allocation) => allocation.projectId))];
for (const projectId of affectedProjectIds) {
checkBudgetThresholdsInBackground(ctx.db, projectId);
}
return { count: existing.length }; return { count: existing.length };
}), }),
@@ -457,19 +424,11 @@ export const allocationAssignmentProcedures = {
}, },
}); });
for (const allocation of updated) { publishBatchAllocationStatusUpdates(ctx.db, updated.map((allocation) => ({
emitAllocationUpdated({ id: allocation.id,
id: allocation.id, projectId: allocation.projectId,
projectId: allocation.projectId, resourceId: allocation.resourceId,
resourceId: allocation.resourceId, })));
});
}
invalidateDashboardCacheInBackground();
const affectedProjectIds = [...new Set(updated.map((allocation) => allocation.projectId))];
for (const projectId of affectedProjectIds) {
checkBudgetThresholdsInBackground(ctx.db, projectId);
}
return { count: updated.length }; return { count: updated.length };
}), }),