123 lines
4.8 KiB
TypeScript
123 lines
4.8 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 { IInterventionTemplateRepository } from "../../application/intervention-template.repository";
|
|
import type { InterventionTemplate } from "../../domain/intervention-template.aggregate";
|
|
import { InterventionTemplateError } from "../../domain/intervention-template-values";
|
|
|
|
import { InterventionTemplatePersistenceMapper } from "./intervention-template-persistence.mapper";
|
|
export class SequelizeInterventionTemplateRepository implements IInterventionTemplateRepository {
|
|
private readonly mapper = new InterventionTemplatePersistenceMapper();
|
|
constructor(private readonly database: Sequelize) {}
|
|
private async exists(companyId: UniqueID | undefined, transaction?: Transaction) {
|
|
if (!companyId) {
|
|
return true;
|
|
}
|
|
const rows = await this.database.query("SELECT id FROM companies WHERE id=:id", {
|
|
replacements: { id: companyId.toPrimitive() },
|
|
type: QueryTypes.SELECT,
|
|
...(transaction ? { transaction } : {}),
|
|
});
|
|
return rows.length > 0;
|
|
}
|
|
private async read(transaction?: Transaction) {
|
|
const rows = await this.database.query("SELECT * FROM intervention_templates", {
|
|
type: QueryTypes.SELECT,
|
|
...(transaction ? { transaction } : {}),
|
|
});
|
|
const revisions = await this.database.query<{ templateId: string }>(
|
|
"SELECT * FROM intervention_template_revisions ORDER BY position",
|
|
{ type: QueryTypes.SELECT, ...(transaction ? { transaction } : {}) }
|
|
);
|
|
const users = await this.database.query<{ id: string; name: string }>(
|
|
"SELECT id,name FROM users",
|
|
{ type: QueryTypes.SELECT, ...(transaction ? { transaction } : {}) }
|
|
);
|
|
return {
|
|
templates: rows.map((row) => {
|
|
const parsed = this.rowIdentifier(row);
|
|
return this.mapper.toDomain(
|
|
row,
|
|
revisions.filter((item) => item.templateId === parsed)
|
|
);
|
|
}),
|
|
actorNames: new Map(users.map((user) => [user.id, user.name])),
|
|
};
|
|
}
|
|
private rowIdentifier(row: object) {
|
|
if (!("id" in row) || typeof row.id !== "string") {
|
|
throw new Error("Invalid intervention template row");
|
|
}
|
|
return row.id;
|
|
}
|
|
async list(companyId: UniqueID | undefined) {
|
|
return this.database.transaction(async (transaction) => {
|
|
if (!(await this.exists(companyId, transaction))) {
|
|
return Result.fail(new InterventionTemplateError("COMPANY_NOT_FOUND"));
|
|
}
|
|
const context = await this.read(transaction);
|
|
return Result.ok({
|
|
...context,
|
|
templates: context.templates.filter(
|
|
(item) =>
|
|
item.companyId.getOrUndefined() === undefined ||
|
|
(companyId !== undefined && item.companyId.getOrUndefined()?.equals(companyId) === true)
|
|
),
|
|
});
|
|
});
|
|
}
|
|
async save(
|
|
companyId: UniqueID | undefined,
|
|
action: (
|
|
templates: InterventionTemplate[]
|
|
) => Result<InterventionTemplate, InterventionTemplateError>
|
|
) {
|
|
return this.database.transaction(async (transaction) => {
|
|
await this.database.query("SELECT id FROM intervention_template_lock WHERE id=1 FOR UPDATE", {
|
|
type: QueryTypes.SELECT,
|
|
transaction,
|
|
});
|
|
if (!(await this.exists(companyId, transaction))) {
|
|
return Result.fail(new InterventionTemplateError("COMPANY_NOT_FOUND"));
|
|
}
|
|
const context = await this.read(transaction);
|
|
const result = action(context.templates);
|
|
if (!result.isSuccess) {
|
|
return Result.fail(result.error);
|
|
}
|
|
const template = result.data;
|
|
const previous = context.templates.find((item) => item.id.equals(template.id));
|
|
await this.write(template, previous, transaction);
|
|
return Result.ok({ ...context, template });
|
|
});
|
|
}
|
|
private async write(
|
|
template: InterventionTemplate,
|
|
previous: InterventionTemplate | undefined,
|
|
transaction: Transaction
|
|
) {
|
|
if (previous === template) {
|
|
return;
|
|
}
|
|
const persisted = this.mapper.toPersistence(template);
|
|
if (previous) {
|
|
await this.database.query("UPDATE intervention_templates SET `values`=:values WHERE id=:id", {
|
|
replacements: persisted.root,
|
|
transaction,
|
|
});
|
|
} else {
|
|
await this.database.query(
|
|
"INSERT INTO intervention_templates (id,companyId,requestKey,`values`) VALUES (:id,:companyId,:requestKey,:values)",
|
|
{ replacements: persisted.root, transaction }
|
|
);
|
|
}
|
|
for (const revision of persisted.revisions.slice(previous?.history.length ?? 0)) {
|
|
await this.database.query(
|
|
"INSERT INTO intervention_template_revisions (id,templateId,`values`,actorId,recordedAt,position) VALUES (:id,:templateId,:values,:actorId,:recordedAt,:position)",
|
|
{ replacements: revision, transaction }
|
|
);
|
|
}
|
|
}
|
|
}
|