File size: 1,481 Bytes
938c50a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import { closeSync, existsSync, openSync, readFileSync, readSync } from "node:fs";
import { join } from "node:path";
import type { DecisionCase, Family } from "./types";

/** a case's head (everything but the conversation) and where its line sits in the family file */
export interface CaseRow {
	head: Omit<DecisionCase, "conversation">;
	offset: number;
	length: number;
}

/** reads only each line's head, the conversation is last and can be megabytes */
export function indexCases(dir: string, family: Family): CaseRow[] {
	const path = join(dir, `${family}.jsonl`);
	if (!existsSync(path)) return [];
	const buffer = readFileSync(path);
	const marker = Buffer.from(',"conversation":');
	const rows: CaseRow[] = [];
	let start = 0;
	while (start < buffer.length) {
		let end = buffer.indexOf(10, start);
		if (end === -1) end = buffer.length;
		const cut = buffer.indexOf(marker, start);
		if (cut !== -1 && cut < end) {
			const head = JSON.parse(`${buffer.subarray(start, cut).toString("utf8")}}`);
			rows.push({ head, offset: start, length: end - start });
		}
		start = end + 1;
	}
	return rows;
}

export function readCaseAt(
	dir: string,
	family: Family,
	row: Pick<CaseRow, "offset" | "length">
): DecisionCase {
	const fd = openSync(join(dir, `${family}.jsonl`), "r");
	try {
		const buffer = Buffer.alloc(row.length);
		readSync(fd, buffer, 0, row.length, row.offset);
		return JSON.parse(buffer.toString("utf8")) as DecisionCase;
	} finally {
		closeSync(fd);
	}
}