Browse Source

chore: makes property validators are synchronous to improve performance

e22m4u 1 year ago
parent
commit
763686ad2d

File diff suppressed because it is too large
+ 0 - 0
docs/assets/search.js


File diff suppressed because it is too large
+ 0 - 0
docs/classes/ModelDataValidator.html


File diff suppressed because it is too large
+ 0 - 0
docs/types/PropertyValidateOptions.html


File diff suppressed because it is too large
+ 0 - 0
docs/types/PropertyValidator.html


File diff suppressed because it is too large
+ 0 - 0
docs/types/PropertyValidatorContext.html


+ 10 - 18
src/adapter/decorator/data-validation-decorator.js

@@ -21,40 +21,32 @@ export class DataValidationDecorator extends Service {
       );
       );
 
 
     const create = adapter.create;
     const create = adapter.create;
-    adapter.create = async function (modelName, modelData, filter) {
-      await this.getService(ModelDataValidator).validate(modelName, modelData);
+    adapter.create = function (modelName, modelData, filter) {
+      this.getService(ModelDataValidator).validate(modelName, modelData);
       return create.call(this, modelName, modelData, filter);
       return create.call(this, modelName, modelData, filter);
     };
     };
 
 
     const replaceById = adapter.replaceById;
     const replaceById = adapter.replaceById;
-    adapter.replaceById = async function (modelName, id, modelData, filter) {
-      await this.getService(ModelDataValidator).validate(modelName, modelData);
+    adapter.replaceById = function (modelName, id, modelData, filter) {
+      this.getService(ModelDataValidator).validate(modelName, modelData);
       return replaceById.call(this, modelName, id, modelData, filter);
       return replaceById.call(this, modelName, id, modelData, filter);
     };
     };
 
 
     const replaceOrCreate = adapter.replaceOrCreate;
     const replaceOrCreate = adapter.replaceOrCreate;
-    adapter.replaceOrCreate = async function (modelName, modelData, filter) {
-      await this.getService(ModelDataValidator).validate(modelName, modelData);
+    adapter.replaceOrCreate = function (modelName, modelData, filter) {
+      this.getService(ModelDataValidator).validate(modelName, modelData);
       return replaceOrCreate.call(this, modelName, modelData, filter);
       return replaceOrCreate.call(this, modelName, modelData, filter);
     };
     };
 
 
     const patch = adapter.patch;
     const patch = adapter.patch;
-    adapter.patch = async function (modelName, modelData, where) {
-      await this.getService(ModelDataValidator).validate(
-        modelName,
-        modelData,
-        true,
-      );
+    adapter.patch = function (modelName, modelData, where) {
+      this.getService(ModelDataValidator).validate(modelName, modelData, true);
       return patch.call(this, modelName, modelData, where);
       return patch.call(this, modelName, modelData, where);
     };
     };
 
 
     const patchById = adapter.patchById;
     const patchById = adapter.patchById;
-    adapter.patchById = async function (modelName, id, modelData, filter) {
-      await this.getService(ModelDataValidator).validate(
-        modelName,
-        modelData,
-        true,
-      );
+    adapter.patchById = function (modelName, id, modelData, filter) {
+      this.getService(ModelDataValidator).validate(modelName, modelData, true);
       return patchById.call(this, modelName, id, modelData, filter);
       return patchById.call(this, modelName, id, modelData, filter);
     };
     };
   }
   }

+ 0 - 40
src/adapter/decorator/data-validation-decorator.spec.js

@@ -74,44 +74,4 @@ describe('DataValidationDecorator', function () {
     expect(V.validate).to.be.called.once;
     expect(V.validate).to.be.called.once;
     expect(V.validate).to.be.called.with.exactly('model', data, true);
     expect(V.validate).to.be.called.with.exactly('model', data, true);
   });
   });
-
-  it('waits the validator execution in the "create" method', async function () {
-    const schema = new Schema();
-    schema.defineModel({name: 'model'});
-    const adapter = S.getService(TestAdapter);
-    const validator = S.getService(ModelDataValidator);
-    validator.validate = () => Promise.reject('rejected');
-    const promise = adapter.create('model', {});
-    await expect(promise).to.be.rejectedWith('rejected');
-  });
-
-  it('waits the validator execution in the "replaceById" method', async function () {
-    const schema = new Schema();
-    schema.defineModel({name: 'model'});
-    const adapter = S.getService(TestAdapter);
-    const validator = S.getService(ModelDataValidator);
-    validator.validate = () => Promise.reject('rejected');
-    const promise = adapter.replaceById('model', 1, {});
-    await expect(promise).to.be.rejectedWith('rejected');
-  });
-
-  it('waits the validator execution in the "replaceOrCreate" method', async function () {
-    const schema = new Schema();
-    schema.defineModel({name: 'model'});
-    const adapter = S.getService(TestAdapter);
-    const validator = S.getService(ModelDataValidator);
-    validator.validate = () => Promise.reject('rejected');
-    const promise = adapter.replaceOrCreate('model', {});
-    await expect(promise).to.be.rejectedWith('rejected');
-  });
-
-  it('waits the validator execution in the "patchById" method', async function () {
-    const schema = new Schema();
-    schema.defineModel({name: 'model'});
-    const adapter = S.getService(TestAdapter);
-    const validator = S.getService(ModelDataValidator);
-    validator.validate = () => Promise.reject('rejected');
-    const promise = adapter.patchById('model', 1, {});
-    await expect(promise).to.be.rejectedWith('rejected');
-  });
 });
 });

