2026-10-07 11:03:01 +00:00
import type { UniqueID } from "@repo/rdx-ddd" ;
import { Result } from "@repo/rdx-utils" ;
2026-10-08 14:43:34 +00:00
import type { Sequelize , Transaction } from "sequelize" ;
import { QueryTypes } from "sequelize" ;
2026-10-07 11:03:01 +00:00
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" ;
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 < Result < InterventionContext , InterventionError > > {
const context = await this . tickets . list ( company ) ;
if ( ! context . isSuccess ) {
return Result . fail ( new InterventionError ( context . error . code ) ) ;
}
const roots = await this . database . query < Record < string , unknown > > (
"SELECT id,companyId,reference,requestKey,ticketId,assigneeId,`values`,`procedure` FROM interventions" +
( company ? " WHERE companyId=:company" : "" ) ,
{
transaction ,
type : QueryTypes . SELECT ,
replacements : { company : company?.toPrimitive ( ) ? ? null } ,
}
) ;
const revisions = await this . database . query < Record < string , unknown > > (
"SELECT r.id,r.interventionId,r.actorId,r.ticketId,r.assigneeId,r.`values`,r.recordedAt,r.position FROM intervention_revisions r JOIN interventions i ON i.id=r.interventionId" +
( company ? " WHERE i.companyId=:company" : "" ) ,
{
transaction ,
type : QueryTypes . SELECT ,
replacements : { company : company?.toPrimitive ( ) ? ? null } ,
}
) ;
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 < Result < InterventionLookups , InterventionError > > {
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 < Intervention , InterventionError >
) {
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 this . database . query (
previous
? "UPDATE interventions SET ticketId=:ticketId,assigneeId=:assigneeId,`values`=:values WHERE id=:id"
: "INSERT INTO interventions (id,companyId,reference,requestKey,ticketId,assigneeId,`values`,`procedure`) VALUES (:id,:companyId,:reference,:requestKey,:ticketId,:assigneeId,:values,:procedure)" ,
{ replacements : persisted.root , transaction }
) ;
for ( const row of persisted . revisions . slice ( previous ? . history . length ? ? 0 ) ) {
await this . database . query (
"INSERT INTO intervention_revisions (id,interventionId,actorId,ticketId,assigneeId,`values`,recordedAt,position) VALUES (:id,:interventionId,:actorId,:ticketId,:assigneeId,:values,:recordedAt,:position)" ,
{ replacements : row , transaction }
) ;
}
if ( ! previous ) {
await this . database . query (
"UPDATE intervention_counter SET nextNumber=nextNumber+1 WHERE id=1" ,
{ transaction }
) ;
}
}
}