144 lines · 4.3 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 upsertProjectionStateRows = SqlSchema.void({    Request: Schema.Array(ProjectionState),    execute: (rows) =>      rows.length === 0        ? Effect.void        : sql`            INSERT INTO projection_state ${sql.insert(              rows.map((row) => ({                projector: row.projector,                last_applied_sequence: row.lastAppliedSequence,                updated_at: 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 upsertMany: ProjectionStateRepositoryShape["upsertMany"] = (rows) =>    upsertProjectionStateRows(rows).pipe(      Effect.mapError(toPersistenceSqlError("ProjectionStateRepository.upsertMany: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,    upsertMany,    getByProjector,    listAll,    minLastAppliedSequence,  } satisfies ProjectionStateRepositoryShape;}); export const ProjectionStateRepositoryLive = Layer.effect(  ProjectionStateRepository,  makeProjectionStateRepository,);