+ 1 - 5
src/definition/model/model-data-validator.d.ts

@@ -12,9 +12,5 @@ export declare class ModelDataValidator extends Service {
    * @param modelData
    * @param modelData
    * @param isPartial
    * @param isPartial
    */
    */
-  validate(
-    modelName: string,
-    modelData: ModelData,
-    isPartial?: boolean,
-  ): Promise<void>;
+  validate(modelName: string, modelData: ModelData, isPartial?: boolean): void;
 }
 }

+ 31 - 41
src/definition/model/model-data-validator.js

@@ -16,9 +16,9 @@ export class ModelDataValidator extends Service {
    * @param {string} modelName
    * @param {string} modelName
    * @param {object} modelData
    * @param {object} modelData
    * @param {boolean} isPartial
    * @param {boolean} isPartial
-   * @returns {Promise<void>}
+   * @returns {undefined}
    */
    */
-  async validate(modelName, modelData, isPartial = false) {
+  validate(modelName, modelData, isPartial = false) {
     if (!isPureObject(modelData))
     if (!isPureObject(modelData))
       throw new InvalidArgumentError(
       throw new InvalidArgumentError(
         'The data of the model %v should be an Object, but %v given.',
         'The data of the model %v should be an Object, but %v given.',
@@ -30,16 +30,16 @@ export class ModelDataValidator extends Service {
         ModelDefinitionUtils,
         ModelDefinitionUtils,
       ).getPropertiesDefinitionInBaseModelHierarchy(modelName);
       ).getPropertiesDefinitionInBaseModelHierarchy(modelName);
     const propNames = Object.keys(isPartial ? modelData : propDefs);
     const propNames = Object.keys(isPartial ? modelData : propDefs);
-    for (const propName of propNames) {
+    propNames.forEach(propName => {
       const propDef = propDefs[propName];
       const propDef = propDefs[propName];
-      if (!propDef) continue;
-      await this._validatePropertyValue(
+      if (!propDef) return;
+      this._validatePropertyValue(
         modelName,
         modelName,
         propName,
         propName,
         propDef,
         propDef,
         modelData[propName],
         modelData[propName],
       );
       );
-    }
+    });
   }
   }
 
 
   /**
   /**
@@ -49,9 +49,9 @@ export class ModelDataValidator extends Service {
    * @param {string} propName
    * @param {string} propName
    * @param {string|object} propDef
    * @param {string|object} propDef
    * @param {*} propValue
    * @param {*} propValue
-   * @returns {Promise<void>}
+   * @returns {undefined}
    */
    */
-  async _validatePropertyValue(modelName, propName, propDef, propValue) {
+  _validatePropertyValue(modelName, propName, propDef, propValue) {
     // undefined and null
     // undefined and null
     if (propValue == null) {
     if (propValue == null) {
       const isRequired =
       const isRequired =
@@ -65,14 +65,9 @@ export class ModelDataValidator extends Service {
       );
       );
     }
     }
     // Property type.
     // Property type.
-    await this._validateValueByPropertyType(
-      modelName,
-      propName,
-      propDef,
-      propValue,
-    );
+    this._validateValueByPropertyType(modelName, propName, propDef, propValue);
     // Property validators.
     // Property validators.
-    await this._validateValueByPropertyValidators(
+    this._validateValueByPropertyValidators(
       modelName,
       modelName,
       propName,
       propName,
       propDef,
       propDef,
@@ -88,9 +83,9 @@ export class ModelDataValidator extends Service {
    * @param {string|object} propDef
    * @param {string|object} propDef
    * @param {*} propValue
    * @param {*} propValue
    * @param {boolean} isArrayValue
    * @param {boolean} isArrayValue
-   * @returns {Promise<void>}
+   * @returns {undefined}
    */
    */
-  async _validateValueByPropertyType(
+  _validateValueByPropertyType(
     modelName,
     modelName,
     propName,
     propName,
     propDef,
     propDef,
@@ -138,7 +133,7 @@ export class ModelDataValidator extends Service {
       // ARRAY
       // ARRAY
       case DataType.ARRAY:
       case DataType.ARRAY:
         if (!Array.isArray(propValue)) throw createError('an Array');
         if (!Array.isArray(propValue)) throw createError('an Array');
-        const arrayItemsValidationPromises = propValue.map(async value =>
+        propValue.forEach(value =>
           this._validateValueByPropertyType(
           this._validateValueByPropertyType(
             modelName,
             modelName,
             propName,
             propName,
@@ -147,13 +142,12 @@ export class ModelDataValidator extends Service {
             true,
             true,
           ),
           ),
         );
         );
-        await Promise.all(arrayItemsValidationPromises);
         break;
         break;
       // OBJECT
       // OBJECT
       case DataType.OBJECT:
       case DataType.OBJECT:
         if (!isPureObject(propValue)) throw createError('an Object');
         if (!isPureObject(propValue)) throw createError('an Object');
         if (typeof propDef === 'object' && propDef.model)
         if (typeof propDef === 'object' && propDef.model)
-          await this.validate(propDef.model, propValue);
+          this.validate(propDef.model, propValue);
         break;
         break;
     }
     }
   }
   }
@@ -165,14 +159,9 @@ export class ModelDataValidator extends Service {
    * @param {string} propName
    * @param {string} propName
    * @param {string|object} propDef
    * @param {string|object} propDef
    * @param {*} propValue
    * @param {*} propValue
-   * @returns {Promise<void>}
+   * @returns {undefined}
    */
    */
-  async _validateValueByPropertyValidators(
-    modelName,
-    propName,
-    propDef,
-    propValue,
-  ) {
+  _validateValueByPropertyValidators(modelName, propName, propDef, propValue) {
     if (typeof propDef === 'string' || propDef.validate == null) return;
     if (typeof propDef === 'string' || propDef.validate == null) return;
     const validateDef = propDef.validate;
     const validateDef = propDef.validate;
     const propertyValidatorRegistry = this.getService(
     const propertyValidatorRegistry = this.getService(
@@ -187,30 +176,31 @@ export class ModelDataValidator extends Service {
         propValue,
         propValue,
         validatorName,
         validatorName,
       );
       );
-    const container = this.container;
-    const validateBy = async (validatorName, validatorOptions = undefined) => {
+    const validateBy = (validatorName, validatorOptions = undefined) => {
       const validator = propertyValidatorRegistry.getValidator(validatorName);
       const validator = propertyValidatorRegistry.getValidator(validatorName);
-      const context = {validatorName, modelName, propName, propDef, container};
-      const valid = await validator(propValue, validatorOptions, context);
-      if (valid !== true) throw createError(validatorName);
+      const context = {validatorName, modelName, propName};
+      const valid = validator(propValue, validatorOptions, context);
+      if (valid instanceof Promise) {
+        throw new InvalidArgumentError(
+          'Asynchronous property validators are not supported, ' +
+            'but the property validator %v returns a Promise.',
+          validatorName,
+        );
+      } else if (valid !== true) {
+        throw createError(validatorName);
+      }
     };
     };
     if (validateDef && typeof validateDef === 'string') {
     if (validateDef && typeof validateDef === 'string') {
-      await validateBy(validateDef);
+      validateBy(validateDef);
     } else if (Array.isArray(validateDef)) {
     } else if (Array.isArray(validateDef)) {
-      const validationPromises = validateDef.map(validatorName =>
-        validateBy(validatorName),
-      );
-      await Promise.all(validationPromises);
+      validateDef.forEach(validatorName => validateBy(validatorName));
     } else if (validateDef !== null && typeof validateDef === 'object') {
     } else if (validateDef !== null && typeof validateDef === 'object') {
-      const validationPromises = [];
       Object.keys(validateDef).forEach(validatorName => {
       Object.keys(validateDef).forEach(validatorName => {
         if (Object.prototype.hasOwnProperty.call(validateDef, validatorName)) {
         if (Object.prototype.hasOwnProperty.call(validateDef, validatorName)) {
           const validatorOptions = validateDef[validatorName];
           const validatorOptions = validateDef[validatorName];
-          const validationPromise = validateBy(validatorName, validatorOptions);
-          validationPromises.push(validationPromise);
+          validateBy(validatorName, validatorOptions);
         }
         }
       });
       });
-      await Promise.all(validationPromises);
     } else {
     } else {
       throw new InvalidArgumentError(
       throw new InvalidArgumentError(
         'The provided option "validate" of the property %v in the model %v ' +
         'The provided option "validate" of the property %v in the model %v ' +

File diff suppressed because it is too large
+ 199 - 187
src/definition/model/model-data-validator.spec.js


+ 1 - 6
src/definition/model/properties/property-validator/property-validator.d.ts

@@ -1,6 +1,3 @@
-import {ServiceContainer} from '@e22m4u/js-service';
-import {FullPropertyDefinition} from '../property-definition.js';
-
 /**
 /**
  * Property validator context.
  * Property validator context.
  */
  */
@@ -8,8 +5,6 @@ export type PropertyValidatorContext = {
   validatorName: string,
   validatorName: string,
   modelName: string,
   modelName: string,
   propName: string,
   propName: string,
-  propDef: FullPropertyDefinition,
-  container: ServiceContainer,
 }
 }
 
 
 /**
 /**
@@ -19,7 +14,7 @@ export type PropertyValidator = (
   value: unknown,
   value: unknown,
   options: unknown,
   options: unknown,
   context: PropertyValidatorContext,
   context: PropertyValidatorContext,
-) => Promise<boolean> | boolean;
+) => boolean;
 
 
 /**
 /**
  * Property validate options.
  * Property validate options.

Some files were not shown because too many files changed in this diff