import { ResultAsync, errAsync, okAsync } from "neverthrow"; import { FlowExecCtx } from "@core/flow.execution.context"; import { Database, asc, eq } from "@pkg/db"; import { supportedApp } from "@pkg/db/schema"; import { type Err } from "@pkg/result"; import { logger } from "@pkg/logger"; import { traceResultAsync } from "@core/observability"; import { CreateSupportedApp, SupportedApp, UpdateSupportedApp, } from "./data"; import { supportedAppErrors } from "./errors"; export class SupportedAppRepository { constructor(private db: Database) {} list(fctx: FlowExecCtx): ResultAsync { return traceResultAsync({ name: "supportedApp.list", fctx, fn: () => ResultAsync.fromPromise( this.db .select() .from(supportedApp) .orderBy(asc(supportedApp.createdAt)), (e) => supportedAppErrors.listFailed( fctx, e instanceof Error ? e.message : String(e), ), ).map((rows) => rows as SupportedApp[]), }); } getById(fctx: FlowExecCtx, id: number): ResultAsync { return traceResultAsync({ name: "supportedApp.getById", fctx, fn: () => ResultAsync.fromPromise( this.db.query.supportedApp.findFirst({ where: eq(supportedApp.id, id), }), (e) => supportedAppErrors.dbError( fctx, e instanceof Error ? e.message : String(e), ), ).andThen((row) => { if (!row) { return errAsync( supportedAppErrors.supportedAppNotFound(fctx, id), ); } return okAsync(row as SupportedApp); }), }); } create( fctx: FlowExecCtx, data: CreateSupportedApp, ): ResultAsync { logger.info("Creating supported app", { ...fctx, title: data.title }); return traceResultAsync({ name: "supportedApp.create", fctx, fn: () => ResultAsync.fromPromise( this.db .insert(supportedApp) .values({ title: data.title, packageName: data.packageName, createdAt: new Date(), updatedAt: new Date(), }) .returning() .execute(), (e) => supportedAppErrors.createFailed( fctx, e instanceof Error ? e.message : String(e), ), ).map((rows) => rows[0] as SupportedApp), }); } update( fctx: FlowExecCtx, id: number, updates: UpdateSupportedApp, ): ResultAsync { return traceResultAsync({ name: "supportedApp.update", fctx, fn: () => this.getById(fctx, id).andThen(() => ResultAsync.fromPromise( this.db .update(supportedApp) .set({ ...updates, updatedAt: new Date() }) .where(eq(supportedApp.id, id)) .returning() .execute(), (e) => supportedAppErrors.updateFailed( fctx, e instanceof Error ? e.message : String(e), ), ).andThen((rows) => { if (!rows[0]) { return errAsync( supportedAppErrors.supportedAppNotFound( fctx, id, ), ); } return okAsync(rows[0] as SupportedApp); }), ), }); } delete(fctx: FlowExecCtx, id: number): ResultAsync { return traceResultAsync({ name: "supportedApp.delete", fctx, fn: () => this.getById(fctx, id).andThen(() => ResultAsync.fromPromise( this.db .delete(supportedApp) .where(eq(supportedApp.id, id)) .execute(), (e) => supportedAppErrors.deleteFailed( fctx, e instanceof Error ? e.message : String(e), ), ).map(() => true), ), }); } }