UNPKG

@sap-cloud-sdk/odata-common

Version:

SAP Cloud SDK for JavaScript common functions of OData client generator and OpenAPI clint generator.

234 lines • 9.36 kB
"use strict"; /* eslint-disable max-classes-per-file */ Object.defineProperty(exports, "__esModule", { value: true }); exports.EntityBase = void 0; exports.isSelectedProperty = isSelectedProperty; exports.isExistentProperty = isExistentProperty; exports.isExpandedProperty = isExpandedProperty; exports.entityBuilder = entityBuilder; const util_1 = require("@sap-cloud-sdk/util"); const entity_builder_1 = require("./entity-builder"); const properties_util_1 = require("./properties-util"); /** * Super class for all representations of OData entity types. */ class EntityBase { /** * @internal */ constructor(_entityApi) { this._entityApi = _entityApi; (0, properties_util_1.nonEnumerable)(this, '_customFields'); (0, properties_util_1.nonEnumerable)(this, '_entityApi'); (0, properties_util_1.nonEnumerable)(this, 'remoteState'); (0, properties_util_1.nonEnumerable)(this, '_versionIdentifier'); this._customFields = {}; } /** * ETag version identifier accessor. * @returns The ETag version identifier of the retrieved entity, returns `undefined` if not retrieved. */ get versionIdentifier() { return this._versionIdentifier; } /** * Returns a map that contains all entity custom fields. * @returns A map of all defined custom fields in the entity. */ getCustomFields() { return this._customFields; } /** * Custom field value getter. * @param fieldName - The name of the custom field. * @returns The value of the corresponding custom field. */ getCustomField(fieldName) { return this._customFields[fieldName]; } /** * Sets a new custom field in the entity or updates it. * Throws an error, if the provided custom field name is already defined by an original field in entity. * @param fieldName - The name of the custom field to update. * @param value - The value of the field. * @returns The entity itself, to facilitate method chaining. */ setCustomField(fieldName, value) { if (this.isConflictingCustomField(fieldName)) { throw new Error(`The field name "${fieldName}" is already defined in the entity and cannot be set as custom field.`); } this._customFields[fieldName] = value; return this; } /** * Validates whether a custom field exists in the entity. * @param fieldName - The name of the custom field to update. * @returns A boolean value, that indicates whether a custom field is defined in entity. */ hasCustomField(fieldName) { return this._customFields[fieldName] !== undefined; } /** * Sets custom fields on an entity. * @param customFields - Custom fields to set on the entity. * @returns The entity itself, to facilitate method chaining. */ setCustomFields(customFields) { Object.entries(customFields).forEach(([key, value]) => { this.setCustomField(key, value); }); return this; } /** * Set the ETag version identifier of the retrieved entity. * @param etag - The returned ETag version of the entity. * @returns The entity itself, to facilitate method chaining. */ setVersionIdentifier(etag) { if (etag && typeof etag === 'string') { this._versionIdentifier = etag; } return this; } /** * Initializes or sets the remoteState of the entity. * This function is called on all read, create and update requests. * @param state - State to be set as remote state. * @returns The entity itself, to facilitate method chaining. */ setOrInitializeRemoteState(state) { state = state || this.asObject(); this.remoteState = Object.entries(state).reduce((stateObject, [fieldName, value]) => { const propertyName = this[(0, util_1.camelCase)(fieldName)] ? (0, util_1.camelCase)(fieldName) : fieldName; return { ...stateObject, [propertyName]: value }; }, {}); return this; } /** * Returns all updated custom field properties compared to the last known remote state. * @returns An object containing all updated custom properties, with their new values. */ getUpdatedCustomFields() { if (!this.remoteState) { return this._customFields; } return Object.entries(this.getCustomFields()) .filter(([fieldName, value]) => this.remoteState[fieldName] !== value) .reduce((updatedCustomFields, [fieldName, value]) => ({ ...updatedCustomFields, [fieldName]: value }), {}); } /** * Returns all changed properties compared to the last known remote state. * The returned properties do not include custom fields. * Use {@link getUpdatedCustomFields}, if you need custom fields. * @returns EntityBase with all properties that changed. */ getUpdatedProperties() { const current = this.asObject(); return this.getUpdatedPropertyNames().reduce((patch, key) => ({ ...patch, [key]: current[key] }), {}); } /** * Returns all changed property names compared to the last known remote state. * The returned properties names do not include custom fields. * Use {@link getUpdatedCustomFields}, if you need custom fields. * @returns EntityBase with all properties that changed. */ getUpdatedPropertyNames() { const currentState = this.asObject(); const names = Object.keys(currentState).filter(key => this.propertyIsEnumerable(key) && !this.hasCustomField(key)); return !this.remoteState ? names : names.filter(key => !(0, util_1.equal)(this.remoteState[key], currentState[key])); } /** * Overwrites the default toJSON method so that all instance variables as well as all custom fields of the entity are returned. * @returns An object containing all instance variables + custom fields. */ toJSON() { return { ...this, ...this._customFields }; } isVisitedEntity(entity, visitedEntities = []) { return Array.isArray(entity) ? entity.some(multiLinkChild => visitedEntities.includes(multiLinkChild)) : visitedEntities.includes(entity); } getCurrentStateForKey(key, visitedEntities = []) { if ((0, properties_util_1.isNavigationProperty)(key, this._entityApi.schema)) { if ((0, util_1.isNullish)(this[key])) { return this[key]; } return Array.isArray(this[key]) ? this[key].map(linkedEntity => linkedEntity.asObject(visitedEntities)) : this[key].asObject(visitedEntities); } return Array.isArray(this[key]) ? [...this[key]] : this[key]; } /** * Validates whether a field name does not conflict with an original field name and thus can be defined as custom fields. * @param customFieldName - Field name to check. * @returns Boolean value that describes whether a field name can be defined as custom field. */ isConflictingCustomField(customFieldName) { return Object.values(this._entityApi.schema) .map((f) => f._fieldName) .includes(customFieldName); } /** * Creates an object containing all defined properties, navigation properties and custom fields in the entity. * @param visitedEntities - List of entities to check in case of circular dependencies. * @returns EntityBase as an object with all defined entity fields. */ asObject(visitedEntities = []) { visitedEntities.push(this); // eslint-disable-next-line @typescript-eslint/no-unused-vars return Object.keys(this) .filter(key => this.propertyIsEnumerable(key) && (!(0, properties_util_1.isNavigationProperty)(key, this._entityApi.schema) || !this.isVisitedEntity(this[key], visitedEntities))) .reduce((accumulatedMap, key) => ({ ...accumulatedMap, [key]: this.getCurrentStateForKey(key, visitedEntities) }), this.getCustomFields()); } } exports.EntityBase = EntityBase; /** * @internal */ function isSelectedProperty(json, field) { return json.hasOwnProperty(field._fieldName); } /** * @internal */ function isExistentProperty(json, link) { return isSelectedProperty(json, link) && json[link._fieldName] !== null; } /** * @internal */ function isExpandedProperty(json, link) { return (isExistentProperty(json, link) && !json[link._fieldName].hasOwnProperty('__deferred')); } /** * Create an entity builder for an entity API. * @param entityApi - The entity API to build entities for. * @returns An entity builder instance for the given entity API. */ function entityBuilder(entityApi) { const builder = new entity_builder_1.EntityBuilder(entityApi); Object.values(entityApi.schema).forEach((field) => { const fieldName = `${(0, util_1.camelCase)(field._fieldName)}`; builder[fieldName] = function (value) { this._entity[fieldName] = value; return this; }; }); return builder; } //# sourceMappingURL=entity-base.js.map