perf(api): eliminate N+1 queries, add query guards and missing indexes
- Notification fan-out: replace sequential for loops with Promise.all (allocation-effects, notification-broadcast, create-notification) - Public holiday batch: group resources by location combo, resolve holidays once per group, replace per-holiday delete/findFirst/create with 3 batched queries (~18K → ~5 queries) - Add take guards to unbounded findMany calls (resource-analytics: 5000, resource-marketplace: 2000, resource-capacity: 1000, chargeability-report: 2000) - auto-staffing: add select with only needed fields + take: 5000 - schema.prisma: add 5 missing indexes (ManagementLevel.groupId, Blueprint.isActive/target, Comment.parentId, Vacation.requestedById, Resource.managementLevelGroupId) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -54,6 +54,22 @@ type DbClient = Parameters<typeof listAssignmentBookings>[0] & {
|
||||
resource: {
|
||||
findMany: (args: {
|
||||
where: { isActive: true };
|
||||
select?: {
|
||||
id?: true;
|
||||
displayName?: true;
|
||||
eid?: true;
|
||||
skills?: true;
|
||||
lcrCents?: true;
|
||||
chargeabilityTarget?: true;
|
||||
valueScore?: true;
|
||||
availability?: true;
|
||||
countryId?: true;
|
||||
federalState?: true;
|
||||
metroCityId?: true;
|
||||
country?: { select: { code: true } };
|
||||
metroCity?: { select: { name: true } };
|
||||
};
|
||||
take?: number;
|
||||
}) => Promise<Array<{
|
||||
id: string;
|
||||
displayName: string;
|
||||
@@ -155,6 +171,22 @@ export async function generateAutoSuggestions(
|
||||
// 4. Fetch all active resources and their current bookings
|
||||
const resources = await db.resource.findMany({
|
||||
where: { isActive: true },
|
||||
select: {
|
||||
id: true,
|
||||
displayName: true,
|
||||
eid: true,
|
||||
skills: true,
|
||||
lcrCents: true,
|
||||
chargeabilityTarget: true,
|
||||
valueScore: true,
|
||||
availability: true,
|
||||
countryId: true,
|
||||
federalState: true,
|
||||
metroCityId: true,
|
||||
country: { select: { code: true } },
|
||||
metroCity: { select: { name: true } },
|
||||
},
|
||||
take: 5000,
|
||||
});
|
||||
|
||||
if (resources.length === 0) return;
|
||||
|
||||
@@ -93,10 +93,7 @@ export async function createNotificationsForUsers(
|
||||
params: Omit<CreateNotificationParams, "userId"> & { userIds: string[] },
|
||||
): Promise<number> {
|
||||
const { userIds, ...rest } = params;
|
||||
let count = 0;
|
||||
for (const userId of userIds) {
|
||||
await createNotification({ ...rest, userId });
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
if (userIds.length === 0) return 0;
|
||||
await Promise.all(userIds.map((userId) => createNotification({ ...rest, userId })));
|
||||
return userIds.length;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user