100 lines · 3.5 KB · TypeScript
RawDownload
import { EventId, ThreadId } from "@t3tools/contracts";import { assert, it } from "@effect/vitest";import * as Effect from "effect/Effect";import * as Layer from "effect/Layer";import * as SqlClient from "effect/unstable/sql/SqlClient"; import { ProjectionThreadActivityRepository } from "../Services/ProjectionThreadActivities.ts";import { ProjectionThreadActivityRepositoryLive } from "./ProjectionThreadActivities.ts";import { SqlitePersistenceMemory } from "./Sqlite.ts"; const layer = it.layer(  ProjectionThreadActivityRepositoryLive.pipe(Layer.provideMerge(SqlitePersistenceMemory)),); layer("ProjectionThreadActivityRepository", (it) => {  it.effect("reads only the latest matching task activity", () =>    Effect.gen(function* () {      const repository = yield* ProjectionThreadActivityRepository;      const sql = yield* SqlClient.SqlClient;      const threadId = ThreadId.make("thread-latest-task-activity");       yield* sql`        INSERT INTO projection_thread_activities (          activity_id, thread_id, turn_id, tone, kind, summary, payload_json, sequence, created_at        )        VALUES          (            'activity-task-unrelated-tool', ${threadId}, NULL, 'tool', 'tool.completed',            'large tool output', 'not-json', 1, '2026-03-01T00:00:00.000Z'          ),          (            'activity-task-started', ${threadId}, NULL, 'info', 'task.started',            'started', '{"taskId":"task-1","title":"Initial title"}', 2,            '2026-03-01T00:00:01.000Z'          ),          (            'activity-task-progress', ${threadId}, NULL, 'info', 'task.progress',            'progress', '{"taskId":"task-1","title":"Updated title"}', 3,            '2026-03-01T00:00:02.000Z'          ),          (            'activity-task-other', ${threadId}, NULL, 'info', 'task.progress',            'other', '{"taskId":"task-2","title":"Other title"}', 4,            '2026-03-01T00:00:03.000Z'          )      `;       yield* repository.upsert({        activityId: EventId.make("activity-task-untitled"),        threadId,        turnId: null,        tone: "info",        kind: "task.progress",        summary: "Still running",        payload: { taskId: "task-1" },        sequence: 5,        createdAt: "2026-03-01T00:00:04.000Z",      });      yield* repository.upsert({        activityId: EventId.make("activity-task-blank-title"),        threadId,        turnId: null,        tone: "info",        kind: "task.progress",        summary: "Still running",        payload: { taskId: "task-1", title: " \t\n\u00a0" },        sequence: 6,        createdAt: "2026-03-01T00:00:05.000Z",      });       const recent = yield* repository.listByThreadId({        threadId,        activityKinds: ["task.progress"],        limit: 2,      });      assert.deepEqual(        recent.map((entry) => entry.activityId),        ["activity-task-untitled", "activity-task-blank-title"],      );       const activity = yield* repository.getLatestTaskActivity({        threadId,        taskId: "task-1",      });      assert.equal(activity._tag, "Some");      if (activity._tag === "Some") {        assert.equal(activity.value.activityId, EventId.make("activity-task-progress"));        assert.deepEqual(activity.value.payload, {          taskId: "task-1",          title: "Updated title",        });      }       assert.equal(        (yield* repository.getLatestTaskActivity({ threadId, taskId: "missing" }))._tag,        "None",      );    }),  );});