Просмотр исходного кода

chore: uses the option "itemModel" instead of "model" to define a model for array items

e22m4u 1 год назад
Родитель
Сommit
35e1f82500

+ 36 - 11
dist/cjs/index.cjs

@@ -2838,6 +2838,14 @@ var init_properties_definition_validator = __esm({
             propDef.itemType
           );
         }
+        if (propDef.itemModel && typeof propDef.itemModel !== "string") {
+          throw new InvalidArgumentError(
+            'The provided option "itemModel" of the property %v in the model %v should be a String, but %v given.',
+            propName,
+            modelName,
+            propDef.itemModel
+          );
+        }
         if (propDef.model && typeof propDef.model !== "string")
           throw new InvalidArgumentError(
             'The provided option "model" of the property %v in the model %v should be a String, but %v given.',
@@ -2893,28 +2901,41 @@ var init_properties_definition_validator = __esm({
           );
         if (propDef.itemType && propDef.type !== DataType.ARRAY)
           throw new InvalidArgumentError(
-            'The property %v of the model %v has the non-array type, so it should not have the option "itemType" to be provided.',
+            'The property %v of the model %v has a non-array type, so it should not have the option "itemType" to be provided.',
             propName,
             modelName,
             propDef.type
           );
-        if (propDef.model && propDef.type !== DataType.OBJECT && propDef.itemType !== DataType.OBJECT) {
-          if (propDef.type !== DataType.ARRAY) {
+        if (propDef.itemModel && propDef.type !== DataType.ARRAY)
+          throw new InvalidArgumentError(
+            'The option "itemModel" is not supported for %s property type, so the property %v of the model %v should not have the option "itemModel" to be provided.',
+            capitalize(propDef.type),
+            propName,
+            modelName
+          );
+        if (propDef.itemModel && propDef.itemType !== DataType.OBJECT) {
+          if (propDef.itemType) {
             throw new InvalidArgumentError(
-              'The option "model" is not supported for %s property type, so the property %v of the model %v should not have the option "model" to be provided.',
-              capitalize(propDef.type),
+              'The provided option "itemModel" requires the option "itemType" to be explicitly set to Object, but the property %v of the model %v has specified item type as %s.',
               propName,
-              modelName
+              modelName,
+              capitalize(propDef.itemType)
             );
           } else {
             throw new InvalidArgumentError(
-              'The option "model" is not supported for Array property type of %s, so the property %v of the model %v should not have the option "model" to be provided.',
-              capitalize(propDef.itemType),
+              'The provided option "itemModel" requires the option "itemType" to be explicitly set to Object, but the property %v of the model %v does not have specified item type.',
               propName,
               modelName
             );
           }
         }
+        if (propDef.model && propDef.type !== DataType.OBJECT)
+          throw new InvalidArgumentError(
+            'The option "model" is not supported for %s property type, so the property %v of the model %v should not have the option "model" to be provided.',
+            capitalize(propDef.type),
+            propName,
+            modelName
+          );
         if (propDef.validate != null) {
           const propertyValidatorRegistry = this.getService(
             PropertyValidatorRegistry
@@ -3186,11 +3207,15 @@ var init_model_data_validator = __esm({
             );
             break;
           // OBJECT
-          case DataType.OBJECT:
+          case DataType.OBJECT: {
             if (!isPureObject(propValue)) throw createError("an Object");
-            if (typeof propDef === "object" && propDef.model)
-              this.validate(propDef.model, propValue);
+            if (typeof propDef === "object") {
+              const modelOptionField = isArrayValue ? "itemModel" : "model";
+              const modelOptionValue = propDef[modelOptionField];
+              if (modelOptionValue) this.validate(modelOptionValue, propValue);
+            }
             break;
+          }
         }
       }
       /**

+ 7 - 3
src/definition/model/model-data-validator.js

@@ -157,11 +157,15 @@ export class ModelDataValidator extends Service {
         );
         break;
       // OBJECT
-      case DataType.OBJECT:
+      case DataType.OBJECT: {
         if (!isPureObject(propValue)) throw createError('an Object');
-        if (typeof propDef === 'object' && propDef.model)
-          this.validate(propDef.model, propValue);
+        if (typeof propDef === 'object') {
+          const modelOptionField = isArrayValue ? 'itemModel' : 'model';
+          const modelOptionValue = propDef[modelOptionField];
+          if (modelOptionValue) this.validate(modelOptionValue, propValue);
+        }
         break;
+      }
     }
   }
 

+ 18 - 3
src/definition/model/model-data-validator.spec.js

@@ -1651,7 +1651,22 @@ describe('ModelDataValidator', function () {
             );
           });
 
-          describe('the "model" option', function () {
+          describe('the "itemModel" option', function () {
+            it('does not throw an error if the option "itemModel" is not specified in case of Object item type', function () {
+              const S = new Schema();
+              S.defineModel({
+                name: 'model',
+                properties: {
+                  foo: {
+                    type: DataType.ARRAY,
+                    itemType: DataType.OBJECT,
+                  },
+                },
+              });
+              const value = {foo: [{a: 1}, {b: 2}]};
+              S.getService(ModelDataValidator).validate('model', value);
+            });
+
             it('throws an error when the given object element has an invalid model', function () {
               const S = new Schema();
               S.defineModel({
@@ -1667,7 +1682,7 @@ describe('ModelDataValidator', function () {
                   bar: {
                     type: DataType.ARRAY,
                     itemType: DataType.OBJECT,
-                    model: 'modelA',
+                    itemModel: 'modelA',
                   },
                 },
               });
@@ -1696,7 +1711,7 @@ describe('ModelDataValidator', function () {
                   bar: {
                     type: DataType.ARRAY,
                     itemType: DataType.OBJECT,
-                    model: 'modelA',
+                    itemModel: 'modelA',
                   },
                 },
               });

+ 37 - 15
src/definition/model/properties/properties-definition-validator.js

@@ -112,6 +112,15 @@ export class PropertiesDefinitionValidator extends Service {
         propDef.itemType,
       );
     }
+    if (propDef.itemModel && typeof propDef.itemModel !== 'string') {
+      throw new InvalidArgumentError(
+        'The provided option "itemModel" of the property %v in the model %v ' +
+          'should be a String, but %v given.',
+        propName,
+        modelName,
+        propDef.itemModel,
+      );
+    }
     if (propDef.model && typeof propDef.model !== 'string')
       throw new InvalidArgumentError(
         'The provided option "model" of the property %v in the model %v ' +
@@ -175,37 +184,50 @@ export class PropertiesDefinitionValidator extends Service {
       );
     if (propDef.itemType && propDef.type !== Type.ARRAY)
       throw new InvalidArgumentError(
-        'The property %v of the model %v has the non-array type, ' +
+        'The property %v of the model %v has a non-array type, ' +
           'so it should not have the option "itemType" to be provided.',
         propName,
         modelName,
         propDef.type,
       );
-    if (
-      propDef.model &&
-      propDef.type !== Type.OBJECT &&
-      propDef.itemType !== Type.OBJECT
-    ) {
-      if (propDef.type !== Type.ARRAY) {
+    if (propDef.itemModel && propDef.type !== Type.ARRAY)
+      throw new InvalidArgumentError(
+        'The option "itemModel" is not supported for %s property type, ' +
+          'so the property %v of the model %v should not have ' +
+          'the option "itemModel" to be provided.',
+        capitalize(propDef.type),
+        propName,
+        modelName,
+      );
+    if (propDef.itemModel && propDef.itemType !== Type.OBJECT) {
+      if (propDef.itemType) {
         throw new InvalidArgumentError(
-          'The option "model" is not supported for %s property type, ' +
-            'so the property %v of the model %v should not have ' +
-            'the option "model" to be provided.',
-          capitalize(propDef.type),
+          'The provided option "itemModel" requires the option "itemType" ' +
+            'to be explicitly set to Object, but the property %v of ' +
+            'the model %v has specified item type as %s.',
           propName,
           modelName,
+          capitalize(propDef.itemType),
         );
       } else {
         throw new InvalidArgumentError(
-          'The option "model" is not supported for Array property type of %s, ' +
-            'so the property %v of the model %v should not have ' +
-            'the option "model" to be provided.',
-          capitalize(propDef.itemType),
+          'The provided option "itemModel" requires the option "itemType" ' +
+            'to be explicitly set to Object, but the property %v of ' +
+            'the model %v does not have specified item type.',
           propName,
           modelName,
         );
       }
     }
+    if (propDef.model && propDef.type !== Type.OBJECT)
+      throw new InvalidArgumentError(
+        'The option "model" is not supported for %s property type, ' +
+          'so the property %v of the model %v should not have ' +
+          'the option "model" to be provided.',
+        capitalize(propDef.type),
+        propName,
+        modelName,
+      );
     if (propDef.validate != null) {
       const propertyValidatorRegistry = this.getService(
         PropertyValidatorRegistry,

+ 48 - 19
src/definition/model/properties/properties-definition-validator.spec.js

@@ -133,7 +133,7 @@ describe('PropertiesDefinitionValidator', function () {
       validate(DataType.STRING)();
     });
 
-    it('expects provided the option "itemType" to be a DataType', function () {
+    it('expects the provided option "itemType" to be a DataType', function () {
       const validate = v => {
         const foo = {type: DataType.ARRAY, itemType: v};
         return () => S.validate('model', {foo});
@@ -153,7 +153,29 @@ describe('PropertiesDefinitionValidator', function () {
       validate(DataType.STRING)();
     });
 
-    it('expects provided the option "model" to be a string', function () {
+    it('expects the provided option "itemModel" to be a string', function () {
+      const validate = v => {
+        const foo = {
+          type: DataType.ARRAY,
+          itemType: DataType.OBJECT,
+          itemModel: v,
+        };
+        return () => S.validate('model', {foo});
+      };
+      const error = v =>
+        format(
+          'The provided option "itemModel" of the property "foo" ' +
+            'in the model "model" should be a String, but %s given.',
+          v,
+        );
+      expect(validate(10)).to.throw(error('10'));
+      expect(validate(true)).to.throw(error('true'));
+      expect(validate([])).to.throw(error('Array'));
+      expect(validate({})).to.throw(error('Object'));
+      validate('model')();
+    });
+
+    it('expects the provided option "model" to be a string', function () {
       const validate = v => {
         const foo = {
           type: DataType.OBJECT,
@@ -174,7 +196,7 @@ describe('PropertiesDefinitionValidator', function () {
       validate('model')();
     });
 
-    it('expects provided the option "primaryKey" to be a boolean', function () {
+    it('expects the provided option "primaryKey" to be a boolean', function () {
       const validate = v => {
         const foo = {
           type: DataType.STRING,
@@ -195,7 +217,7 @@ describe('PropertiesDefinitionValidator', function () {
       validate(false)();
     });
 
-    it('expects provided the option "columnName" to be a string', function () {
+    it('expects the provided option "columnName" to be a string', function () {
       const validate = v => {
         const foo = {
           type: DataType.STRING,
@@ -216,7 +238,7 @@ describe('PropertiesDefinitionValidator', function () {
       validate('columnName')();
     });
 
-    it('expects provided the option "columnType" to be a string', function () {
+    it('expects the provided option "columnType" to be a string', function () {
       const validate = v => {
         const foo = {
           type: DataType.STRING,
@@ -237,7 +259,7 @@ describe('PropertiesDefinitionValidator', function () {
       validate('columnType')();
     });
 
-    it('expects provided the option "required" to be a boolean', function () {
+    it('expects the provided option "required" to be a boolean', function () {
       const validate = v => {
         const foo = {
           type: DataType.STRING,
@@ -332,7 +354,7 @@ describe('PropertiesDefinitionValidator', function () {
         S.validate('model', {foo});
       };
       const error =
-        'The property "foo" of the model "model" has the non-array type, ' +
+        'The property "foo" of the model "model" has a non-array type, ' +
         'so it should not have the option "itemType" to be provided.';
       expect(validate(DataType.ANY)).to.throw(error);
       expect(validate(DataType.STRING)).to.throw(error);
@@ -364,27 +386,34 @@ describe('PropertiesDefinitionValidator', function () {
       validate(DataType.OBJECT)();
     });
 
-    it('the option "model" requires the "object" item type', function () {
+    it('the option "itemModel" requires the "object" item type', function () {
       const validate = v => () => {
         const foo = {
           type: DataType.ARRAY,
           itemType: v,
-          model: 'model',
+          itemModel: 'model',
         };
         S.validate('model', {foo});
       };
-      const error = v =>
+      const errorForNonEmpty = v =>
         format(
-          'The option "model" is not supported for Array property type of %s, ' +
-            'so the property "foo" of the model "model" should not have ' +
-            'the option "model" to be provided.',
+          'The provided option "itemModel" requires the option "itemType" ' +
+            'to be explicitly set to Object, but the property "foo" of ' +
+            'the model "model" has specified item type as %s.',
           v,
         );
-      expect(validate(DataType.ANY)).to.throw(error('Any'));
-      expect(validate(DataType.STRING)).to.throw(error('String'));
-      expect(validate(DataType.NUMBER)).to.throw(error('Number'));
-      expect(validate(DataType.BOOLEAN)).to.throw(error('Boolean'));
-      expect(validate(DataType.ARRAY)).to.throw(error('Array'));
+      const errorForEmpty = format(
+        'The provided option "itemModel" requires the option "itemType" ' +
+          'to be explicitly set to Object, but the property "foo" of ' +
+          'the model "model" does not have specified item type.',
+      );
+      expect(validate(DataType.ANY)).to.throw(errorForNonEmpty('Any'));
+      expect(validate(DataType.STRING)).to.throw(errorForNonEmpty('String'));
+      expect(validate(DataType.NUMBER)).to.throw(errorForNonEmpty('Number'));
+      expect(validate(DataType.BOOLEAN)).to.throw(errorForNonEmpty('Boolean'));
+      expect(validate(DataType.ARRAY)).to.throw(errorForNonEmpty('Array'));
+      expect(validate(undefined)).to.throw(errorForEmpty);
+      expect(validate(null)).to.throw(errorForEmpty);
       validate(DataType.OBJECT)();
     });
 
@@ -491,7 +520,7 @@ describe('PropertiesDefinitionValidator', function () {
       validate({myTransformer: true})();
     });
 
-    it('expects provided the option "unique" to be a Boolean or the PropertyUniqueness', function () {
+    it('expects the provided option "unique" to be a Boolean or the PropertyUniqueness', function () {
       const validate = v => {
         const foo = {
           type: DataType.STRING,

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

@@ -9,6 +9,7 @@ import {PropertyTransformOptions} from './property-transformer/index.js';
 export declare type FullPropertyDefinition = {
   type: DataType;
   itemType?: DataType;
+  itemModel?: string;
   model?: string;
   primaryKey?: boolean;
   columnName?: string;