import type { Db } from "../db/database.js"; import { createModelRow, deleteModelRow, getModel, resolveCompany, updateModelCell } from "../db/queries.js"; import { fail, ok } from "./result.js"; import type { RpcHandlers } from "./types.js"; function errorDetail(operation: string, error: unknown): { operation: string; message?: string } { return { operation, message: error instanceof Error ? error.message : undefined, }; } export function modelHandlers(db: Db): RpcHandlers<"model.get" | "model.updateCell" | "model.createRow" | "model.deleteRow" | "model.runScenario"> { return { "model.get": ({ companyId, tab }) => { const company = resolveCompany(db, companyId); if (!company) return fail("NOT_FOUND", `Company "${companyId}" not found.`); try { return ok("model.get", getModel(db, company.id, tab)); } catch (error) { return fail("INTERNAL_ERROR", "Could not load model for company.", errorDetail("getModel", error)); } }, "model.updateCell": ({ companyId, tab, row, col, value }) => { const company = resolveCompany(db, companyId); if (!company) return fail("NOT_FOUND", `Company "${companyId}" not found.`); return ok("model.updateCell", updateModelCell(db, company.id, tab, row, col, value)); }, "model.createRow": ({ companyId, tab, label, kind, values }) => { const company = resolveCompany(db, companyId); if (!company) return fail("NOT_FOUND", `Company "${companyId}" not found.`); return ok("model.createRow", createModelRow(db, company.id, tab, { label, kind, values: values ?? [] })); }, "model.deleteRow": ({ companyId, tab, row }) => { const company = resolveCompany(db, companyId); if (!company) return fail("NOT_FOUND", `Company "${companyId}" not found.`); return ok("model.deleteRow", { ok: deleteModelRow(db, company.id, tab, row) }); }, "model.runScenario": ({ companyId, overrides }) => { const company = resolveCompany(db, companyId); if (!company) return fail("NOT_FOUND", `Company "${companyId}" not found.`); const model = getModel(db, company.id, "operating"); const rows = model.rows.map((row, rowIndex) => ({ ...row, values: row.values.map((value, colIndex) => overrides[`${rowIndex}-${colIndex}`] ?? value), })); return ok("model.runScenario", { headers: model.headers, rows }); }, }; }