Buckets:
| import { and, asc, desc, eq, gt, gte, ne, or } from "drizzle-orm" | |
| import { Effect, Schema } from "effect" | |
| import { Database } from "../database/database" | |
| import { MessageDecodeError } from "./error" | |
| import { SessionMessage } from "./message" | |
| import { SessionSchema } from "./schema" | |
| import { SessionContextEpochTable, SessionMessageTable } from "./sql" | |
| type DatabaseService = Database.Interface["db"] | |
| const decode = Schema.decodeUnknownEffect(SessionMessage.Message) | |
| const latestCompaction = Effect.fnUntraced(function* (db: DatabaseService, sessionID: SessionSchema.ID) { | |
| return yield* db | |
| .select() | |
| .from(SessionMessageTable) | |
| .where(and(eq(SessionMessageTable.session_id, sessionID), eq(SessionMessageTable.type, "compaction"))) | |
| .orderBy(desc(SessionMessageTable.seq)) | |
| .limit(1) | |
| .get() | |
| .pipe(Effect.orDie) | |
| }) | |
| const messageRows = Effect.fnUntraced(function* ( | |
| db: DatabaseService, | |
| sessionID: SessionSchema.ID, | |
| compaction: { readonly seq: number } | undefined, | |
| baselineSeq?: number, | |
| ) { | |
| const rows = yield* db | |
| .select() | |
| .from(SessionMessageTable) | |
| .where( | |
| and( | |
| eq(SessionMessageTable.session_id, sessionID), | |
| compaction | |
| ? or( | |
| gte(SessionMessageTable.seq, compaction.seq), | |
| baselineSeq === undefined | |
| ? undefined | |
| : and(eq(SessionMessageTable.type, "system"), gt(SessionMessageTable.seq, baselineSeq)), | |
| ) | |
| : undefined, | |
| baselineSeq === undefined | |
| ? undefined | |
| : or(ne(SessionMessageTable.type, "system"), gt(SessionMessageTable.seq, baselineSeq)), | |
| ), | |
| ) | |
| .orderBy(asc(SessionMessageTable.seq)) | |
| .all() | |
| .pipe(Effect.orDie) | |
| return rows | |
| }) | |
| const decodeMessageRow = (row: typeof SessionMessageTable.$inferSelect) => | |
| decode({ ...row.data, id: row.id, type: row.type }).pipe( | |
| Effect.mapError( | |
| () => | |
| new MessageDecodeError({ | |
| sessionID: SessionSchema.ID.make(row.session_id), | |
| messageID: SessionMessage.ID.make(row.id), | |
| }), | |
| ), | |
| ) | |
| export const load = Effect.fn("SessionHistory.load")(function* (db: DatabaseService, sessionID: SessionSchema.ID) { | |
| const [epoch, compaction] = yield* Effect.all( | |
| [ | |
| db | |
| .select({ baselineSeq: SessionContextEpochTable.baseline_seq }) | |
| .from(SessionContextEpochTable) | |
| .where(eq(SessionContextEpochTable.session_id, sessionID)) | |
| .get() | |
| .pipe(Effect.orDie), | |
| latestCompaction(db, sessionID), | |
| ], | |
| { concurrency: "unbounded" }, | |
| ) | |
| return yield* Effect.forEach(yield* messageRows(db, sessionID, compaction, epoch?.baselineSeq), decodeMessageRow) | |
| }) | |
| export const loadForRunner = Effect.fn("SessionHistory.loadForRunner")(function* ( | |
| db: DatabaseService, | |
| sessionID: SessionSchema.ID, | |
| baselineSeq: number, | |
| ) { | |
| return (yield* entriesForRunner(db, sessionID, baselineSeq)).map((entry) => entry.message) | |
| }) | |
| export const entriesForRunner = Effect.fn("SessionHistory.entriesForRunner")(function* ( | |
| db: DatabaseService, | |
| sessionID: SessionSchema.ID, | |
| baselineSeq: number, | |
| ) { | |
| const rows = yield* messageRows(db, sessionID, yield* latestCompaction(db, sessionID), baselineSeq) | |
| return yield* Effect.forEach(rows, (row) => | |
| decodeMessageRow(row).pipe(Effect.map((message) => ({ seq: row.seq, message }))), | |
| ) | |
| }) | |
| export * as SessionHistory from "./history" | |
Xet Storage Details
- Size:
- 3.41 kB
- Xet hash:
- 078f12eaacebad168811e1e813370b0fbeb3c12baa747b72123737061cf30c71
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.