mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
fix: sqlite time to number
This commit is contained in:
parent
75c7fd6623
commit
a4453b79bb
9 changed files with 23 additions and 33 deletions
|
|
@ -10,7 +10,7 @@ export interface SessionSearchOptions {
|
|||
export interface SessionSearchHit<TMetadata extends SessionMetadata = SessionMetadata> {
|
||||
metadata: TMetadata;
|
||||
entryId: string;
|
||||
timestamp: string;
|
||||
timestamp: number;
|
||||
snippet?: string;
|
||||
score?: number;
|
||||
}
|
||||
|
|
@ -53,7 +53,7 @@ class ScanningSessionSearch<TMetadata extends SessionMetadata = SessionMetadata>
|
|||
hits.push({
|
||||
metadata,
|
||||
entryId: entry.id,
|
||||
timestamp: new Date(entry.timestamp).toISOString(),
|
||||
timestamp: entry.timestamp,
|
||||
snippet: payload,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
CREATE TABLE IF NOT EXISTS sessions (
|
||||
id TEXT PRIMARY KEY,
|
||||
created_at TEXT NOT NULL,
|
||||
created_at INTEGER NOT NULL,
|
||||
cwd TEXT NOT NULL,
|
||||
parent_session_id TEXT NULL,
|
||||
metadata TEXT NULL
|
||||
|
|
@ -15,7 +15,7 @@ CREATE TABLE IF NOT EXISTS entries (
|
|||
id TEXT NOT NULL,
|
||||
parent_id TEXT NULL,
|
||||
type TEXT NOT NULL,
|
||||
timestamp TEXT NOT NULL,
|
||||
timestamp INTEGER NOT NULL,
|
||||
payload TEXT NOT NULL,
|
||||
PRIMARY KEY (session_id, id),
|
||||
UNIQUE (session_id, seq)
|
||||
|
|
@ -71,7 +71,7 @@ CREATE TABLE IF NOT EXISTS records (
|
|||
run_id TEXT NULL,
|
||||
type TEXT NOT NULL,
|
||||
op_kind TEXT NULL,
|
||||
timestamp TEXT NOT NULL,
|
||||
timestamp INTEGER NOT NULL,
|
||||
payload TEXT NOT NULL,
|
||||
PRIMARY KEY (session_id, id),
|
||||
UNIQUE (session_id, seq)
|
||||
|
|
|
|||
|
|
@ -175,14 +175,6 @@ function configureSqliteDatabase(db: SqliteDatabase): void {
|
|||
sql`PRAGMA busy_timeout=5000`.exec(db);
|
||||
}
|
||||
|
||||
function timestampToText(timestamp: number): string {
|
||||
return new Date(timestamp).toISOString();
|
||||
}
|
||||
|
||||
function timestampFromText(timestamp: string): number {
|
||||
return Date.parse(timestamp);
|
||||
}
|
||||
|
||||
function entryRowFromCached(row: CachedBranchEntryRow): EntryRow {
|
||||
return { ...row, seq: row.entry_seq, type: row.type as Entry["type"] };
|
||||
}
|
||||
|
|
@ -198,9 +190,7 @@ function readObjectPayload(row: EntryRow): Record<string, unknown> {
|
|||
function decodeEntry(row: EntryRow): Entry {
|
||||
try {
|
||||
const payload = readObjectPayload(row);
|
||||
const timestamp = timestampFromText(row.timestamp);
|
||||
if (!Number.isFinite(timestamp)) throw new Error(`Invalid timestamp ${row.timestamp}`);
|
||||
const base = { id: row.id, seq: row.seq, parentId: row.parent_id, timestamp };
|
||||
const base = { id: row.id, seq: row.seq, parentId: row.parent_id, timestamp: row.timestamp };
|
||||
switch (row.type) {
|
||||
case "message":
|
||||
if (typeof payload.message !== "object" || payload.message === null) throw new Error("Missing message");
|
||||
|
|
@ -283,14 +273,12 @@ function recordOpKind(record: NewRecord): string | undefined {
|
|||
return record.type === "operation_started" ? record.intent.kind : undefined;
|
||||
}
|
||||
|
||||
function decodeRecord(row: { seq: number; timestamp: string; payload: string }): LaneRecord {
|
||||
function decodeRecord(row: { seq: number; timestamp: number; payload: string }): LaneRecord {
|
||||
try {
|
||||
const timestamp = timestampFromText(row.timestamp);
|
||||
if (!Number.isFinite(timestamp)) throw new Error(`Invalid timestamp ${row.timestamp}`);
|
||||
return {
|
||||
...(JSON.parse(row.payload) as object),
|
||||
seq: row.seq,
|
||||
timestamp,
|
||||
timestamp: row.timestamp,
|
||||
} as LaneRecord;
|
||||
} catch (error) {
|
||||
throw new SessionError(
|
||||
|
|
@ -476,7 +464,7 @@ class SqliteSessionStorage implements SessionStorage<SqliteSessionMetadata> {
|
|||
id: committed.id,
|
||||
parentId: committed.parentId,
|
||||
type: committed.type,
|
||||
timestamp: timestampToText(committed.timestamp),
|
||||
timestamp: committed.timestamp,
|
||||
payload: JSON.stringify(entryPayload(committed)),
|
||||
});
|
||||
setLaneLeaf(this.db, this.metadata.id, lane, committed.id);
|
||||
|
|
@ -514,7 +502,7 @@ class SqliteSessionStorage implements SessionStorage<SqliteSessionMetadata> {
|
|||
runId: recordRunId(record),
|
||||
type: record.type,
|
||||
opKind: recordOpKind(record),
|
||||
timestamp: timestampToText(committed.timestamp),
|
||||
timestamp: committed.timestamp,
|
||||
payload: JSON.stringify(record),
|
||||
});
|
||||
if (record.type === "operation_finished") {
|
||||
|
|
@ -739,7 +727,7 @@ export class SqliteSessionRepository
|
|||
const lease = db.transaction(() => {
|
||||
insertSessionRow(db, {
|
||||
id,
|
||||
createdAt: timestampToText(createdAt),
|
||||
createdAt,
|
||||
cwd: options.cwd,
|
||||
parentSessionId: options.parentSessionId,
|
||||
metadata: options.metadata,
|
||||
|
|
@ -870,7 +858,7 @@ export class SqliteSessionRepository
|
|||
lease = db.transaction(() => {
|
||||
insertSessionRow(db, {
|
||||
id,
|
||||
createdAt: timestampToText(createdAt),
|
||||
createdAt,
|
||||
cwd: options.cwd,
|
||||
parentSessionId: options.parentSessionId ?? source.id,
|
||||
metadata,
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ class SqliteSessionSearch implements SessionSearch<SqliteSessionMetadata> {
|
|||
WHERE f.session_id = s.id AND f.kind = 'name' AND f.key IS NULL
|
||||
)
|
||||
WHERE session_search_fts MATCH ${query} AND (${cwd} IS NULL OR s.cwd = ${cwd})
|
||||
ORDER BY score`.all<SessionRow & { entry_id: string; timestamp: string; score: number }>(db);
|
||||
ORDER BY score`.all<SessionRow & { entry_id: string; timestamp: number; score: number }>(db);
|
||||
const path = await this.getDatabasePath();
|
||||
return rows.map((row) => ({
|
||||
metadata: decodeSessionMetadata(row, path),
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export interface CachedBranchEntryRow {
|
|||
entry_seq: number;
|
||||
parent_id: string | null;
|
||||
type: Entry["type"];
|
||||
timestamp: string;
|
||||
timestamp: number;
|
||||
payload: string;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ export interface EntryRow {
|
|||
id: string;
|
||||
parent_id: string | null;
|
||||
type: Entry["type"];
|
||||
timestamp: string;
|
||||
timestamp: number;
|
||||
payload: string;
|
||||
}
|
||||
|
||||
|
|
@ -17,7 +17,7 @@ export interface NewEntryRow {
|
|||
id: string;
|
||||
parentId: string | null;
|
||||
type: Entry["type"];
|
||||
timestamp: string;
|
||||
timestamp: number;
|
||||
payload: string;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ export interface RecordRow {
|
|||
run_id: string | null;
|
||||
type: string;
|
||||
op_kind: string | null;
|
||||
timestamp: string;
|
||||
timestamp: number;
|
||||
payload: string;
|
||||
}
|
||||
|
||||
|
|
@ -21,7 +21,7 @@ export interface NewRecordRow {
|
|||
runId?: string;
|
||||
type: string;
|
||||
opKind?: string;
|
||||
timestamp: string;
|
||||
timestamp: number;
|
||||
payload: string;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import type { SqliteDatabase, SqliteSessionMetadata } from "../types.ts";
|
|||
|
||||
export interface SessionRow {
|
||||
id: string;
|
||||
created_at: string;
|
||||
created_at: number;
|
||||
metadata: string | null;
|
||||
cwd: string;
|
||||
parent_session_id: string | null;
|
||||
|
|
@ -14,7 +14,7 @@ export interface SessionRow {
|
|||
|
||||
export interface NewSessionRow {
|
||||
id: string;
|
||||
createdAt: string;
|
||||
createdAt: number;
|
||||
cwd: string;
|
||||
parentSessionId?: string;
|
||||
metadata?: Record<string, unknown>;
|
||||
|
|
@ -121,7 +121,7 @@ export function decodeSessionMetadata(row: SessionRow, path: string): SqliteSess
|
|||
const name = row.has_session_name === 0 ? undefined : parseSessionName(row.session_name, row.id);
|
||||
return {
|
||||
id: row.id,
|
||||
createdAt: Date.parse(row.created_at),
|
||||
createdAt: row.created_at,
|
||||
...(name === undefined ? {} : { name }),
|
||||
cwd: row.cwd,
|
||||
path,
|
||||
|
|
|
|||
|
|
@ -30,8 +30,10 @@ describe("SQLite FTS5 session search", () => {
|
|||
await expect(search.search({ text: "auth", cwd: root })).resolves.toEqual([
|
||||
expect.objectContaining({
|
||||
entryId,
|
||||
timestamp: expect.any(Number),
|
||||
metadata: expect.objectContaining({
|
||||
id: "included",
|
||||
createdAt: expect.any(Number),
|
||||
name: "Canonical name",
|
||||
metadata: { name: "application-owned" },
|
||||
}),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue