perf(api): eliminate 3 N+1 query patterns
- timeline-holiday-load-support: deduplicate getResolvedCalendarHolidays by location key so resources sharing the same country/state/city resolve holidays once instead of per-resource - rate-card-lookup: add lookupRatesBatch that loads rate card lines once and scores locally per demand line, replacing per-line DB round-trips in estimate-demand-lines autoFillDemandLineRates - config-readmodels: include _count in utilization-category list query instead of calling getById per category for project counts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+1
-12
@@ -43,17 +43,9 @@ describe("assistant master data management and utilization read tools", () => {
|
||||
description: "Client work",
|
||||
isActive: true,
|
||||
sortOrder: 1,
|
||||
_count: { projects: 3 },
|
||||
},
|
||||
]),
|
||||
findUnique: vi.fn().mockResolvedValue({
|
||||
id: "util_billable",
|
||||
code: "BILLABLE",
|
||||
name: "Billable",
|
||||
description: "Client work",
|
||||
isActive: true,
|
||||
sortOrder: 1,
|
||||
_count: { projects: 3 },
|
||||
}),
|
||||
},
|
||||
};
|
||||
const ctx = createToolContext(db, {
|
||||
@@ -71,9 +63,6 @@ describe("assistant master data management and utilization read tools", () => {
|
||||
expect(db.utilizationCategory.findMany).toHaveBeenCalledWith({
|
||||
where: {},
|
||||
orderBy: { sortOrder: "asc" },
|
||||
});
|
||||
expect(db.utilizationCategory.findUnique).toHaveBeenCalledWith({
|
||||
where: { id: "util_billable" },
|
||||
include: { _count: { select: { projects: true } } },
|
||||
});
|
||||
|
||||
|
||||
@@ -37,11 +37,13 @@ function createUnauthenticatedContext(db: Record<string, unknown>) {
|
||||
describe("master-data router authorization", () => {
|
||||
it("requires planning read access for blueprint summaries with project counts", async () => {
|
||||
const findMany = vi.fn();
|
||||
const caller = createCallerFactory(blueprintRouter)(createProtectedContext({
|
||||
blueprint: {
|
||||
findMany,
|
||||
},
|
||||
}));
|
||||
const caller = createCallerFactory(blueprintRouter)(
|
||||
createProtectedContext({
|
||||
blueprint: {
|
||||
findMany,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
await expect(caller.listSummaries()).rejects.toMatchObject({
|
||||
code: "FORBIDDEN",
|
||||
@@ -59,13 +61,18 @@ describe("master-data router authorization", () => {
|
||||
_count: { projects: 4 },
|
||||
},
|
||||
]);
|
||||
const caller = createCallerFactory(blueprintRouter)(createProtectedContext({
|
||||
blueprint: {
|
||||
findMany,
|
||||
},
|
||||
}, {
|
||||
granted: [PermissionKey.VIEW_PLANNING],
|
||||
}));
|
||||
const caller = createCallerFactory(blueprintRouter)(
|
||||
createProtectedContext(
|
||||
{
|
||||
blueprint: {
|
||||
findMany,
|
||||
},
|
||||
},
|
||||
{
|
||||
granted: [PermissionKey.VIEW_PLANNING],
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
const result = await caller.listSummaries();
|
||||
|
||||
@@ -85,19 +92,23 @@ describe("master-data router authorization", () => {
|
||||
const findMany = vi.fn();
|
||||
const findUnique = vi.fn();
|
||||
const findFirst = vi.fn();
|
||||
const caller = createCallerFactory(blueprintRouter)(createProtectedContext({
|
||||
blueprint: {
|
||||
findMany,
|
||||
findUnique,
|
||||
findFirst,
|
||||
},
|
||||
}));
|
||||
const caller = createCallerFactory(blueprintRouter)(
|
||||
createProtectedContext({
|
||||
blueprint: {
|
||||
findMany,
|
||||
findUnique,
|
||||
findFirst,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
await expect(caller.list({ isActive: true })).rejects.toMatchObject({
|
||||
code: "FORBIDDEN",
|
||||
message: "Planning read access required",
|
||||
});
|
||||
await expect(caller.getByIdentifier({ identifier: "Consulting Blueprint" })).rejects.toMatchObject({
|
||||
await expect(
|
||||
caller.getByIdentifier({ identifier: "Consulting Blueprint" }),
|
||||
).rejects.toMatchObject({
|
||||
code: "FORBIDDEN",
|
||||
message: "Planning read access required",
|
||||
});
|
||||
@@ -121,7 +132,8 @@ describe("master-data router authorization", () => {
|
||||
isActive: true,
|
||||
},
|
||||
]);
|
||||
const getByIdFindUnique = vi.fn()
|
||||
const getByIdFindUnique = vi
|
||||
.fn()
|
||||
.mockResolvedValueOnce({
|
||||
id: "bp_1",
|
||||
name: "Consulting Blueprint",
|
||||
@@ -145,15 +157,20 @@ describe("master-data router authorization", () => {
|
||||
rolePresets: [],
|
||||
isActive: true,
|
||||
});
|
||||
const caller = createCallerFactory(blueprintRouter)(createProtectedContext({
|
||||
blueprint: {
|
||||
findMany: listFindMany,
|
||||
findUnique: getByIdFindUnique,
|
||||
findFirst: getByIdentifierFindFirst,
|
||||
},
|
||||
}, {
|
||||
granted: [PermissionKey.VIEW_PLANNING],
|
||||
}));
|
||||
const caller = createCallerFactory(blueprintRouter)(
|
||||
createProtectedContext(
|
||||
{
|
||||
blueprint: {
|
||||
findMany: listFindMany,
|
||||
findUnique: getByIdFindUnique,
|
||||
findFirst: getByIdentifierFindFirst,
|
||||
},
|
||||
},
|
||||
{
|
||||
granted: [PermissionKey.VIEW_PLANNING],
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
const listResult = await caller.list({ target: BlueprintTarget.PROJECT, isActive: true });
|
||||
const byIdResult = await caller.getById({ id: "bp_1" });
|
||||
@@ -177,22 +194,30 @@ describe("master-data router authorization", () => {
|
||||
it("requires authenticated planning access for global blueprint field definitions", async () => {
|
||||
const findMany = vi.fn();
|
||||
|
||||
const unauthenticatedCaller = createCallerFactory(blueprintRouter)(createUnauthenticatedContext({
|
||||
blueprint: {
|
||||
findMany,
|
||||
},
|
||||
}));
|
||||
const authenticatedCaller = createCallerFactory(blueprintRouter)(createProtectedContext({
|
||||
blueprint: {
|
||||
findMany,
|
||||
},
|
||||
}));
|
||||
const unauthenticatedCaller = createCallerFactory(blueprintRouter)(
|
||||
createUnauthenticatedContext({
|
||||
blueprint: {
|
||||
findMany,
|
||||
},
|
||||
}),
|
||||
);
|
||||
const authenticatedCaller = createCallerFactory(blueprintRouter)(
|
||||
createProtectedContext({
|
||||
blueprint: {
|
||||
findMany,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
await expect(unauthenticatedCaller.getGlobalFieldDefs({ target: BlueprintTarget.PROJECT })).rejects.toMatchObject({
|
||||
await expect(
|
||||
unauthenticatedCaller.getGlobalFieldDefs({ target: BlueprintTarget.PROJECT }),
|
||||
).rejects.toMatchObject({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "Authentication required",
|
||||
});
|
||||
await expect(authenticatedCaller.getGlobalFieldDefs({ target: BlueprintTarget.PROJECT })).rejects.toMatchObject({
|
||||
await expect(
|
||||
authenticatedCaller.getGlobalFieldDefs({ target: BlueprintTarget.PROJECT }),
|
||||
).rejects.toMatchObject({
|
||||
code: "FORBIDDEN",
|
||||
message: "Planning read access required",
|
||||
});
|
||||
@@ -211,13 +236,18 @@ describe("master-data router authorization", () => {
|
||||
],
|
||||
},
|
||||
]);
|
||||
const caller = createCallerFactory(blueprintRouter)(createProtectedContext({
|
||||
blueprint: {
|
||||
findMany,
|
||||
},
|
||||
}, {
|
||||
granted: [PermissionKey.VIEW_PLANNING],
|
||||
}));
|
||||
const caller = createCallerFactory(blueprintRouter)(
|
||||
createProtectedContext(
|
||||
{
|
||||
blueprint: {
|
||||
findMany,
|
||||
},
|
||||
},
|
||||
{
|
||||
granted: [PermissionKey.VIEW_PLANNING],
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
const result = await caller.getGlobalFieldDefs({ target: BlueprintTarget.PROJECT });
|
||||
|
||||
@@ -254,20 +284,24 @@ describe("master-data router authorization", () => {
|
||||
metroCities: [{ id: "city_ber", name: "Berlin", countryId: "country_de" }],
|
||||
},
|
||||
]);
|
||||
const caller = createCallerFactory(countryRouter)(createProtectedContext({
|
||||
country: {
|
||||
findMany,
|
||||
},
|
||||
}));
|
||||
const caller = createCallerFactory(countryRouter)(
|
||||
createProtectedContext({
|
||||
country: {
|
||||
findMany,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
const result = await caller.list({ isActive: true });
|
||||
|
||||
expect(result).toHaveLength(1);
|
||||
expect(findMany).toHaveBeenCalledWith(expect.objectContaining({
|
||||
where: { isActive: true },
|
||||
include: { metroCities: { orderBy: { name: "asc" } } },
|
||||
orderBy: { name: "asc" },
|
||||
}));
|
||||
expect(findMany).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
where: { isActive: true },
|
||||
include: { metroCities: { orderBy: { name: "asc" } } },
|
||||
orderBy: { name: "asc" },
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps minimal country lookups available to authenticated users", async () => {
|
||||
@@ -278,12 +312,14 @@ describe("master-data router authorization", () => {
|
||||
isActive: true,
|
||||
dailyWorkingHours: 8,
|
||||
});
|
||||
const caller = createCallerFactory(countryRouter)(createProtectedContext({
|
||||
country: {
|
||||
findUnique: vi.fn().mockResolvedValue(null),
|
||||
findFirst,
|
||||
},
|
||||
}));
|
||||
const caller = createCallerFactory(countryRouter)(
|
||||
createProtectedContext({
|
||||
country: {
|
||||
findUnique: vi.fn().mockResolvedValue(null),
|
||||
findFirst,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
const result = await caller.resolveByIdentifier({ identifier: "de" });
|
||||
|
||||
@@ -303,11 +339,13 @@ describe("master-data router authorization", () => {
|
||||
name: "Munich",
|
||||
countryId: "country_de",
|
||||
});
|
||||
const caller = createCallerFactory(countryRouter)(createProtectedContext({
|
||||
metroCity: {
|
||||
findUnique,
|
||||
},
|
||||
}));
|
||||
const caller = createCallerFactory(countryRouter)(
|
||||
createProtectedContext({
|
||||
metroCity: {
|
||||
findUnique,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
const result = await caller.getCityById({ id: "city_muc" });
|
||||
|
||||
@@ -323,12 +361,14 @@ describe("master-data router authorization", () => {
|
||||
});
|
||||
|
||||
it("requires resource overview access for detailed country reads with resource counts", async () => {
|
||||
const caller = createCallerFactory(countryRouter)(createProtectedContext({
|
||||
country: {
|
||||
findFirst: vi.fn(),
|
||||
findUnique: vi.fn(),
|
||||
},
|
||||
}));
|
||||
const caller = createCallerFactory(countryRouter)(
|
||||
createProtectedContext({
|
||||
country: {
|
||||
findFirst: vi.fn(),
|
||||
findUnique: vi.fn(),
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
await expect(caller.getByIdentifier({ identifier: "DE" })).rejects.toMatchObject({
|
||||
code: "FORBIDDEN",
|
||||
@@ -351,24 +391,31 @@ describe("master-data router authorization", () => {
|
||||
metroCities: [{ id: "city_muc", name: "Munich", countryId: "country_de" }],
|
||||
_count: { resources: 12 },
|
||||
});
|
||||
const caller = createCallerFactory(countryRouter)(createProtectedContext({
|
||||
country: {
|
||||
findUnique: vi.fn().mockResolvedValue(null),
|
||||
findFirst,
|
||||
},
|
||||
}, {
|
||||
granted: [PermissionKey.VIEW_ALL_RESOURCES],
|
||||
}));
|
||||
const caller = createCallerFactory(countryRouter)(
|
||||
createProtectedContext(
|
||||
{
|
||||
country: {
|
||||
findUnique: vi.fn().mockResolvedValue(null),
|
||||
findFirst,
|
||||
},
|
||||
},
|
||||
{
|
||||
granted: [PermissionKey.VIEW_ALL_RESOURCES],
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
const result = await caller.getByIdentifier({ identifier: "DE" });
|
||||
|
||||
expect(result._count.resources).toBe(12);
|
||||
expect(findFirst).toHaveBeenCalledWith(expect.objectContaining({
|
||||
include: expect.objectContaining({
|
||||
metroCities: expect.any(Object),
|
||||
_count: expect.any(Object),
|
||||
expect(findFirst).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
include: expect.objectContaining({
|
||||
metroCities: expect.any(Object),
|
||||
_count: expect.any(Object),
|
||||
}),
|
||||
}),
|
||||
}));
|
||||
);
|
||||
});
|
||||
|
||||
it("allows detailed country reads for users with manage-resources access", async () => {
|
||||
@@ -382,13 +429,18 @@ describe("master-data router authorization", () => {
|
||||
metroCities: [],
|
||||
_count: { resources: 4 },
|
||||
});
|
||||
const caller = createCallerFactory(countryRouter)(createProtectedContext({
|
||||
country: {
|
||||
findUnique,
|
||||
},
|
||||
}, {
|
||||
granted: [PermissionKey.MANAGE_RESOURCES],
|
||||
}));
|
||||
const caller = createCallerFactory(countryRouter)(
|
||||
createProtectedContext(
|
||||
{
|
||||
country: {
|
||||
findUnique,
|
||||
},
|
||||
},
|
||||
{
|
||||
granted: [PermissionKey.MANAGE_RESOURCES],
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
const result = await caller.getById({ id: "country_de" });
|
||||
|
||||
@@ -397,21 +449,21 @@ describe("master-data router authorization", () => {
|
||||
});
|
||||
|
||||
it("keeps minimal org-unit lookups available to authenticated users", async () => {
|
||||
const findFirst = vi.fn()
|
||||
.mockResolvedValueOnce(null)
|
||||
.mockResolvedValueOnce({
|
||||
id: "ou_1",
|
||||
name: "Delivery",
|
||||
shortName: "DEL",
|
||||
level: 5,
|
||||
isActive: true,
|
||||
});
|
||||
const caller = createCallerFactory(orgUnitRouter)(createProtectedContext({
|
||||
orgUnit: {
|
||||
findUnique: vi.fn().mockResolvedValue(null),
|
||||
findFirst,
|
||||
},
|
||||
}));
|
||||
const findFirst = vi.fn().mockResolvedValueOnce(null).mockResolvedValueOnce({
|
||||
id: "ou_1",
|
||||
name: "Delivery",
|
||||
shortName: "DEL",
|
||||
level: 5,
|
||||
isActive: true,
|
||||
});
|
||||
const caller = createCallerFactory(orgUnitRouter)(
|
||||
createProtectedContext({
|
||||
orgUnit: {
|
||||
findUnique: vi.fn().mockResolvedValue(null),
|
||||
findFirst,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
const result = await caller.resolveByIdentifier({ identifier: "DEL" });
|
||||
|
||||
@@ -426,11 +478,13 @@ describe("master-data router authorization", () => {
|
||||
|
||||
it("requires resource overview access for org-unit list and tree reads", async () => {
|
||||
const findMany = vi.fn();
|
||||
const caller = createCallerFactory(orgUnitRouter)(createProtectedContext({
|
||||
orgUnit: {
|
||||
findMany,
|
||||
},
|
||||
}));
|
||||
const caller = createCallerFactory(orgUnitRouter)(
|
||||
createProtectedContext({
|
||||
orgUnit: {
|
||||
findMany,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
await expect(caller.list({ level: 5, isActive: true })).rejects.toMatchObject({
|
||||
code: "FORBIDDEN",
|
||||
@@ -445,12 +499,14 @@ describe("master-data router authorization", () => {
|
||||
});
|
||||
|
||||
it("requires resource overview access for detailed org-unit reads with staffing counts", async () => {
|
||||
const caller = createCallerFactory(orgUnitRouter)(createProtectedContext({
|
||||
orgUnit: {
|
||||
findFirst: vi.fn(),
|
||||
findUnique: vi.fn(),
|
||||
},
|
||||
}));
|
||||
const caller = createCallerFactory(orgUnitRouter)(
|
||||
createProtectedContext({
|
||||
orgUnit: {
|
||||
findFirst: vi.fn(),
|
||||
findUnique: vi.fn(),
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
await expect(caller.getByIdentifier({ identifier: "Delivery" })).rejects.toMatchObject({
|
||||
code: "FORBIDDEN",
|
||||
@@ -473,21 +529,28 @@ describe("master-data router authorization", () => {
|
||||
isActive: true,
|
||||
_count: { resources: 7 },
|
||||
});
|
||||
const caller = createCallerFactory(orgUnitRouter)(createProtectedContext({
|
||||
orgUnit: {
|
||||
findUnique: vi.fn().mockResolvedValue(null),
|
||||
findFirst,
|
||||
},
|
||||
}, {
|
||||
granted: [PermissionKey.VIEW_ALL_RESOURCES],
|
||||
}));
|
||||
const caller = createCallerFactory(orgUnitRouter)(
|
||||
createProtectedContext(
|
||||
{
|
||||
orgUnit: {
|
||||
findUnique: vi.fn().mockResolvedValue(null),
|
||||
findFirst,
|
||||
},
|
||||
},
|
||||
{
|
||||
granted: [PermissionKey.VIEW_ALL_RESOURCES],
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
const result = await caller.getByIdentifier({ identifier: "Delivery" });
|
||||
|
||||
expect(result._count.resources).toBe(7);
|
||||
expect(findFirst).toHaveBeenCalledWith(expect.objectContaining({
|
||||
include: { _count: { select: { resources: true } } },
|
||||
}));
|
||||
expect(findFirst).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
include: { _count: { select: { resources: true } } },
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("allows org-unit list and tree reads for users with resource overview access", async () => {
|
||||
@@ -517,15 +580,21 @@ describe("master-data router authorization", () => {
|
||||
updatedAt: new Date("2026-03-01T00:00:00.000Z"),
|
||||
},
|
||||
]);
|
||||
const caller = createCallerFactory(orgUnitRouter)(createProtectedContext({
|
||||
orgUnit: {
|
||||
findMany: vi.fn()
|
||||
.mockImplementationOnce(listFindMany)
|
||||
.mockImplementationOnce(treeFindMany),
|
||||
},
|
||||
}, {
|
||||
granted: [PermissionKey.MANAGE_RESOURCES],
|
||||
}));
|
||||
const caller = createCallerFactory(orgUnitRouter)(
|
||||
createProtectedContext(
|
||||
{
|
||||
orgUnit: {
|
||||
findMany: vi
|
||||
.fn()
|
||||
.mockImplementationOnce(listFindMany)
|
||||
.mockImplementationOnce(treeFindMany),
|
||||
},
|
||||
},
|
||||
{
|
||||
granted: [PermissionKey.MANAGE_RESOURCES],
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
const listResult = await caller.list({ level: 5, isActive: true });
|
||||
const treeResult = await caller.getTree({ isActive: true });
|
||||
@@ -549,21 +618,21 @@ describe("master-data router authorization", () => {
|
||||
});
|
||||
|
||||
it("keeps minimal client lookups available to authenticated users", async () => {
|
||||
const findUnique = vi.fn()
|
||||
.mockResolvedValueOnce(null)
|
||||
.mockResolvedValueOnce({
|
||||
id: "client_1",
|
||||
name: "Acme Studios",
|
||||
code: "ACME",
|
||||
parentId: null,
|
||||
isActive: true,
|
||||
});
|
||||
const caller = createCallerFactory(clientRouter)(createProtectedContext({
|
||||
client: {
|
||||
findUnique,
|
||||
findFirst: vi.fn(),
|
||||
},
|
||||
}));
|
||||
const findUnique = vi.fn().mockResolvedValueOnce(null).mockResolvedValueOnce({
|
||||
id: "client_1",
|
||||
name: "Acme Studios",
|
||||
code: "ACME",
|
||||
parentId: null,
|
||||
isActive: true,
|
||||
});
|
||||
const caller = createCallerFactory(clientRouter)(
|
||||
createProtectedContext({
|
||||
client: {
|
||||
findUnique,
|
||||
findFirst: vi.fn(),
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
const result = await caller.resolveByIdentifier({ identifier: "ACME" });
|
||||
|
||||
@@ -578,11 +647,13 @@ describe("master-data router authorization", () => {
|
||||
|
||||
it("requires planning read access for client list and tree reads", async () => {
|
||||
const findMany = vi.fn();
|
||||
const caller = createCallerFactory(clientRouter)(createProtectedContext({
|
||||
client: {
|
||||
findMany,
|
||||
},
|
||||
}));
|
||||
const caller = createCallerFactory(clientRouter)(
|
||||
createProtectedContext({
|
||||
client: {
|
||||
findMany,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
await expect(caller.list({ isActive: true })).rejects.toMatchObject({
|
||||
code: "FORBIDDEN",
|
||||
@@ -597,12 +668,14 @@ describe("master-data router authorization", () => {
|
||||
});
|
||||
|
||||
it("requires planning read access for detailed client reads with project counts", async () => {
|
||||
const caller = createCallerFactory(clientRouter)(createProtectedContext({
|
||||
client: {
|
||||
findFirst: vi.fn(),
|
||||
findUnique: vi.fn(),
|
||||
},
|
||||
}));
|
||||
const caller = createCallerFactory(clientRouter)(
|
||||
createProtectedContext({
|
||||
client: {
|
||||
findFirst: vi.fn(),
|
||||
findUnique: vi.fn(),
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
await expect(caller.getByIdentifier({ identifier: "Acme" })).rejects.toMatchObject({
|
||||
code: "FORBIDDEN",
|
||||
@@ -642,7 +715,8 @@ describe("master-data router authorization", () => {
|
||||
updatedAt: new Date("2026-03-01T00:00:00.000Z"),
|
||||
},
|
||||
]);
|
||||
const getByIdFindUnique = vi.fn()
|
||||
const getByIdFindUnique = vi
|
||||
.fn()
|
||||
.mockResolvedValueOnce({
|
||||
id: "client_1",
|
||||
name: "Acme Studios",
|
||||
@@ -670,17 +744,23 @@ describe("master-data router authorization", () => {
|
||||
updatedAt: new Date("2026-03-01T00:00:00.000Z"),
|
||||
_count: { children: 1, projects: 4 },
|
||||
});
|
||||
const caller = createCallerFactory(clientRouter)(createProtectedContext({
|
||||
client: {
|
||||
findMany: vi.fn()
|
||||
.mockImplementationOnce(listFindMany)
|
||||
.mockImplementationOnce(treeFindMany),
|
||||
findUnique: getByIdFindUnique,
|
||||
findFirst: getByIdentifierFindFirst,
|
||||
},
|
||||
}, {
|
||||
granted: [PermissionKey.VIEW_PLANNING],
|
||||
}));
|
||||
const caller = createCallerFactory(clientRouter)(
|
||||
createProtectedContext(
|
||||
{
|
||||
client: {
|
||||
findMany: vi
|
||||
.fn()
|
||||
.mockImplementationOnce(listFindMany)
|
||||
.mockImplementationOnce(treeFindMany),
|
||||
findUnique: getByIdFindUnique,
|
||||
findFirst: getByIdentifierFindFirst,
|
||||
},
|
||||
},
|
||||
{
|
||||
granted: [PermissionKey.VIEW_PLANNING],
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
const listResult = await caller.list({ isActive: true, search: "Acme" });
|
||||
const treeResult = await caller.getTree({ isActive: true });
|
||||
@@ -720,21 +800,25 @@ describe("master-data router authorization", () => {
|
||||
_count: { select: { projects: true, children: true } },
|
||||
},
|
||||
});
|
||||
expect(getByIdentifierFindFirst).toHaveBeenCalledWith(expect.objectContaining({
|
||||
where: { name: { equals: "Acme Studios", mode: "insensitive" } },
|
||||
include: { _count: { select: { projects: true, children: true } } },
|
||||
}));
|
||||
expect(getByIdentifierFindFirst).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
where: { name: { equals: "Acme Studios", mode: "insensitive" } },
|
||||
include: { _count: { select: { projects: true, children: true } } },
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("requires planning read access for utilization-category reads with project counts", async () => {
|
||||
const listFindMany = vi.fn();
|
||||
const getByIdFindUnique = vi.fn();
|
||||
const caller = createCallerFactory(utilizationCategoryRouter)(createProtectedContext({
|
||||
utilizationCategory: {
|
||||
findMany: listFindMany,
|
||||
findUnique: getByIdFindUnique,
|
||||
},
|
||||
}));
|
||||
const caller = createCallerFactory(utilizationCategoryRouter)(
|
||||
createProtectedContext({
|
||||
utilizationCategory: {
|
||||
findMany: listFindMany,
|
||||
findUnique: getByIdFindUnique,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
await expect(caller.list({ isActive: true })).rejects.toMatchObject({
|
||||
code: "FORBIDDEN",
|
||||
@@ -771,14 +855,19 @@ describe("master-data router authorization", () => {
|
||||
isActive: true,
|
||||
_count: { projects: 12 },
|
||||
});
|
||||
const caller = createCallerFactory(utilizationCategoryRouter)(createProtectedContext({
|
||||
utilizationCategory: {
|
||||
findMany: listFindMany,
|
||||
findUnique: getByIdFindUnique,
|
||||
},
|
||||
}, {
|
||||
granted: [PermissionKey.VIEW_PLANNING],
|
||||
}));
|
||||
const caller = createCallerFactory(utilizationCategoryRouter)(
|
||||
createProtectedContext(
|
||||
{
|
||||
utilizationCategory: {
|
||||
findMany: listFindMany,
|
||||
findUnique: getByIdFindUnique,
|
||||
},
|
||||
},
|
||||
{
|
||||
granted: [PermissionKey.VIEW_PLANNING],
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
const listResult = await caller.list({ isActive: true });
|
||||
const byIdResult = await caller.getById({ id: "util_chargeable" });
|
||||
@@ -788,6 +877,7 @@ describe("master-data router authorization", () => {
|
||||
expect(listFindMany).toHaveBeenCalledWith({
|
||||
where: { isActive: true },
|
||||
orderBy: { sortOrder: "asc" },
|
||||
include: { _count: { select: { projects: true } } },
|
||||
});
|
||||
expect(getByIdFindUnique).toHaveBeenCalledWith({
|
||||
where: { id: "util_chargeable" },
|
||||
@@ -798,12 +888,14 @@ describe("master-data router authorization", () => {
|
||||
it("requires planning read access for management-level reads", async () => {
|
||||
const listFindMany = vi.fn();
|
||||
const getByIdFindUnique = vi.fn();
|
||||
const caller = createCallerFactory(managementLevelRouter)(createProtectedContext({
|
||||
managementLevelGroup: {
|
||||
findMany: listFindMany,
|
||||
findUnique: getByIdFindUnique,
|
||||
},
|
||||
}));
|
||||
const caller = createCallerFactory(managementLevelRouter)(
|
||||
createProtectedContext({
|
||||
managementLevelGroup: {
|
||||
findMany: listFindMany,
|
||||
findUnique: getByIdFindUnique,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
await expect(caller.listGroups()).rejects.toMatchObject({
|
||||
code: "FORBIDDEN",
|
||||
@@ -836,14 +928,19 @@ describe("master-data router authorization", () => {
|
||||
levels: [{ id: "mgmt_level_1", name: "Senior Team Lead" }],
|
||||
_count: { resources: 6 },
|
||||
});
|
||||
const caller = createCallerFactory(managementLevelRouter)(createProtectedContext({
|
||||
managementLevelGroup: {
|
||||
findMany: listFindMany,
|
||||
findUnique: getByIdFindUnique,
|
||||
},
|
||||
}, {
|
||||
granted: [PermissionKey.VIEW_PLANNING],
|
||||
}));
|
||||
const caller = createCallerFactory(managementLevelRouter)(
|
||||
createProtectedContext(
|
||||
{
|
||||
managementLevelGroup: {
|
||||
findMany: listFindMany,
|
||||
findUnique: getByIdFindUnique,
|
||||
},
|
||||
},
|
||||
{
|
||||
granted: [PermissionKey.VIEW_PLANNING],
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
const listResult = await caller.listGroups();
|
||||
const detailResult = await caller.getGroupById({ id: "mgmt_group_1" });
|
||||
|
||||
@@ -48,6 +48,7 @@ describe("utilization category router", () => {
|
||||
expect(findMany).toHaveBeenCalledWith({
|
||||
where: { isActive: true },
|
||||
orderBy: { sortOrder: "asc" },
|
||||
include: { _count: { select: { projects: true } } },
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user