import type { UniqueID } from "@repo/rdx-ddd"; import { Result } from "@repo/rdx-utils"; import type { Sequelize, Transaction } from "sequelize"; import { QueryTypes } from "sequelize"; import { z } from "zod/v4"; import type { IInterventionRepository, InterventionContext, InterventionLookups, InterventionSaveContext, } from "../../application/intervention.repository"; import type { IInterventionTemplateRepository } from "../../application/intervention-template.repository"; import type { ITicketRepository } from "../../application/ticket.repository"; import type { Intervention } from "../../domain/intervention.aggregate"; import { InterventionError } from "../../domain/intervention-values"; import { InterventionPersistenceMapper } from "./intervention-persistence.mapper"; import { readSupportRows, writeSupportRow } from "./support-record-relational"; export class SequelizeInterventionRepository implements IInterventionRepository { private readonly mapper = new InterventionPersistenceMapper(); constructor( private readonly database: Sequelize, private readonly tickets: ITicketRepository, private readonly templates: IInterventionTemplateRepository ) {} private async read( company: UniqueID | undefined, transaction: Transaction ): Promise> { const context = await this.tickets.list(company); if (!context.isSuccess) { return Result.fail(new InterventionError(context.error.code)); } const roots = (await readSupportRows(this.database, "interventions", transaction)).filter( (row) => !company || row.companyId === company.toPrimitive() ); const revisions = await readSupportRows(this.database, "intervention_revisions", transaction); return Result.ok({ ...context.data, interventions: roots.map((row) => this.mapper.toDomain( row, revisions.filter((item) => item.interventionId === row.id) ) ), }); } list(company?: UniqueID) { return this.database.transaction((transaction) => this.read(company, transaction)); } async lookups(company: UniqueID): Promise> { const [context, lookups, templates] = await Promise.all([ this.tickets.list(company), this.tickets.lookups(company), this.templates.list(company), ]); if (!context.isSuccess) { return Result.fail(new InterventionError(context.error.code)); } if (!lookups.isSuccess) { return Result.fail(new InterventionError(lookups.error.code)); } if (!templates.isSuccess) { return Result.fail(new InterventionError(templates.error.code)); } return Result.ok({ context: context.data, lookups: lookups.data, templates: templates.data.templates, templateActors: templates.data.actorNames, }); } save( company: UniqueID, requestKey: UniqueID, action: (context: InterventionSaveContext) => Result ) { return this.database.transaction(async (transaction) => { await this.database.query("SELECT id FROM companies WHERE id=:id FOR UPDATE", { replacements: { id: company.toPrimitive() }, transaction, type: QueryTypes.SELECT, }); await this.database.query("SELECT id FROM intervention_counter WHERE id=1 FOR UPDATE", { transaction, type: QueryTypes.SELECT, }); const all = await this.read(undefined, transaction); const lookups = await this.lookups(company); if (!all.isSuccess) { return Result.fail(all.error); } if (!lookups.isSuccess) { return Result.fail(lookups.error); } const sequence = await this.database.query<{ nextNumber: number }>( "SELECT nextNumber FROM intervention_counter WHERE id=1", { transaction, type: QueryTypes.SELECT } ); const scoped = { ...all.data, ...lookups.data, tickets: lookups.data.context.tickets, interventions: all.data.interventions.filter((item) => item.companyId.equals(company)), nextNumber: z.number().int().positive().parse(sequence[0]?.nextNumber), requestIntervention: all.data.interventions.find((item) => item.requestKey.equals(requestKey) ), }; const result = action(scoped); if (!result.isSuccess) { return Result.fail(result.error); } const previous = all.data.interventions.find((item) => item.id.equals(result.data.id)); await this.write(result.data, previous, transaction); return Result.ok({ intervention: result.data, context: all.data }); }); } private async write( intervention: Intervention, previous: Intervention | undefined, transaction: Transaction ) { if (previous === intervention) { return; } const persisted = this.mapper.toPersistence(intervention); await writeSupportRow( this.database, "interventions", persisted.root, transaction, previous ? "update" : "insert" ); for (const row of persisted.revisions.slice(previous?.history.length ?? 0)) { await writeSupportRow(this.database, "intervention_revisions", row, transaction, "insert"); } if (!previous) { await this.database.query( "UPDATE intervention_counter SET nextNumber=nextNumber+1 WHERE id=1", { transaction } ); } } }