fix(test): use awaitable add() in history storage compat test

This commit is contained in:
can1357
2026-04-08 12:43:36 +02:00
parent 88595b541c
commit 468601935c
3 changed files with 62 additions and 20 deletions
@@ -19,12 +19,48 @@ type HistoryRow = {
const SQLITE_NOW_EPOCH = "CAST(strftime('%s','now') AS INTEGER)";
class AsyncDrain<T> {
#queue?: T[];
#promise = Promise.resolve();
constructor(readonly delayMs: number = 0) {}
push(value: T, hnd: (values: T[]) => Promise<void> | void): Promise<void> {
let queue = this.#queue;
if (!queue) {
queue = [];
this.#queue = [];
this.#promise = new Promise((resolve, reject) => {
const exec = () => {
try {
if (this.#queue === queue) {
this.#queue = undefined;
}
resolve(hnd(queue!));
} catch (error) {
reject(error);
}
};
if (this.delayMs > 0) {
setTimeout(exec, this.delayMs);
} else {
queueMicrotask(exec);
}
});
}
queue.push(value);
return this.#promise;
}
}
export class HistoryStorage {
#db: Database;
static #instance?: HistoryStorage;
#drain = new AsyncDrain<Pick<HistoryEntry, "prompt" | "cwd">>(100);
// Prepared statements
#insertStmt: Statement;
#insertRowStmt: Statement;
#recentStmt: Statement;
#searchStmt: Statement;
#lastPromptStmt: Statement;
@@ -71,7 +107,6 @@ CREATE TRIGGER IF NOT EXISTS history_ai AFTER INSERT ON history BEGIN
}
}
this.#insertStmt = this.#db.prepare("INSERT INTO history (prompt, cwd) VALUES (?, ?)");
this.#recentStmt = this.#db.prepare(
"SELECT id, prompt, created_at, cwd FROM history ORDER BY created_at DESC, id DESC LIMIT ?",
);
@@ -80,6 +115,8 @@ CREATE TRIGGER IF NOT EXISTS history_ai AFTER INSERT ON history BEGIN
);
this.#lastPromptStmt = this.#db.prepare("SELECT prompt FROM history ORDER BY id DESC LIMIT 1");
this.#insertRowStmt = this.#db.prepare("INSERT INTO history (prompt, cwd) VALUES (?, ?)");
const last = this.#lastPromptStmt.get() as { prompt?: string } | undefined;
this.#lastPromptCache = last?.prompt ?? null;
}
@@ -91,19 +128,21 @@ CREATE TRIGGER IF NOT EXISTS history_ai AFTER INSERT ON history BEGIN
return HistoryStorage.#instance;
}
add(prompt: string, cwd?: string): void {
const trimmed = prompt.trim();
if (!trimmed) return;
if (this.#lastPromptCache === trimmed) return;
this.#lastPromptCache = trimmed;
setImmediate(() => {
try {
this.#insertStmt.run(trimmed, cwd ?? null);
} catch (error) {
logger.error("HistoryStorage add failed", { error: String(error) });
#insertBatch(rows: Array<Pick<HistoryEntry, "prompt" | "cwd">>): void {
this.#db.transaction((rows: Array<Pick<HistoryEntry, "prompt" | "cwd">>) => {
for (const row of rows) {
this.#insertRowStmt.run(row.prompt, row.cwd ?? null);
}
})(rows);
}
add(prompt: string, cwd?: string): Promise<void> {
const trimmed = prompt.trim();
if (!trimmed) return Promise.resolve();
if (this.#lastPromptCache === trimmed) return Promise.resolve();
this.#lastPromptCache = trimmed;
return this.#drain.push({ prompt: trimmed, cwd: cwd ?? undefined }, rows => {
this.#insertBatch(rows);
});
}
@@ -46,9 +46,7 @@ it("migrates legacy history schema away from unixepoch defaults", async () => {
legacyDb.close();
const storage = HistoryStorage.open(dbPath);
storage.add("new prompt", "/tmp/new");
// add() defers the INSERT via setImmediate; drain the macrotask queue
await new Promise<void>(resolve => setImmediate(resolve));
await storage.add("new prompt", "/tmp/new");
const db = new Database(dbPath, { readonly: true });
try {
+8 -3
View File
@@ -1,4 +1,4 @@
import { getProjectDir } from "@oh-my-pi/pi-utils";
import { getProjectDir, logger } from "@oh-my-pi/pi-utils";
import type { AutocompleteProvider, CombinedAutocompleteProvider } from "../autocomplete";
import { BracketedPasteHandler } from "../bracketed-paste";
import { getKeybindings, type KeybindingsManager } from "../keybindings";
@@ -304,7 +304,7 @@ interface HistoryEntry {
}
interface HistoryStorage {
add(prompt: string, cwd?: string): void;
add(prompt: string, cwd?: string): Promise<void>;
getRecent(limit: number): HistoryEntry[];
}
@@ -478,7 +478,12 @@ export class Editor implements Component, Focusable {
this.#history.pop();
}
this.#historyStorage?.add(trimmed, getProjectDir());
const stor = this.#historyStorage;
if (stor) {
stor.add(trimmed, getProjectDir()).catch(error => {
logger.error("HistoryStorage add failed", { error: String(error) });
});
}
}
#isEditorEmpty(): boolean {