metis-desk/modules/companies/src/api/infrastructure/persistence/sequelize-printer-configuration.repository.ts

134 lines
5.7 KiB
TypeScript

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<Result<PrinterContext, PrinterConfigurationError>> {
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<PrinterRow>(
"SELECT * FROM printer_configurations WHERE companyId=:companyId",
{ ...options, type: QueryTypes.SELECT }
);
const revisions = await this.database.query<PrinterRevisionRow>(
"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<ProfileRow>(
"SELECT * FROM work_profiles WHERE companyId=:companyId",
{ ...options, type: QueryTypes.SELECT }
);
const profileRevisions = await this.database.query<ProfileRevisionRow>(
"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<IPrinterConfigurationRepository["save"]>[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 });
});
}
}