refactor(api): extract timeline entry query support
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
import { Prisma } from "@capakraken/db";
|
||||
import {
|
||||
PROJECT_PLANNING_DEMAND_INCLUDE,
|
||||
TIMELINE_ASSIGNMENT_INCLUDE,
|
||||
} from "./project-planning-read-model.js";
|
||||
import type { TimelineEntriesDbClient, TimelineEntriesFilters } from "./timeline-read-shared.js";
|
||||
|
||||
export async function resolveTimelineEntryResourceIds(
|
||||
db: TimelineEntriesDbClient,
|
||||
input: Pick<TimelineEntriesFilters, "resourceIds" | "chapters" | "eids" | "countryCodes">,
|
||||
): Promise<string[] | undefined> {
|
||||
if (input.resourceIds && input.resourceIds.length > 0) {
|
||||
return input.resourceIds;
|
||||
}
|
||||
|
||||
const hasChapters = !!input.chapters?.length;
|
||||
const hasEids = !!input.eids?.length;
|
||||
const hasCountry = !!input.countryCodes?.length;
|
||||
if (!hasChapters && !hasEids && !hasCountry) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const andConditions: Record<string, unknown>[] = [];
|
||||
if (hasChapters) {
|
||||
andConditions.push({ chapter: { in: input.chapters } });
|
||||
}
|
||||
if (hasEids) {
|
||||
andConditions.push({ eid: { in: input.eids } });
|
||||
}
|
||||
if (hasCountry) {
|
||||
andConditions.push({ country: { code: { in: input.countryCodes } } });
|
||||
}
|
||||
|
||||
const matching = await db.resource.findMany({
|
||||
where: (andConditions.length === 1 ? andConditions[0]! : { AND: andConditions }) as Prisma.ResourceWhereInput,
|
||||
select: { id: true },
|
||||
});
|
||||
|
||||
return matching.map((resource) => resource.id);
|
||||
}
|
||||
|
||||
export async function resolveTimelineEntryProjectIds(
|
||||
db: TimelineEntriesDbClient,
|
||||
input: Pick<TimelineEntriesFilters, "projectIds" | "clientIds">,
|
||||
): Promise<string[] | undefined> {
|
||||
if (!input.clientIds?.length) {
|
||||
return input.projectIds;
|
||||
}
|
||||
|
||||
const matchingProjects = await db.project.findMany({
|
||||
where: { clientId: { in: input.clientIds } },
|
||||
select: { id: true },
|
||||
});
|
||||
const clientProjectIds = matchingProjects.map((project) => project.id);
|
||||
|
||||
if (!input.projectIds?.length) {
|
||||
return clientProjectIds;
|
||||
}
|
||||
|
||||
const allowedIds = new Set(clientProjectIds);
|
||||
return input.projectIds.filter((projectId) => allowedIds.has(projectId));
|
||||
}
|
||||
|
||||
export async function loadTimelineEntryRecords(
|
||||
db: TimelineEntriesDbClient,
|
||||
input: TimelineEntriesFilters,
|
||||
) {
|
||||
const effectiveResourceIds = await resolveTimelineEntryResourceIds(db, input);
|
||||
const effectiveProjectIds = await resolveTimelineEntryProjectIds(db, input);
|
||||
const excludeDemands = effectiveResourceIds !== undefined;
|
||||
|
||||
const [demandRequirements, assignments] = await Promise.all([
|
||||
excludeDemands
|
||||
? Promise.resolve([])
|
||||
: db.demandRequirement.findMany({
|
||||
where: {
|
||||
status: { not: "CANCELLED" },
|
||||
startDate: { lte: input.endDate },
|
||||
endDate: { gte: input.startDate },
|
||||
...(effectiveProjectIds ? { projectId: { in: effectiveProjectIds } } : {}),
|
||||
},
|
||||
include: PROJECT_PLANNING_DEMAND_INCLUDE,
|
||||
orderBy: [{ startDate: "asc" }, { projectId: "asc" }],
|
||||
}),
|
||||
db.assignment.findMany({
|
||||
where: {
|
||||
status: { not: "CANCELLED" },
|
||||
startDate: { lte: input.endDate },
|
||||
endDate: { gte: input.startDate },
|
||||
...(effectiveResourceIds ? { resourceId: { in: effectiveResourceIds } } : {}),
|
||||
...(effectiveProjectIds ? { projectId: { in: effectiveProjectIds } } : {}),
|
||||
},
|
||||
include: TIMELINE_ASSIGNMENT_INCLUDE,
|
||||
orderBy: [{ startDate: "asc" }, { resourceId: "asc" }],
|
||||
}),
|
||||
]);
|
||||
|
||||
return { demandRequirements, assignments };
|
||||
}
|
||||
Reference in New Issue
Block a user