refactor(api): extract role read procedures

This commit is contained in:
2026-03-31 21:22:44 +02:00
parent cba4d44f16
commit 884f1012c9
5 changed files with 345 additions and 84 deletions
@@ -4,10 +4,18 @@ import {
createRole,
deactivateRole,
deleteRole,
getRoleById,
getRoleByIdentifier,
listRoles,
resolveRoleByIdentifier,
RoleIdInputSchema,
RoleIdentifierInputSchema,
RoleListInputSchema,
ResolveRoleIdentifierInputSchema,
UpdateRoleProcedureInputSchema,
updateRole,
} from "../router/role-procedure-support.js";
import { RESOURCE_BRIEF_SELECT } from "../db/selects.js";
const { countPlanningEntries } = vi.hoisted(() => ({
countPlanningEntries: vi.fn(),
@@ -49,6 +57,163 @@ describe("role procedure support", () => {
emitRoleUpdated.mockReset();
});
it("lists roles with planning entry counts", async () => {
countPlanningEntries.mockResolvedValue({
countsByRoleId: new Map([["role_fx", 2]]),
});
const db = {
role: {
findMany: vi.fn().mockResolvedValue([
{
id: "role_fx",
name: "FX",
_count: { resourceRoles: 1 },
},
]),
},
demandRequirement: {},
assignment: {},
};
const result = await listRoles(
createContext(db),
RoleListInputSchema.parse({ search: "FX" }),
);
expect(result).toEqual([
{
id: "role_fx",
name: "FX",
_count: { resourceRoles: 1, allocations: 2 },
},
]);
expect(db.role.findMany).toHaveBeenCalledWith({
where: { name: { contains: "FX", mode: "insensitive" } },
include: { _count: { select: { resourceRoles: true } } },
orderBy: { name: "asc" },
});
});
it("resolves roles by identifier for protected read paths", async () => {
const db = {
role: {
findUnique: vi.fn().mockResolvedValue({
id: "role_fx",
name: "FX",
color: "#111111",
isActive: true,
}),
},
};
const result = await resolveRoleByIdentifier(
createContext(db),
ResolveRoleIdentifierInputSchema.parse({ identifier: "role_fx" }),
);
expect(result).toEqual({
id: "role_fx",
name: "FX",
color: "#111111",
isActive: true,
});
expect(db.role.findUnique).toHaveBeenCalledWith({
where: { id: "role_fx" },
select: {
id: true,
name: true,
color: true,
isActive: true,
},
});
});
it("loads a role by identifier and attaches planning counts", async () => {
countPlanningEntries.mockResolvedValue({
countsByRoleId: new Map([["role_fx", 3]]),
});
const db = {
role: {
findUnique: vi.fn().mockResolvedValue({
id: "role_fx",
name: "FX",
description: null,
color: "#111111",
isActive: true,
_count: { resourceRoles: 2 },
}),
},
demandRequirement: {},
assignment: {},
};
const result = await getRoleByIdentifier(
createContext(db),
RoleIdentifierInputSchema.parse({ identifier: "role_fx" }),
);
expect(result).toEqual({
id: "role_fx",
name: "FX",
description: null,
color: "#111111",
isActive: true,
_count: { resourceRoles: 2, allocations: 3 },
});
expect(db.role.findUnique).toHaveBeenCalledWith({
where: { id: "role_fx" },
select: {
id: true,
name: true,
description: true,
color: true,
isActive: true,
_count: { select: { resourceRoles: true } },
},
});
});
it("loads a role by id with resource role details and planning counts", async () => {
countPlanningEntries.mockResolvedValue({
countsByRoleId: new Map([["role_fx", 1]]),
});
const db = {
role: {
findUnique: vi.fn().mockResolvedValue({
id: "role_fx",
name: "FX",
_count: { resourceRoles: 1 },
resourceRoles: [],
}),
},
demandRequirement: {},
assignment: {},
};
const result = await getRoleById(
createContext(db),
RoleIdInputSchema.parse({ id: "role_fx" }),
);
expect(result).toEqual({
id: "role_fx",
name: "FX",
_count: { resourceRoles: 1, allocations: 1 },
resourceRoles: [],
});
expect(db.role.findUnique).toHaveBeenCalledWith({
where: { id: "role_fx" },
include: {
_count: { select: { resourceRoles: true } },
resourceRoles: {
include: {
resource: { select: RESOURCE_BRIEF_SELECT },
},
},
},
});
});
it("creates roles with audit and zero allocation counts", async () => {
const role = {
id: "role_fx",