UNPKG

rich-domain

Version:

This package provide utils file and interfaces to assistant build a complex application with domain driving design

146 lines 7.11 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Entity = void 0; const deep_freeze_util_1 = require("../utils/deep-freeze.util"); const auto_mapper_1 = require("./auto-mapper"); const entity_getters_and_setters_1 = require("./entity-getters-and-setters"); const id_1 = require("./id"); const result_1 = require("./result"); /** * @description Represents a domain entity identified by a unique identifier (ID). * Extends basic entity functionalities, ensuring the presence of `createdAt` and `updatedAt` timestamps and providing * utility methods such as equality checks, object transformations, and instance creation. */ class Entity extends entity_getters_and_setters_1.default { _id; autoMapper; constructor(props, config) { super(Object.assign({}, { createdAt: new Date(), updatedAt: new Date() }, { ...props }), 'Entity', config); if (typeof props !== 'object' || (props instanceof Date) || Array.isArray(props)) { throw new Error(`Props must be an 'object' for entities, but received: '${typeof props}' as props on Class '${this.constructor.name}'`); } ; const isID = this.validator.isID(props?.['id']); const isStringOrNumber = this.validator.isString(props?.['id']) || this.validator.isNumber(props?.['id']); this._id = isStringOrNumber ? id_1.default.create(props?.['id']) : isID ? props?.['id'] : id_1.default.create(); this.autoMapper = new auto_mapper_1.default(); } /** * @description Determines if the current entity has the same properties (except `createdAt` and `updatedAt`) and the same ID as another entity. * @param other The entity instance to compare against. * @returns `true` if both entities have identical properties and IDs; otherwise, `false`. */ isEqual(other) { const currentProps = { ...this?.props, id: null }; const providedProps = { ...other?.props, id: null }; delete currentProps?.['createdAt']; delete currentProps?.['updatedAt']; delete providedProps?.['createdAt']; delete providedProps?.['updatedAt']; const equalId = this.id.isEqual(other?.id); const serializedA = JSON.stringify(currentProps); const serializedB = JSON.stringify(providedProps); const equalSerialized = serializedA === serializedB; return equalId && equalSerialized; } /** * @description Converts the current entity instance into a plain object representation. * @param adapter An optional adapter or builder that transforms the entity into another object format. * @returns If an adapter is provided, returns the adapted object. Otherwise, returns a deeply frozen object * representing the entity properties along with entity metadata (`AutoMapperSerializer<Props> & EntityMapperPayload`). */ toObject(adapter) { if (adapter && typeof adapter?.adaptOne === 'function') { return adapter.adaptOne(this); } if (adapter && typeof adapter?.build === 'function') { return adapter.build(this).value(); } const serializedObject = this.autoMapper.entityToObj(this); const frozenObject = (0, deep_freeze_util_1.deepFreeze)(serializedObject); return frozenObject; } /** * @description Retrieves the unique identifier (ID) of the entity. * @returns An instance of `UID<string>` representing the entity's ID. */ get id() { return this._id; } /** * @description Generates a "hash code" like identifier for the entity, combining its class name and ID. * @summary The format is `[Entity@ClassName]:UUID`. The ClassName is derived from the entity's prototype. * This helps uniquely identify the entity instance in logs or debugging. * @returns A `UID<string>` representing the hash code of the entity. */ hashCode() { const name = Reflect.getPrototypeOf(this); return id_1.default.create(`[Entity@${name?.constructor?.name}]:${this.id.value()}`); } /** * @description Checks if the entity is newly created and not yet persisted or saved externally (e.g., to a database). * @returns `true` if the entity is considered new (ID marked as new); otherwise, `false`. */ isNew() { return this.id.isNew(); } /** * @description Creates a new entity instance based on the current entity. * Allows overriding some properties. If no `id` is provided in the new props, a new one will be generated. * @param props Optional partial properties to override when creating the new entity instance. * @returns A new instance of the entity with updated properties. */ clone(props) { const instance = Reflect.getPrototypeOf(this); const _props = props ? { ...this.props, ...props } : { ...this.props }; const args = [_props, this.config]; return Reflect.construct(instance.constructor, args); } /** * @description Validates if a given value is suitable for creating or representing an entity. * @param value The value to validate. * @returns `true` if the value is considered valid for the entity; otherwise, `false`. */ static isValid(value) { return this.isValidProps(value); } ; /** * @description Validates the provided properties to check if they can be used to create a valid entity instance. * @param props The properties object to validate. * @returns `true` if the props are valid; `false` otherwise. */ static isValidProps(props) { return !this.validator.isUndefined(props) && !this.validator.isNull(props); } ; /** * @description Initializes a new entity instance from the given properties. * @summary This method should be implemented in subclasses. By default, it throws an error. * @param props The properties to initialize the entity. * @returns The newly created entity instance or throws an error if not implemented. * @throws An error indicating the method is not implemented. */ static init(props) { throw new Error('method not implemented: init', { cause: props }); } ; /** * @description Creates a new entity instance wrapped inside a `Result` object. * @param props The properties to create the entity with. Must be valid properties. * @param id (Optional) A UUID to assign to the entity. If not provided, a new one will be generated. * @returns A `Result` instance containing the new entity if successfully created; otherwise, a failure `Result`. * @summary If the properties are invalid, the result will be a failure with `null` state. */ static create(props) { if (!this.isValidProps(props)) return result_1.default.fail('Invalid props to create an instance of ' + this.name); return result_1.default.Ok(new this(props)); } ; } exports.Entity = Entity; exports.default = Entity; //# sourceMappingURL=entity.js.map