diff --git a/src/db.ts b/src/db.ts index 531b716..45fe31f 100644 --- a/src/db.ts +++ b/src/db.ts @@ -5,6 +5,21 @@ import type { Device, OutputLog, Prompt, Session } from "./types"; let db: Database; +// Prepared statements - initialized once in initDb() +let createDeviceStmt: ReturnType; +let getDeviceBySecretStmt: ReturnType; +let updateLastSeenStmt: ReturnType; +let createSessionStmt: ReturnType; +let getSessionStmt: ReturnType; +let endSessionStmt: ReturnType; +let getActiveSessionsStmt: ReturnType; +let createPromptStmt: ReturnType; +let getPromptStmt: ReturnType; +let respondToPromptStmt: ReturnType; +let getPendingPromptsStmt: ReturnType; +let appendOutputStmt: ReturnType; +let getSessionOutputStmt: ReturnType; + 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[]; }