118 lines · 3.4 KB · TypeScript
RawDownload
import { NonNegativeInt } from "@t3tools/contracts";import * as SqlClient from "effect/unstable/sql/SqlClient";import * as SqlSchema from "effect/unstable/sql/SqlSchema";import * as Effect from "effect/Effect";import * as Layer from "effect/Layer";import * as Schema from "effect/Schema"; import { toPersistenceSqlError } from "../Errors.ts"; import {  ProjectionStateRepository,  type ProjectionStateRepositoryShape,  GetProjectionStateInput,  ProjectionState,} from "../Services/ProjectionState.ts"; const MinLastAppliedSequenceRowSchema = Schema.Struct({  minLastAppliedSequence: Schema.NullOr(NonNegativeInt),}); const makeProjectionStateRepository = Effect.gen(function* () {  const sql = yield* SqlClient.SqlClient;   const upsertProjectionStateRow = SqlSchema.void({    Request: ProjectionState,    execute: (row) =>      sql`        INSERT INTO projection_state (          projector,          last_applied_sequence,          updated_at        )        VALUES (          ${row.projector},          ${row.lastAppliedSequence},          ${row.updatedAt}        )        ON CONFLICT (projector)        DO UPDATE SET          last_applied_sequence = excluded.last_applied_sequence,          updated_at = excluded.updated_at      `,  });   const getProjectionStateRow = SqlSchema.findOneOption({    Request: GetProjectionStateInput,    Result: ProjectionState,    execute: ({ projector }) =>      sql`        SELECT          projector,          last_applied_sequence AS "lastAppliedSequence",          updated_at AS "updatedAt"        FROM projection_state        WHERE projector = ${projector}      `,  });   const listProjectionStateRows = SqlSchema.findAll({    Request: Schema.Void,    Result: ProjectionState,    execute: () =>      sql`        SELECT          projector,          last_applied_sequence AS "lastAppliedSequence",          updated_at AS "updatedAt"        FROM projection_state        ORDER BY projector ASC      `,  });   const readMinLastAppliedSequence = SqlSchema.findOne({    Request: Schema.Void,    Result: MinLastAppliedSequenceRowSchema,    execute: () =>      sql`        SELECT          MIN(last_applied_sequence) AS "minLastAppliedSequence"        FROM projection_state      `,  });   const upsert: ProjectionStateRepositoryShape["upsert"] = (row) =>    upsertProjectionStateRow(row).pipe(      Effect.mapError(toPersistenceSqlError("ProjectionStateRepository.upsert:query")),    );   const getByProjector: ProjectionStateRepositoryShape["getByProjector"] = (input) =>    getProjectionStateRow(input).pipe(      Effect.mapError(toPersistenceSqlError("ProjectionStateRepository.getByProjector:query")),    );   const listAll: ProjectionStateRepositoryShape["listAll"] = () =>    listProjectionStateRows(undefined).pipe(      Effect.mapError(toPersistenceSqlError("ProjectionStateRepository.listAll:query")),    );   const minLastAppliedSequence: ProjectionStateRepositoryShape["minLastAppliedSequence"] = () =>    readMinLastAppliedSequence(undefined).pipe(      Effect.mapError(        toPersistenceSqlError("ProjectionStateRepository.minLastAppliedSequence:query"),      ),      Effect.map((row) => row.minLastAppliedSequence),    );   return {    upsert,    getByProjector,    listAll,    minLastAppliedSequence,  } satisfies ProjectionStateRepositoryShape;}); export const ProjectionStateRepositoryLive = Layer.effect(  ProjectionStateRepository,  makeProjectionStateRepository,);