UNPKG

@e22m4u/js-repository

Version:

Реализация репозитория для работы с базами данных в Node.js

113 lines (110 loc) 4.13 kB
import {Service} from '@e22m4u/js-service'; import {cloneDeep} from '../../utils/index.js'; import {isPureObject} from '../../utils/index.js'; import {transformPromise} from '../../utils/index.js'; import {EmptyValuesService} from '@e22m4u/js-empty-values'; import {InvalidArgumentError} from '../../errors/index.js'; import {ModelDefinitionUtils} from './model-definition-utils.js'; import {PropertyTransformerRegistry} from './properties/index.js'; /** * Model data transformer. */ export class ModelDataTransformer extends Service { /** * Transform. * * @param {string} modelName * @param {object} modelData * @param {boolean} isPartial * @returns {object|Promise<object>} */ transform(modelName, modelData, isPartial = false) { if (!isPureObject(modelData)) throw new InvalidArgumentError( 'The data of the model %v should be an Object, but %v given.', modelName, modelData, ); const emptyValuesService = this.getService(EmptyValuesService); const modelDefinitionUtils = this.getService(ModelDefinitionUtils); const propDefs = modelDefinitionUtils.getPropertiesDefinitionInBaseModelHierarchy( modelName, ); const propNames = Object.keys(isPartial ? modelData : propDefs); const transformedData = cloneDeep(modelData); return propNames.reduce((transformedDataOrPromise, propName) => { const propDef = propDefs[propName]; if (!propDef) return transformedDataOrPromise; const propType = modelDefinitionUtils.getDataTypeFromPropertyDefinition(propDef); const propValue = modelData[propName]; const isEmpty = emptyValuesService.isEmptyByType(propType, propValue); if (isEmpty) return transformedDataOrPromise; const newPropValueOrPromise = this._transformPropertyValue( modelName, propName, propDef, propValue, ); return transformPromise(newPropValueOrPromise, newPropValue => { return transformPromise(transformedDataOrPromise, resolvedData => { if (newPropValue !== propValue) resolvedData[propName] = newPropValue; return resolvedData; }); }); }, transformedData); } /** * Transform property value. * * @param {string} modelName * @param {string} propName * @param {string|object} propDef * @param {*} propValue * @returns {*} */ _transformPropertyValue(modelName, propName, propDef, propValue) { if (typeof propDef === 'string' || propDef.transform == null) return propValue; const transformDef = propDef.transform; const transformerRegistry = this.getService(PropertyTransformerRegistry); const transformFn = ( value, transformerName, transformerOptions = undefined, ) => { const transformer = transformerRegistry.getTransformer(transformerName); const context = {transformerName, modelName, propName}; return transformer(value, transformerOptions, context); }; if (transformDef && typeof transformDef === 'string') { return transformFn(propValue, transformDef); } else if (Array.isArray(transformDef)) { return transformDef.reduce((valueOrPromise, transformerName) => { return transformPromise(valueOrPromise, value => { return transformFn(value, transformerName); }); }, propValue); } else if (transformDef !== null && typeof transformDef === 'object') { return Object.keys(transformDef).reduce( (valueOrPromise, transformerName) => { const transformerOptions = transformDef[transformerName]; return transformPromise(valueOrPromise, value => { return transformFn(value, transformerName, transformerOptions); }); }, propValue, ); } else { throw new InvalidArgumentError( 'The provided option "transform" of the property %v in the model %v ' + 'should be a non-empty String, an Array of String or an Object, ' + 'but %v given.', propName, modelName, transformDef, ); } } }