106 lines
3.7 KiB
TypeScript
106 lines
3.7 KiB
TypeScript
|
|
import type { UniqueID } from "@repo/rdx-ddd";
|
||
|
|
import type { Result as DomainResult } from "@repo/rdx-utils";
|
||
|
|
import { Maybe, Result } from "@repo/rdx-utils";
|
||
|
|
import type { Sequelize, Transaction } from "sequelize";
|
||
|
|
import { Op } from "sequelize";
|
||
|
|
|
||
|
|
import type { ICompanyRepository } from "../../application/company.repository";
|
||
|
|
import type { Company } from "../../domain/company.aggregate";
|
||
|
|
import { CompanyError } from "../../domain/company-error";
|
||
|
|
|
||
|
|
import { CompanyModel, ContactModel, SiteModel } from "./company.model";
|
||
|
|
import type { CompanyPersistenceMapper } from "./company-persistence.mapper";
|
||
|
|
|
||
|
|
export class SequelizeCompanyRepository implements ICompanyRepository {
|
||
|
|
constructor(
|
||
|
|
private readonly database: Sequelize,
|
||
|
|
private readonly mapper: CompanyPersistenceMapper
|
||
|
|
) {}
|
||
|
|
async list(): Promise<readonly Company[]> {
|
||
|
|
const companies = await CompanyModel.findAll({
|
||
|
|
order: [
|
||
|
|
["name", "ASC"],
|
||
|
|
["id", "ASC"],
|
||
|
|
],
|
||
|
|
});
|
||
|
|
if (companies.length === 0) {
|
||
|
|
return [];
|
||
|
|
}
|
||
|
|
const ids = companies.map((company) => company.id);
|
||
|
|
const [contacts, sites] = await Promise.all([
|
||
|
|
ContactModel.findAll({
|
||
|
|
where: { companyId: { [Op.in]: ids } },
|
||
|
|
order: [
|
||
|
|
["name", "ASC"],
|
||
|
|
["id", "ASC"],
|
||
|
|
],
|
||
|
|
}),
|
||
|
|
SiteModel.findAll({
|
||
|
|
where: { companyId: { [Op.in]: ids } },
|
||
|
|
order: [
|
||
|
|
["name", "ASC"],
|
||
|
|
["id", "ASC"],
|
||
|
|
],
|
||
|
|
}),
|
||
|
|
]);
|
||
|
|
return companies.map((company) =>
|
||
|
|
this.mapper.toDomain({
|
||
|
|
company,
|
||
|
|
contacts: contacts.filter((contact) => contact.companyId === company.id),
|
||
|
|
sites: sites.filter((site) => site.companyId === company.id),
|
||
|
|
})
|
||
|
|
);
|
||
|
|
}
|
||
|
|
private async load(id: UniqueID, transaction?: Transaction): Promise<Maybe<Company>> {
|
||
|
|
const options = transaction ? { transaction, lock: transaction.LOCK.UPDATE } : {};
|
||
|
|
const company = await CompanyModel.findByPk(id.toPrimitive(), options);
|
||
|
|
if (!company) {
|
||
|
|
return Maybe.none();
|
||
|
|
}
|
||
|
|
const childOptions = {
|
||
|
|
where: { companyId: company.id },
|
||
|
|
...(transaction ? { transaction } : {}),
|
||
|
|
};
|
||
|
|
const contacts = await ContactModel.findAll({ ...childOptions, order: [["name", "ASC"]] });
|
||
|
|
const sites = await SiteModel.findAll({ ...childOptions, order: [["name", "ASC"]] });
|
||
|
|
return Maybe.some(this.mapper.toDomain({ company, contacts, sites }));
|
||
|
|
}
|
||
|
|
findById(id: UniqueID) {
|
||
|
|
return this.load(id);
|
||
|
|
}
|
||
|
|
async create(company: Company): Promise<Company> {
|
||
|
|
await CompanyModel.create(this.mapper.toPersistence(company).company);
|
||
|
|
return company;
|
||
|
|
}
|
||
|
|
async update(
|
||
|
|
id: UniqueID,
|
||
|
|
change: (company: Company) => DomainResult<Company, CompanyError>
|
||
|
|
): Promise<DomainResult<Company, CompanyError>> {
|
||
|
|
return this.database.transaction(async (transaction) => {
|
||
|
|
const current = (await this.load(id, transaction)).getOrUndefined();
|
||
|
|
if (!current) {
|
||
|
|
return Result.fail(new CompanyError("COMPANY_NOT_FOUND"));
|
||
|
|
}
|
||
|
|
const changed = change(current);
|
||
|
|
if (!changed.isSuccess || changed.data === current) {
|
||
|
|
return changed;
|
||
|
|
}
|
||
|
|
const record = this.mapper.toPersistence(changed.data);
|
||
|
|
await CompanyModel.update(record.company, { where: { id: id.toPrimitive() }, transaction });
|
||
|
|
if (record.contacts.length > 0) {
|
||
|
|
await ContactModel.bulkCreate(record.contacts, {
|
||
|
|
transaction,
|
||
|
|
updateOnDuplicate: ["name", "position", "email", "phone", "active"],
|
||
|
|
});
|
||
|
|
}
|
||
|
|
if (record.sites.length > 0) {
|
||
|
|
await SiteModel.bulkCreate(record.sites, {
|
||
|
|
transaction,
|
||
|
|
updateOnDuplicate: ["name", "address"],
|
||
|
|
});
|
||
|
|
}
|
||
|
|
return changed;
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|