import type { Name, UniqueID } from "@repo/rdx-ddd"; import { AggregateRoot } from "@repo/rdx-ddd"; import { Result } from "@repo/rdx-utils"; import { CompanyError } from "./company-error"; import type { Contact, ContactProps } from "./contact.entity"; import type { Site, SiteProps } from "./site.entity"; export type CompanyProps = Readonly<{ name: Name; active: boolean; contacts: readonly Contact[]; sites: readonly Site[]; }>; export class Company extends AggregateRoot { protected constructor(props: CompanyProps, id?: UniqueID) { super( { ...props, contacts: Object.freeze([...props.contacts]), sites: Object.freeze([...props.sites]), }, id ); } static create(props: Pick): Result { if (props.name.toPrimitive().length > 100) { return Result.fail(new CompanyError("INVALID_REQUEST")); } return Result.ok(new Company({ ...props, contacts: [], sites: [] })); } static rehydrate(props: CompanyProps, id: UniqueID): Company { return new Company(props, id); } get name() { return this.props.name; } get active() { return this.props.active; } get contacts() { return this.props.contacts; } get sites() { return this.props.sites; } update(values: Pick): Result { if (values.name.toPrimitive().length > 100) { return Result.fail(new CompanyError("INVALID_REQUEST")); } return this.name.equals(values.name) && this.active === values.active ? Result.ok(this) : Result.ok(new Company({ ...this.props, ...values }, this.id)); } addContact(contact: Contact): Result { if (!contact.companyId.equals(this.id)) { return Result.fail(new CompanyError("INVALID_REQUEST")); } if (this.contacts.some((existing) => existing.id.equals(contact.id))) { return Result.ok(this); } return Result.ok( new Company({ ...this.props, contacts: [...this.contacts, contact] }, this.id) ); } updateContact( id: UniqueID, values: Omit ): Result { const current = this.contacts.find((contact) => contact.id.equals(id)); if (!current) { return Result.fail(new CompanyError("CONTACT_NOT_FOUND")); } const updated = current.update(values); if (!updated.isSuccess) { return updated; } return updated.data === current ? Result.ok(this) : Result.ok( new Company( { ...this.props, contacts: this.contacts.map((contact) => contact.id.equals(id) ? updated.data : contact ), }, this.id ) ); } addSite(site: Site): Result { if (!site.companyId.equals(this.id)) { return Result.fail(new CompanyError("INVALID_REQUEST")); } if (this.sites.some((existing) => existing.id.equals(site.id))) { return Result.ok(this); } return Result.ok(new Company({ ...this.props, sites: [...this.sites, site] }, this.id)); } updateSite(id: UniqueID, values: Omit): Result { const current = this.sites.find((site) => site.id.equals(id)); if (!current) { return Result.fail(new CompanyError("SITE_NOT_FOUND")); } const updated = current.update(values); if (!updated.isSuccess) { return updated; } return updated.data === current ? Result.ok(this) : Result.ok( new Company( { ...this.props, sites: this.sites.map((site) => (site.id.equals(id) ? updated.data : site)), }, this.id ) ); } }