Open History to see the last commit
1import * as Context from "effect/Context";
2import * as NodeSqliteClient from "@t3tools/shared/nodeSqliteClient";
3import * as Effect from "effect/Effect";
4import * as Layer from "effect/Layer";
5import * as Option from "effect/Option";
6import * as Schema from "effect/Schema";
7import * as SqlClient from "effect/sql/SqlClient";
8import * as SqlSchema from "effect/sql/SqlSchema";
9
10import { PullRequestReviewGuide, ThreadPullRequestKey } from "@t3tools/contracts";
11
12import {
13 PersistenceDecodeError,
14 PersistenceSqlError,
15 type PullRequestReviewGuideRepositoryError,
16} from "./Errors.ts";
17
18const GuideRow = Schema.Struct({
19 guide: Schema.fromJsonString(PullRequestReviewGuide),
20});
21
22export class PullRequestReviewGuideRepository extends Context.Service<
23 PullRequestReviewGuideRepository,
24 {
25 readonly get: (
26 key: ThreadPullRequestKey,
27 ) => Effect.Effect<
28 Option.Option<PullRequestReviewGuide>,
29 PullRequestReviewGuideRepositoryError
30 >;
31 readonly put: (
32 key: ThreadPullRequestKey,
33 guide: PullRequestReviewGuide,
34 ) => Effect.Effect<void, PullRequestReviewGuideRepositoryError>;
35 }
36>()("t3/persistence/PullRequestReviewGuides/PullRequestReviewGuideRepository") {}
37
38const make = Effect.gen(function* () {
39 const sql = yield* SqlClient.SqlClient;
40
41 const findGuide = SqlSchema.findOneOption({
42 Request: ThreadPullRequestKey,
43 Result: GuideRow,
44 execute: ({ host, repository, number }) =>
45 sql`
46 SELECT guide_json AS "guide"
47 FROM pull_request_review_guides
48 WHERE host = ${host} AND repository = ${repository} AND number = ${number}
49 `,
50 });
51 const encodeGuide = Schema.encodeEffect(Schema.fromJsonString(PullRequestReviewGuide));
52
53 return PullRequestReviewGuideRepository.of({
54 get: Effect.fn("PullRequestReviewGuideRepository.get")(function (key) {
55 return findGuide(key).pipe(
56 NodeSqliteClient.readOnly,
57 Effect.map(Option.map((row) => row.guide)),
58 Effect.mapError((cause) =>
59 Schema.isSchemaError(cause)
60 ? PersistenceDecodeError.fromSchemaError("PullRequestReviewGuide", cause)
61 : new PersistenceSqlError({ operation: "getPullRequestReviewGuide", cause }),
62 ),
63 );
64 }),
65 put: Effect.fn("PullRequestReviewGuideRepository.put")(function (key, guide) {
66 return encodeGuide(guide).pipe(
67 Effect.mapError((cause) =>
68 PersistenceDecodeError.fromSchemaError("PullRequestReviewGuide", cause),
69 ),
70 Effect.flatMap((guideJson) =>
71 sql`
72 INSERT INTO pull_request_review_guides (host, repository, number, guide_json)
73 VALUES (${key.host}, ${key.repository}, ${key.number}, ${guideJson})
74 ON CONFLICT (host, repository, number) DO UPDATE SET guide_json = excluded.guide_json
75 `.pipe(
76 Effect.mapError(
77 (cause) => new PersistenceSqlError({ operation: "putPullRequestReviewGuide", cause }),
78 ),
79 ),
80 ),
81 Effect.asVoid,
82 );
83 }),
84 });
85});
86
87export const layer = Layer.effect(PullRequestReviewGuideRepository, make);