refactor(api): extract computation graph procedures

This commit is contained in:
2026-03-31 21:24:28 +02:00
parent 884f1012c9
commit b1799e4f54
4 changed files with 102 additions and 25 deletions
@@ -27,6 +27,7 @@ Done
- `calculation-rules` - `calculation-rules`
- `webhook` - `webhook`
- `role` - `role`
- `computation-graph`
Ready next Ready next
- none in the conflict-safe backlog - none in the conflict-safe backlog
@@ -0,0 +1,52 @@
import { describe, expect, it, vi } from "vitest";
import {
getProjectGraphData,
getResourceGraphData,
} from "../router/computation-graph-procedure-support.js";
const { readResourceGraphSnapshot, readProjectGraphSnapshot } = vi.hoisted(() => ({
readResourceGraphSnapshot: vi.fn(),
readProjectGraphSnapshot: vi.fn(),
}));
vi.mock("../router/computation-graph-resource.js", () => ({
readResourceGraphSnapshot,
}));
vi.mock("../router/computation-graph-project.js", () => ({
readProjectGraphSnapshot,
}));
describe("computation-graph-procedure-support", () => {
it("delegates resource graph reads to the snapshot reader", async () => {
const ctx = { db: {} } as never;
const snapshot = { nodes: [], links: [], meta: { resourceEid: "eid", resourceName: "Bruce" } };
readResourceGraphSnapshot.mockResolvedValue(snapshot);
const result = await getResourceGraphData(ctx, {
resourceId: "resource_1",
month: "2026-01",
});
expect(result).toBe(snapshot);
expect(readResourceGraphSnapshot).toHaveBeenCalledWith(ctx, {
resourceId: "resource_1",
month: "2026-01",
});
});
it("delegates project graph reads to the snapshot reader", async () => {
const ctx = { db: {} } as never;
const snapshot = { nodes: [], links: [], meta: { projectCode: "GDM", projectName: "Gelddruckmaschine" } };
readProjectGraphSnapshot.mockResolvedValue(snapshot);
const result = await getProjectGraphData(ctx, {
projectId: "project_1",
});
expect(result).toBe(snapshot);
expect(readProjectGraphSnapshot).toHaveBeenCalledWith(ctx, {
projectId: "project_1",
});
});
});
@@ -0,0 +1,37 @@
import { z } from "zod";
import type { TRPCContext } from "../trpc.js";
import { createComputationGraphDetailProcedures } from "./computation-graph-detail.js";
import { readProjectGraphSnapshot } from "./computation-graph-project.js";
import { readResourceGraphSnapshot } from "./computation-graph-resource.js";
export const ResourceGraphInputSchema = z.object({
resourceId: z.string(),
month: z.string().regex(/^\d{4}-\d{2}$/),
});
export const ProjectGraphInputSchema = z.object({
projectId: z.string(),
});
type ComputationGraphProcedureContext = Pick<TRPCContext, "db">;
export const computationGraphDetailProcedures = createComputationGraphDetailProcedures({
resourceGraphInputSchema: ResourceGraphInputSchema,
projectGraphInputSchema: ProjectGraphInputSchema,
readResourceGraphSnapshot,
readProjectGraphSnapshot,
});
export async function getResourceGraphData(
ctx: ComputationGraphProcedureContext,
input: z.infer<typeof ResourceGraphInputSchema>,
) {
return readResourceGraphSnapshot(ctx, input);
}
export async function getProjectGraphData(
ctx: ComputationGraphProcedureContext,
input: z.infer<typeof ProjectGraphInputSchema>,
) {
return readProjectGraphSnapshot(ctx, input);
}
+12 -25
View File
@@ -1,27 +1,14 @@
import { z } from "zod"; import { createTRPCRouter, controllerProcedure } from "../trpc.js";
import { createTRPCRouter, controllerProcedure, type TRPCContext } from "../trpc.js"; import {
import { createComputationGraphDetailProcedures } from "./computation-graph-detail.js"; computationGraphDetailProcedures,
import { readProjectGraphSnapshot } from "./computation-graph-project.js"; getProjectGraphData,
import { readResourceGraphSnapshot } from "./computation-graph-resource.js"; getResourceGraphData,
ProjectGraphInputSchema,
ResourceGraphInputSchema,
} from "./computation-graph-procedure-support.js";
import { type GraphLink, type GraphNode } from "./computation-graph-shared.js"; import { type GraphLink, type GraphNode } from "./computation-graph-shared.js";
export type { GraphLink, GraphNode } from "./computation-graph-shared.js"; export type { GraphLink, GraphNode } from "./computation-graph-shared.js";
const resourceGraphInputSchema = z.object({
resourceId: z.string(),
month: z.string().regex(/^\d{4}-\d{2}$/),
});
const projectGraphInputSchema = z.object({
projectId: z.string(),
});
const computationGraphDetailProcedures = createComputationGraphDetailProcedures({
resourceGraphInputSchema,
projectGraphInputSchema,
readResourceGraphSnapshot,
readProjectGraphSnapshot,
});
// ─── Router ───────────────────────────────────────────────────────────────── // ─── Router ─────────────────────────────────────────────────────────────────
export const computationGraphRouter = createTRPCRouter({ export const computationGraphRouter = createTRPCRouter({
@@ -31,13 +18,13 @@ export const computationGraphRouter = createTRPCRouter({
* for a single resource in a single month. * for a single resource in a single month.
*/ */
getResourceData: controllerProcedure getResourceData: controllerProcedure
.input(resourceGraphInputSchema) .input(ResourceGraphInputSchema)
.query(({ ctx, input }) => readResourceGraphSnapshot(ctx, input)), .query(({ ctx, input }) => getResourceGraphData(ctx, input)),
/** /**
* Project View: Estimate, Commercial, Experience, Effort, Spread, Budget * Project View: Estimate, Commercial, Experience, Effort, Spread, Budget
*/ */
getProjectData: controllerProcedure getProjectData: controllerProcedure
.input(projectGraphInputSchema) .input(ProjectGraphInputSchema)
.query(({ ctx, input }) => readProjectGraphSnapshot(ctx, input)), .query(({ ctx, input }) => getProjectGraphData(ctx, input)),
}); });