Fix prepared statements to prepare once at init

This commit is contained in:
Jared Miller 2026-01-28 11:18:44 -05:00
parent 596b0fd013
commit 76a81666a2
Signed by: shmup
GPG key ID: 22B5C6D66A38B06C

125
src/db.ts
View file

@ -5,6 +5,21 @@ import type { Device, OutputLog, Prompt, Session } from "./types";
let db: Database;
// Prepared statements - initialized once in initDb()
let createDeviceStmt: ReturnType<Database["prepare"]>;
let getDeviceBySecretStmt: ReturnType<Database["prepare"]>;
let updateLastSeenStmt: ReturnType<Database["prepare"]>;
let createSessionStmt: ReturnType<Database["prepare"]>;
let getSessionStmt: ReturnType<Database["prepare"]>;
let endSessionStmt: ReturnType<Database["prepare"]>;
let getActiveSessionsStmt: ReturnType<Database["prepare"]>;
let createPromptStmt: ReturnType<Database["prepare"]>;
let getPromptStmt: ReturnType<Database["prepare"]>;
let respondToPromptStmt: ReturnType<Database["prepare"]>;
let getPendingPromptsStmt: ReturnType<Database["prepare"]>;
let appendOutputStmt: ReturnType<Database["prepare"]>;
let getSessionOutputStmt: ReturnType<Database["prepare"]>;
export function initDb(path = "claude-remote.db"): Database {
db = new Database(path);
@ -47,126 +62,108 @@ export function initDb(path = "claude-remote.db"): Database {
);
`);
// Prepare all statements once
createDeviceStmt = db.prepare(
"INSERT INTO devices (secret, name, created_at, last_seen) VALUES (?, ?, ?, ?) RETURNING *",
);
getDeviceBySecretStmt = db.prepare("SELECT * FROM devices WHERE secret = ?");
updateLastSeenStmt = db.prepare(
"UPDATE devices SET last_seen = ? WHERE id = ?",
);
createSessionStmt = db.prepare(
"INSERT INTO sessions (device_id, started_at, cwd, command) VALUES (?, ?, ?, ?) RETURNING *",
);
getSessionStmt = db.prepare("SELECT * FROM sessions WHERE id = ?");
endSessionStmt = db.prepare("UPDATE sessions SET ended_at = ? WHERE id = ?");
getActiveSessionsStmt = db.prepare(
"SELECT * FROM sessions WHERE ended_at IS NULL ORDER BY started_at DESC",
);
createPromptStmt = db.prepare(
"INSERT INTO prompts (session_id, created_at, prompt_text) VALUES (?, ?, ?) RETURNING *",
);
getPromptStmt = db.prepare("SELECT * FROM prompts WHERE id = ?");
respondToPromptStmt = db.prepare(
"UPDATE prompts SET response = ?, responded_at = ? WHERE id = ?",
);
getPendingPromptsStmt = db.prepare(
"SELECT * FROM prompts WHERE response IS NULL ORDER BY created_at ASC",
);
appendOutputStmt = db.prepare(
"INSERT INTO output_log (session_id, timestamp, line) VALUES (?, ?, ?)",
);
getSessionOutputStmt = db.prepare(
"SELECT * FROM output_log WHERE session_id = ? ORDER BY timestamp ASC",
);
return db;
}
// Device functions
const createDeviceStmt = () =>
db.prepare(
"INSERT INTO devices (secret, name, created_at, last_seen) VALUES (?, ?, ?, ?) RETURNING *",
);
export function createDevice(
secret: string,
name: string | null = null,
): Device {
const now = Date.now();
return createDeviceStmt().get(secret, name, now, now) as Device;
return createDeviceStmt.get(secret, name, now, now) as Device;
}
const getDeviceBySecretStmt = () =>
db.prepare("SELECT * FROM devices WHERE secret = ?");
export function getDeviceBySecret(secret: string): Device | null {
return (getDeviceBySecretStmt().get(secret) as Device) ?? null;
return (getDeviceBySecretStmt.get(secret) as Device) ?? null;
}
const updateLastSeenStmt = () =>
db.prepare("UPDATE devices SET last_seen = ? WHERE id = ?");
export function updateLastSeen(deviceId: number): void {
updateLastSeenStmt().run(Date.now(), deviceId);
updateLastSeenStmt.run(Date.now(), deviceId);
}
// Session functions
const createSessionStmt = () =>
db.prepare(
"INSERT INTO sessions (device_id, started_at, cwd, command) VALUES (?, ?, ?, ?) RETURNING *",
);
export function createSession(
deviceId: number,
cwd: string | null = null,
command: string | null = null,
): Session {
const now = Date.now();
return createSessionStmt().get(deviceId, now, cwd, command) as Session;
return createSessionStmt.get(deviceId, now, cwd, command) as Session;
}
const getSessionStmt = () => db.prepare("SELECT * FROM sessions WHERE id = ?");
export function getSession(sessionId: number): Session | null {
return (getSessionStmt().get(sessionId) as Session) ?? null;
return (getSessionStmt.get(sessionId) as Session) ?? null;
}
const endSessionStmt = () =>
db.prepare("UPDATE sessions SET ended_at = ? WHERE id = ?");
export function endSession(sessionId: number): void {
endSessionStmt().run(Date.now(), sessionId);
endSessionStmt.run(Date.now(), sessionId);
}
const getActiveSessionsStmt = () =>
db.prepare(
"SELECT * FROM sessions WHERE ended_at IS NULL ORDER BY started_at DESC",
);
export function getActiveSessions(): Session[] {
return getActiveSessionsStmt().all() as Session[];
return getActiveSessionsStmt.all() as Session[];
}
// Prompt functions
const createPromptStmt = () =>
db.prepare(
"INSERT INTO prompts (session_id, created_at, prompt_text) VALUES (?, ?, ?) RETURNING *",
);
export function createPrompt(sessionId: number, promptText: string): Prompt {
const now = Date.now();
return createPromptStmt().get(sessionId, now, promptText) as Prompt;
return createPromptStmt.get(sessionId, now, promptText) as Prompt;
}
const getPromptStmt = () => db.prepare("SELECT * FROM prompts WHERE id = ?");
export function getPrompt(promptId: number): Prompt | null {
return (getPromptStmt().get(promptId) as Prompt) ?? null;
return (getPromptStmt.get(promptId) as Prompt) ?? null;
}
const respondToPromptStmt = () =>
db.prepare("UPDATE prompts SET response = ?, responded_at = ? WHERE id = ?");
export function respondToPrompt(promptId: number, response: string): void {
respondToPromptStmt().run(response, Date.now(), promptId);
respondToPromptStmt.run(response, Date.now(), promptId);
}
const getPendingPromptsStmt = () =>
db.prepare(
"SELECT * FROM prompts WHERE response IS NULL ORDER BY created_at ASC",
);
export function getPendingPrompts(): Prompt[] {
return getPendingPromptsStmt().all() as Prompt[];
return getPendingPromptsStmt.all() as Prompt[];
}
// OutputLog functions
const appendOutputStmt = () =>
db.prepare(
"INSERT INTO output_log (session_id, timestamp, line) VALUES (?, ?, ?)",
);
export function appendOutput(sessionId: number, line: string): void {
appendOutputStmt().run(sessionId, Date.now(), line);
appendOutputStmt.run(sessionId, Date.now(), line);
}
const getSessionOutputStmt = () =>
db.prepare(
"SELECT * FROM output_log WHERE session_id = ? ORDER BY timestamp ASC",
);
export function getSessionOutput(sessionId: number): OutputLog[] {
return getSessionOutputStmt().all(sessionId) as OutputLog[];
return getSessionOutputStmt.all(sessionId) as OutputLog[];
}