feat(db): lab_drafts, lab_draws, biomarkers tables

Refs PAI-91.
This commit is contained in:
marcuspaico
2026-08-17 15:17:37 -07:00
parent e3cfc6592e
commit bd4817cb77
5 changed files with 375 additions and 1 deletions

View File

@@ -0,0 +1,33 @@
CREATE TABLE `biomarkers` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`draw_id` text NOT NULL,
`panel` text NOT NULL,
`name` text NOT NULL,
`marker` text NOT NULL,
`analyte_key` text,
`value` text NOT NULL,
`value_num` real,
`unit` text,
`reference_range` text,
`flagged` integer DEFAULT 0 NOT NULL,
`value_canonical` real,
`canonical_unit` text
);
--> statement-breakpoint
CREATE TABLE `lab_drafts` (
`id` text PRIMARY KEY NOT NULL,
`filename` text NOT NULL,
`file_path` text NOT NULL,
`status` text NOT NULL,
`extracted` text,
`error` text,
`created_at` integer NOT NULL
);
--> statement-breakpoint
CREATE TABLE `lab_draws` (
`id` text PRIMARY KEY NOT NULL,
`collected_at` text NOT NULL,
`lab_name` text,
`draft_id` text,
`created_at` integer NOT NULL
);

View File

@@ -0,0 +1,279 @@
{
"version": "6",
"dialect": "sqlite",
"id": "8d0cf0e5-668d-4526-a0cb-5a264d813be3",
"prevId": "383d7bd7-3ebf-456e-8c5c-f39cebab14c4",
"tables": {
"biomarkers": {
"name": "biomarkers",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": true
},
"draw_id": {
"name": "draw_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"panel": {
"name": "panel",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"marker": {
"name": "marker",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"analyte_key": {
"name": "analyte_key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"value_num": {
"name": "value_num",
"type": "real",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"unit": {
"name": "unit",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"reference_range": {
"name": "reference_range",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"flagged": {
"name": "flagged",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": 0
},
"value_canonical": {
"name": "value_canonical",
"type": "real",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"canonical_unit": {
"name": "canonical_unit",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"lab_drafts": {
"name": "lab_drafts",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"filename": {
"name": "filename",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"file_path": {
"name": "file_path",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"status": {
"name": "status",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"extracted": {
"name": "extracted",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"error": {
"name": "error",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"lab_draws": {
"name": "lab_draws",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"collected_at": {
"name": "collected_at",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"lab_name": {
"name": "lab_name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"draft_id": {
"name": "draft_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"sessions": {
"name": "sessions",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"expires_at": {
"name": "expires_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"settings": {
"name": "settings",
"columns": {
"key": {
"name": "key",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
}
},
"views": {},
"enums": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"indexes": {}
}
}

View File

@@ -8,6 +8,13 @@
"when": 1787000672259,
"tag": "0000_init",
"breakpoints": true
},
{
"idx": 1,
"version": "6",
"when": 1787005028172,
"tag": "0001_labs",
"breakpoints": true
}
]
}

View File

@@ -1,4 +1,4 @@
import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
import { integer, real, sqliteTable, text } from "drizzle-orm/sqlite-core";
export const settings = sqliteTable("settings", {
key: text("key").primaryKey(),
@@ -10,3 +10,37 @@ export const sessions = sqliteTable("sessions", {
createdAt: integer("created_at").notNull(),
expiresAt: integer("expires_at").notNull(),
});
export const labDrafts = sqliteTable("lab_drafts", {
id: text("id").primaryKey(),
filename: text("filename").notNull(),
filePath: text("file_path").notNull(),
status: text("status").notNull(), // pending | confirmed | discarded
extracted: text("extracted"),
error: text("error"),
createdAt: integer("created_at").notNull(),
});
export const labDraws = sqliteTable("lab_draws", {
id: text("id").primaryKey(),
collectedAt: text("collected_at").notNull(), // ISO date YYYY-MM-DD
labName: text("lab_name"),
draftId: text("draft_id"),
createdAt: integer("created_at").notNull(),
});
export const biomarkers = sqliteTable("biomarkers", {
id: integer("id").primaryKey({ autoIncrement: true }),
drawId: text("draw_id").notNull(),
panel: text("panel").notNull(),
name: text("name").notNull(),
marker: text("marker").notNull(),
analyteKey: text("analyte_key"),
value: text("value").notNull(),
valueNum: real("value_num"),
unit: text("unit"),
referenceRange: text("reference_range"),
flagged: integer("flagged").notNull().default(0),
valueCanonical: real("value_canonical"),
canonicalUnit: text("canonical_unit"),
});

View File

@@ -0,0 +1,21 @@
import { describe, expect, test } from "bun:test";
import { mkdtempSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { openDb } from "../src/db";
import { biomarkers, labDraws } from "../src/db/schema";
describe("labs schema", () => {
test("draw + biomarker round-trip", async () => {
const db = openDb(mkdtempSync(join(tmpdir(), "helios-")));
await db.insert(labDraws).values({ id: "d1", collectedAt: "2026-01-15", labName: "Acme Lab", draftId: null, createdAt: 1 });
await db.insert(biomarkers).values({
drawId: "d1", panel: "lipids", name: "LDL Cholesterol", marker: "ldl", analyteKey: "ldl",
value: "3.1", valueNum: 3.1, unit: "mmol/L", referenceRange: "< 3.4", flagged: 0,
valueCanonical: 3.1, canonicalUnit: "mmol/L",
});
const rows = await db.select().from(biomarkers);
expect(rows).toHaveLength(1);
expect(rows[0].marker).toBe("ldl");
});
});