1import {
2 PullRequestDiffStat,
3 PullRequestListStatsInput,
4 type PullRequestListStatsResult,
5 type PullRequestRef,
6} from "@t3tools/contracts";
7import * as Effect from "effect/Effect";
8import * as Option from "effect/Option";
9import * as Schema from "effect/Schema";
10import { persistQuery, type QueryPersistence } from "./queryPersistence.ts";
11
12const requestKey = Schema.fromJsonString(Schema.Tuple([Schema.String, PullRequestListStatsInput]));
13const statKey = (ref: PullRequestRef) =>
14 JSON.stringify(["pull-request-stat", ref.projectId, ref.host ?? "", ref.repository, ref.number]);
15
16/** Visible rows are batched differently after a restart, so store their counts individually. */
17export function persistPullRequestStats(): QueryPersistence<PullRequestListStatsResult> {
18 const row = persistQuery(PullRequestDiffStat);
19 return {
20 load: (environmentId, key) =>
21 Effect.gen(function* () {
22 const [, input] = yield* Schema.decodeEffect(requestKey)(key);
23 const rows = yield* Effect.forEach(input.refs, (ref) =>
24 row.load(environmentId, statKey(ref)),
25 );
26 const stats = rows.flatMap((value) => (Option.isSome(value) ? [value.value] : []));
27 return stats.length ? Option.some({ stats }) : Option.none();
28 }).pipe(Effect.orElseSucceed(() => Option.none())),
29 save: (environmentId, key, result) =>
30 Effect.gen(function* () {
31 const [, input] = yield* Schema.decodeEffect(requestKey)(key);
32 yield* Effect.forEach(result.stats, (stat) => {
33 const ref = input.refs.find(
34 (ref) =>
35 ref.projectId === stat.projectId &&
36 ref.repository === stat.repository &&
37 ref.number === stat.number,
38 );
39 return ref ? row.save(environmentId, statKey(ref), stat) : Effect.void;
40 });
41 }).pipe(Effect.ignore),
42 };
43}