import type { UniqueID } from "@repo/rdx-ddd"; import { Result } from "@repo/rdx-utils"; import { QueryTypes, type Sequelize, type Transaction } from "sequelize"; import type { IPrinterConfigurationRepository, PrinterContext, } from "../../application/printer-configuration.repository"; import { printerReferences } from "../../application/printer-configuration-policy"; import type { IWorkProfileInventoryService } from "../../application/work-profile.repository"; import { PrinterConfigurationError } from "../../domain/printer-configuration-values"; import { PrinterConfigurationPersistenceMapper, type PrinterRevisionRow, type PrinterRow, } from "./printer-configuration-persistence.mapper"; import { type ProfileRevisionRow, type ProfileRow, WorkProfilePersistenceMapper, profileIdentity, } from "./work-profile-persistence.mapper"; export class SequelizePrinterConfigurationRepository implements IPrinterConfigurationRepository { private readonly mapper = new PrinterConfigurationPersistenceMapper(); constructor( private readonly database: Sequelize, private readonly inventory: IWorkProfileInventoryService ) {} private async load( company: UniqueID, transaction: Transaction, write: boolean ): Promise> { const replacements = { companyId: company.toPrimitive() }; const options = { replacements, transaction, type: QueryTypes.SELECT }; const companies = await this.database.query<{ id: string }>( `SELECT id FROM companies WHERE id=:companyId${write ? " FOR UPDATE" : ""}`, { ...options, type: QueryTypes.SELECT } ); if (!companies.length) { return Result.fail(new PrinterConfigurationError("COMPANY_NOT_FOUND")); } const rows = await this.database.query( "SELECT * FROM printer_configurations WHERE companyId=:companyId", { ...options, type: QueryTypes.SELECT } ); const revisions = await this.database.query( "SELECT r.* FROM printer_configuration_revisions r JOIN printer_configurations m ON m.id=r.configurationId WHERE m.companyId=:companyId", { ...options, type: QueryTypes.SELECT } ); const profiles = await this.database.query( "SELECT * FROM work_profiles WHERE companyId=:companyId", { ...options, type: QueryTypes.SELECT } ); const profileRevisions = await this.database.query( "SELECT r.* FROM work_profile_revisions r JOIN work_profiles p ON p.id=r.profileId WHERE p.companyId=:companyId", { ...options, type: QueryTypes.SELECT } ); const people = await this.database.query<{ id: string; active: boolean }>( "SELECT id,active FROM company_contacts WHERE companyId=:companyId", { ...options, type: QueryTypes.SELECT } ); const actors = await this.database.query<{ id: string; name: string }>( "SELECT id,name FROM users", { transaction, type: QueryTypes.SELECT } ); const context: PrinterContext = { configurations: rows.map((row) => this.mapper.toDomain( row, revisions.filter((r) => r.configurationId === row.id) ) ), profiles: profiles.map((row) => new WorkProfilePersistenceMapper().toDomain( row, profileRevisions.filter((r) => r.profileId === row.id) ) ), people: people.map((item) => ({ id: profileIdentity(item.id), active: Boolean(item.active), })), assets: await this.inventory.list(company), actors: new Map(actors.map((actor) => [actor.id, actor.name])), }; if ( context.profiles.some( (profile) => !( context.people.some((person) => person.id.equals(profile.values.personId)) && context.assets.some((asset) => asset.id.equals(profile.values.assetId)) ) ) || context.configurations.some((mapping) => !printerReferences(mapping.values, context)) ) { throw new Error("Ámbito de impresora persistido inconsistente."); } return Result.ok(context); } get(company: UniqueID) { return this.database.transaction((t) => this.load(company, t, false)); } save(company: UniqueID, action: Parameters[1]) { return this.database.transaction(async (transaction) => { const loaded = await this.load(company, transaction, true); if (!loaded.isSuccess) { return loaded; } const candidate = action(loaded.data); if (!candidate.isSuccess) { return candidate; } const previous = loaded.data.configurations.find((item) => item.id.equals(candidate.data.id)); if (previous !== candidate.data) { const record = this.mapper.toPersistence(candidate.data); await this.database.query( "INSERT INTO printer_configurations (id,companyId,profileId,printerId,`values`,currentKey,defaultKey) VALUES (:id,:companyId,:profileId,:printerId,:values,:currentKey,:defaultKey) ON DUPLICATE KEY UPDATE `values`=VALUES(`values`),currentKey=VALUES(currentKey),defaultKey=VALUES(defaultKey)", { replacements: record.root, transaction } ); const stored = new Set(previous?.history.map((r) => r.id.toPrimitive())); for (const revision of record.revisions.filter((r) => !stored.has(r.id))) { await this.database.query( "INSERT INTO printer_configuration_revisions (id,configurationId,position,actorId,recordedAt,`values`) VALUES (:id,:configurationId,:position,:actorId,:recordedAt,:values)", { replacements: revision, transaction } ); } } return Result.ok({ configuration: candidate.data, context: loaded.data }); }); } }