app/db/procedures.ts
117 lines and 11 functions in DrDustinEdwards/dustinedwards-info, at commit 1590ba4 on 2026-10-24. This file on GitHub.
Functions
| Function | Lines | Complexity | Covered | CRAP | Mutation |
|---|---|---|---|---|---|
| getProcedureByPath | 19 to 29 | 2 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
| getPublishedProcedureMarkdown | 32 to 41 | 2 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
| listPublishedProcedures | 44 to 57 | 1 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
| listProceduresForOperator | 60 to 84 | 1 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
| <anonymous:74> | 74 to 83 | 3 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
| listPublishedRecordsOfProfile | 87 to 94 | 1 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
| <anonymous:93> | 93 to 93 | 1 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
| listPublishedLibraryRecords | 97 to 104 | 1 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
| <anonymous:103> | 103 to 103 | 1 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
| listProceduresForAdmin | 107 to 127 | 1 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
| <anonymous:122> | 122 to 126 | 1 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
Imports
It imports app/db/client.ts, app/db/schema.ts, app/kb/procedures/render.mjs, app/lib/search/visibility.mjs. Imported by app/kb/procedures/lineage.server.ts, app/lib/carrel/procedure-handler.server.ts, app/lib/llms/save.server.ts, app/lib/operator/api.server.ts, app/lib/pages/save.server.ts, app/lib/site-urls.server.ts, app/routes/admin.kb.tsx, app/routes/kb-library.tsx, app/routes/kb-library[.csv].ts, app/routes/kb-library[.json].ts, app/routes/kb-library[.md].ts, app/routes/lab.kind.tsx, app/routes/lab[.md].ts, app/routes/procedure.sheet.tsx, app/routes/procedure.tsx, app/routes/procedure.version.tsx, app/routes/procedure[.md].ts, app/routes/protocols.tsx, app/routes/protocols[.csv].ts, app/routes/protocols[.json].ts, app/routes/protocols[.md].ts.
Source
// The procedures table: read by the procedure pages, the sitemap and the operator API. Written only by
// writeProcedureRow, from a compile (app/kb/procedures/compile.mjs).
import { and, asc, eq } from "drizzle-orm";
import { PUBLISHED_STATUS } from "~/lib/search/visibility.mjs";
import type { ProcedureRecord } from "~/kb/procedures/render.mjs";
import { getDb } from "./client";
import { procedures } from "./schema";
export type ProcedureRow = {
slug: string;
path: string;
status: "draft" | "published";
record: ProcedureRecord;
};
/** The page's row, or null. A draft comes back too: the route decides who may see it. */
export async function getProcedureByPath(env: Env, path: string): Promise<ProcedureRow | null> {
const row = (
await getDb(env)
.select({ slug: procedures.slug, path: procedures.path, status: procedures.status, record: procedures.record })
.from(procedures)
.where(eq(procedures.path, path))
.limit(1)
)[0];
if (!row) return null;
return { ...row, record: JSON.parse(row.record) as ProcedureRecord };
}
/** The twin, published rows only: a draft's twin answers 404 like its page. */
export async function getPublishedProcedureMarkdown(env: Env, path: string) {
const row = (
await getDb(env)
.select({ markdown: procedures.markdown })
.from(procedures)
.where(and(eq(procedures.path, path), eq(procedures.status, PUBLISHED_STATUS)))
.limit(1)
)[0];
return row?.markdown ?? null;
}
/** For the sitemap and llms-full: the published pages, by path. */
export async function listPublishedProcedures(env: Env) {
return getDb(env)
.select({
path: procedures.path,
title: procedures.title,
description: procedures.description,
updated: procedures.updated,
markdown: procedures.markdown,
sourcePath: procedures.sourcePath,
})
.from(procedures)
.where(eq(procedures.status, PUBLISHED_STATUS))
.orderBy(asc(procedures.path));
}
/** For the operator's list_procedures: every row, drafts included. */
export async function listProceduresForOperator(env: Env) {
const rows = await getDb(env)
.select({
slug: procedures.slug,
path: procedures.path,
profile: procedures.profile,
title: procedures.title,
status: procedures.status,
version: procedures.version,
updated: procedures.updated,
record: procedures.record,
})
.from(procedures)
.orderBy(asc(procedures.slug));
return rows.map(({ record, status, ...row }) => {
const parsed = JSON.parse(record) as ProcedureRecord;
return {
...row,
draft: status === "draft",
gaps: parsed.gaps.length,
// The admin's view, so Dustin can find the protocols still to set: the level, or MISSING. Public output never says MISSING.
biosafetyLevel: row.profile === "protocol" ? (parsed.biosafetyLevel ?? "MISSING") : null,
};
});
}
/** A knowledge base's published records, for its library (app/kb/libraries.mjs). */
export async function listPublishedRecordsOfProfile(env: Env, profile: "protocol" | "recipe" | "computational"): Promise<ProcedureRecord[]> {
const rows = await getDb(env)
.select({ record: procedures.record })
.from(procedures)
.where(and(eq(procedures.status, PUBLISHED_STATUS), eq(procedures.profile, profile)))
.orderBy(asc(procedures.path));
return rows.map((row) => JSON.parse(row.record) as ProcedureRecord);
}
/** For the protocol library: every published protocol, with its full record. */
export async function listPublishedLibraryRecords(env: Env): Promise<ProcedureRecord[]> {
const rows = await getDb(env)
.select({ record: procedures.record })
.from(procedures)
.where(and(eq(procedures.status, PUBLISHED_STATUS), eq(procedures.profile, "protocol")))
.orderBy(asc(procedures.path));
return rows.map((row) => JSON.parse(row.record) as ProcedureRecord);
}
/** For the admin's Knowledge Base page: every row, drafts included, with each recorded gap as the compile stated it. */
export async function listProceduresForAdmin(env: Env) {
const rows = await getDb(env)
.select({
slug: procedures.slug,
path: procedures.path,
profile: procedures.profile,
title: procedures.title,
description: procedures.description,
status: procedures.status,
version: procedures.version,
updated: procedures.updated,
record: procedures.record,
})
.from(procedures)
.orderBy(asc(procedures.slug));
return rows.map(({ record, status, ...row }) => ({
...row,
draft: status === "draft",
gaps: (JSON.parse(record) as ProcedureRecord).gaps,
}));
}