Browse Source

refactor: removes @e22m4u/js-empty-values

e22m4u 2 weeks ago
parent
commit
57a360e0ff

+ 11 - 27
README.md

@@ -15,7 +15,6 @@
 - [Источник данных](#источник-данных)
 - [Источник данных](#источник-данных)
 - [Модель](#модель)
 - [Модель](#модель)
 - [Свойства](#свойства)
 - [Свойства](#свойства)
-- [Пустые значения](#пустые-значения)
 - [Репозиторий](#репозиторий)
 - [Репозиторий](#репозиторий)
   - [create](#repositorycreate)
   - [create](#repositorycreate)
   - [replaceById](#repositoryreplacebyid)
   - [replaceById](#repositoryreplacebyid)
@@ -390,7 +389,7 @@ dbs.defineModel({
 - `columnName: string` переопределение названия колонки;
 - `columnName: string` переопределение названия колонки;
 - `columnType: string` тип колонки (определяется адаптером);
 - `columnType: string` тип колонки (определяется адаптером);
 - `required: boolean` объявить свойство обязательным;
 - `required: boolean` объявить свойство обязательным;
-- `default: any` значение по умолчанию;
+- `default: any` значение по умолчанию (заменяет `undefined` и `null`);
 - `unique: boolean | string` проверять значение на уникальность;
 - `unique: boolean | string` проверять значение на уникальность;
 
 
 **Параметр `unique`**
 **Параметр `unique`**
@@ -399,15 +398,19 @@ dbs.defineModel({
 строгая проверка на уникальность. В этом режиме любое значение данного свойства
 строгая проверка на уникальность. В этом режиме любое значение данного свойства
 не может быть представлено более одного раза.
 не может быть представлено более одного раза.
 
 
-Режим `"sparse"` проверяет только значения с полезной нагрузкой, исключая
-[пустые значения](#пустые-значения), список которых отличается в зависимости
-от типа свойства. Например, для типа `string` пустым значением будет
-`undefined`, `null` и `""` (пустая строка).
-
 - `unique: true | 'strict'` строгая проверка на уникальность;
 - `unique: true | 'strict'` строгая проверка на уникальность;
-- `unique: 'sparse'` исключить из проверки [пустые значения](#пустые-значения);
+- `unique: 'sparse'` исключить из проверки ложные значения;
 - `unique: false | 'nonUnique'` не проверять на уникальность (по умолчанию);
 - `unique: false | 'nonUnique'` не проверять на уникальность (по умолчанию);
 
 
+Режим `"sparse"` исключает из проверки на уникальность ложные значения с точки
+зрения JavaScript. Указанные ниже значения будут проигнорированы при проверке
+в данном режиме.
+
+- `""` пустая строка;
+- `0` число ноль;
+- `false` логическое отрицание;
+- `undefined` и `null`;
+
 В качестве значений параметра `unique` можно использовать предопределенные
 В качестве значений параметра `unique` можно использовать предопределенные
 константы как эквивалент строковых значений `strict`, `sparse` и `nonUnique`.
 константы как эквивалент строковых значений `strict`, `sparse` и `nonUnique`.
 
 
@@ -471,25 +474,6 @@ dbs.defineModel({
 });
 });
 ```
 ```
 
 
-## Пустые значения
-
-Разные типы свойств имеют свои наборы пустых значений. Эти наборы используются
-для определения наличия полезной нагрузки в значении свойства. Например,
-параметр `default` в определении свойства устанавливает значение по умолчанию,
-только если входящее значение является пустым. Параметр `required` исключает
-пустые значения выбрасывая ошибку. А параметр `unique` в режиме `sparse`
-наоборот допускает дублирование пустых значений уникального свойства,
-поскольку они не участвуют в проверке.
-
-| тип свойства       | пустые значения            |
-|--------------------|----------------------------|
-| `DataType.ANY`     | *значения остальных типов* |
-| `DataType.STRING`  | `undefined`, `null`, `""`  |
-| `DataType.NUMBER`  | `undefined`, `null`        |
-| `DataType.BOOLEAN` | `undefined`, `null`        |
-| `DataType.ARRAY`   | `undefined`, `null`        |
-| `DataType.OBJECT`  | `undefined`, `null`        |
-
 ## Репозиторий
 ## Репозиторий
 
 
 Репозиторий выполняет операции чтения и записи данных определенной модели.
 Репозиторий выполняет операции чтения и записи данных определенной модели.

+ 16 - 28
dist/cjs/index.cjs

@@ -1758,13 +1758,12 @@ var init_definition_registry = __esm({
 });
 });
 
 
 // src/definition/model/model-definition-utils.js
 // src/definition/model/model-definition-utils.js
-var import_js_service7, import_js_empty_values, DEFAULT_PRIMARY_KEY_PROPERTY_NAME, _ModelDefinitionUtils, ModelDefinitionUtils;
+var import_js_service7, DEFAULT_PRIMARY_KEY_PROPERTY_NAME, _ModelDefinitionUtils, ModelDefinitionUtils;
 var init_model_definition_utils = __esm({
 var init_model_definition_utils = __esm({
   "src/definition/model/model-definition-utils.js"() {
   "src/definition/model/model-definition-utils.js"() {
     "use strict";
     "use strict";
     import_js_service7 = require("@e22m4u/js-service");
     import_js_service7 = require("@e22m4u/js-service");
     init_properties();
     init_properties();
-    import_js_empty_values = require("@e22m4u/js-empty-values");
     init_errors();
     init_errors();
     init_definition_registry();
     init_definition_registry();
     init_utils();
     init_utils();
@@ -1865,7 +1864,7 @@ var init_model_definition_utils = __esm({
           return propDef.default instanceof Function ? propDef.default() : propDef.default;
           return propDef.default instanceof Function ? propDef.default() : propDef.default;
       }
       }
       /**
       /**
-       * Set default values for empty properties.
+       * Set default values to empty properties.
        *
        *
        * @param {string} modelName
        * @param {string} modelName
        * @param {object} modelData
        * @param {object} modelData
@@ -1876,13 +1875,12 @@ var init_model_definition_utils = __esm({
         const propDefs = this.getPropertiesDefinitionInBaseModelHierarchy(modelName);
         const propDefs = this.getPropertiesDefinitionInBaseModelHierarchy(modelName);
         const propNames = onlyProvidedProperties ? Object.keys(modelData) : Object.keys(propDefs);
         const propNames = onlyProvidedProperties ? Object.keys(modelData) : Object.keys(propDefs);
         const extendedData = cloneDeep(modelData);
         const extendedData = cloneDeep(modelData);
-        const blankValuesService = this.getService(import_js_empty_values.BlankValuesService);
         propNames.forEach((propName) => {
         propNames.forEach((propName) => {
           const propDef = propDefs[propName];
           const propDef = propDefs[propName];
           const propValue = extendedData[propName];
           const propValue = extendedData[propName];
-          const propType = propDef != null ? this.getDataTypeFromPropertyDefinition(propDef) : DataType.ANY;
-          const isBlank = blankValuesService.isBlankOf(propType, propValue);
-          if (!isBlank) return;
+          if (propValue != null) {
+            return;
+          }
           if (propDef && typeof propDef === "object" && propDef.default !== void 0) {
           if (propDef && typeof propDef === "object" && propDef.default !== void 0) {
             extendedData[propName] = this.getDefaultPropertyValue(
             extendedData[propName] = this.getDefaultPropertyValue(
               modelName,
               modelName,
@@ -2171,13 +2169,12 @@ var init_model_definition_utils = __esm({
 });
 });
 
 
 // src/definition/model/properties/required-property-validator.js
 // src/definition/model/properties/required-property-validator.js
-var import_js_service8, import_js_empty_values2, _RequiredPropertyValidator, RequiredPropertyValidator;
+var import_js_service8, _RequiredPropertyValidator, RequiredPropertyValidator;
 var init_required_property_validator = __esm({
 var init_required_property_validator = __esm({
   "src/definition/model/properties/required-property-validator.js"() {
   "src/definition/model/properties/required-property-validator.js"() {
     "use strict";
     "use strict";
     init_data_type();
     init_data_type();
     import_js_service8 = require("@e22m4u/js-service");
     import_js_service8 = require("@e22m4u/js-service");
-    import_js_empty_values2 = require("@e22m4u/js-empty-values");
     init_errors();
     init_errors();
     init_model_definition_utils();
     init_model_definition_utils();
     _RequiredPropertyValidator = class _RequiredPropertyValidator extends import_js_service8.Service {
     _RequiredPropertyValidator = class _RequiredPropertyValidator extends import_js_service8.Service {
@@ -2212,23 +2209,19 @@ var init_required_property_validator = __esm({
           ModelDefinitionUtils
           ModelDefinitionUtils
         ).getPropertiesDefinitionInBaseModelHierarchy(modelName);
         ).getPropertiesDefinitionInBaseModelHierarchy(modelName);
         const propNames = Object.keys(isPartial ? modelData : propDefs);
         const propNames = Object.keys(isPartial ? modelData : propDefs);
-        const blankValuesService = this.getService(import_js_empty_values2.BlankValuesService);
         for (const propName of propNames) {
         for (const propName of propNames) {
           const propDef = propDefs[propName];
           const propDef = propDefs[propName];
           if (!propDef || typeof propDef !== "object") {
           if (!propDef || typeof propDef !== "object") {
             continue;
             continue;
           }
           }
           const propValue = modelData[propName];
           const propValue = modelData[propName];
-          if (propDef.required) {
-            const propType = propDef.type || DataType.ANY;
-            if (blankValuesService.isBlankOf(propType, propValue)) {
-              throw new InvalidArgumentError(
-                "Property %v of the model %v is required, but %v was given.",
-                propName,
-                modelName,
-                propValue
-              );
-            }
+          if (propDef.required && propValue == null) {
+            throw new InvalidArgumentError(
+              "Property %v of the model %v is required, but %v was given.",
+              propName,
+              modelName,
+              propValue
+            );
           }
           }
           if (propDef.type === DataType.OBJECT && propDef.model && propValue !== null && typeof propValue === "object" && !Array.isArray(propValue)) {
           if (propDef.type === DataType.OBJECT && propDef.model && propValue !== null && typeof propValue === "object" && !Array.isArray(propValue)) {
             this.validate(propDef.model, propValue);
             this.validate(propDef.model, propValue);
@@ -2248,14 +2241,12 @@ var init_required_property_validator = __esm({
 });
 });
 
 
 // src/definition/model/properties/property-uniqueness-validator.js
 // src/definition/model/properties/property-uniqueness-validator.js
-var import_js_service9, import_js_empty_values3, _PropertyUniquenessValidator, PropertyUniquenessValidator;
+var import_js_service9, _PropertyUniquenessValidator, PropertyUniquenessValidator;
 var init_property_uniqueness_validator = __esm({
 var init_property_uniqueness_validator = __esm({
   "src/definition/model/properties/property-uniqueness-validator.js"() {
   "src/definition/model/properties/property-uniqueness-validator.js"() {
     "use strict";
     "use strict";
-    init_data_type();
     import_js_service9 = require("@e22m4u/js-service");
     import_js_service9 = require("@e22m4u/js-service");
     init_utils();
     init_utils();
-    import_js_empty_values3 = require("@e22m4u/js-empty-values");
     init_property_uniqueness();
     init_property_uniqueness();
     init_errors();
     init_errors();
     init_model_definition_utils();
     init_model_definition_utils();
@@ -2307,17 +2298,14 @@ var init_property_uniqueness_validator = __esm({
           propValue
           propValue
         ), "createError");
         ), "createError");
         let willBeReplaced = void 0;
         let willBeReplaced = void 0;
-        const blankValuesService = this.getService(import_js_empty_values3.BlankValuesService);
         for (const propName of propNames) {
         for (const propName of propNames) {
           const propDef = propDefs[propName];
           const propDef = propDefs[propName];
           if (!propDef || typeof propDef === "string" || !propDef.unique || propDef.unique === PropertyUniqueness.NON_UNIQUE) {
           if (!propDef || typeof propDef === "string" || !propDef.unique || propDef.unique === PropertyUniqueness.NON_UNIQUE) {
             continue;
             continue;
           }
           }
           const propValue = modelData[propName];
           const propValue = modelData[propName];
-          if (propDef.unique === PropertyUniqueness.SPARSE) {
-            const propType = propDef.type || DataType.ANY;
-            const isBlank = blankValuesService.isBlankOf(propType, propValue);
-            if (isBlank) continue;
+          if (propDef.unique === PropertyUniqueness.SPARSE && !propValue) {
+            continue;
           }
           }
           if (methodName === "create") {
           if (methodName === "create") {
             const count = await countMethod({ [propName]: propValue });
             const count = await countMethod({ [propName]: propValue });

+ 0 - 1
package.json

@@ -39,7 +39,6 @@
     "prepare": "husky"
     "prepare": "husky"
   },
   },
   "dependencies": {
   "dependencies": {
-    "@e22m4u/js-empty-values": "~0.4.0",
     "@e22m4u/js-format": "~0.3.2",
     "@e22m4u/js-format": "~0.3.2",
     "@e22m4u/js-service": "~0.5.1"
     "@e22m4u/js-service": "~0.5.1"
   },
   },

+ 6 - 9
src/definition/model/model-definition-utils.js

@@ -1,6 +1,5 @@
 import {Service} from '@e22m4u/js-service';
 import {Service} from '@e22m4u/js-service';
 import {DataType} from './properties/index.js';
 import {DataType} from './properties/index.js';
-import {BlankValuesService} from '@e22m4u/js-empty-values';
 import {InvalidArgumentError} from '../../errors/index.js';
 import {InvalidArgumentError} from '../../errors/index.js';
 import {DefinitionRegistry} from '../definition-registry.js';
 import {DefinitionRegistry} from '../definition-registry.js';
 import {cloneDeep, excludeObjectKeys} from '../../utils/index.js';
 import {cloneDeep, excludeObjectKeys} from '../../utils/index.js';
@@ -121,7 +120,7 @@ export class ModelDefinitionUtils extends Service {
   }
   }
 
 
   /**
   /**
-   * Set default values for empty properties.
+   * Set default values to empty properties.
    *
    *
    * @param {string} modelName
    * @param {string} modelName
    * @param {object} modelData
    * @param {object} modelData
@@ -139,16 +138,14 @@ export class ModelDefinitionUtils extends Service {
       ? Object.keys(modelData)
       ? Object.keys(modelData)
       : Object.keys(propDefs);
       : Object.keys(propDefs);
     const extendedData = cloneDeep(modelData);
     const extendedData = cloneDeep(modelData);
-    const blankValuesService = this.getService(BlankValuesService);
     propNames.forEach(propName => {
     propNames.forEach(propName => {
       const propDef = propDefs[propName];
       const propDef = propDefs[propName];
       const propValue = extendedData[propName];
       const propValue = extendedData[propName];
-      const propType =
-        propDef != null
-          ? this.getDataTypeFromPropertyDefinition(propDef)
-          : DataType.ANY;
-      const isBlank = blankValuesService.isBlankOf(propType, propValue);
-      if (!isBlank) return;
+      // если значение свойства не является undefined и null,
+      // то свойство пропускается (остается исходное значение)
+      if (propValue != null) {
+        return;
+      }
       if (
       if (
         propDef &&
         propDef &&
         typeof propDef === 'object' &&
         typeof propDef === 'object' &&

+ 2 - 6
src/definition/model/model-definition-utils.spec.js

@@ -4,7 +4,6 @@ import {createSandbox} from '@e22m4u/js-spy';
 import {DataType} from './properties/index.js';
 import {DataType} from './properties/index.js';
 import {RelationType} from './relations/index.js';
 import {RelationType} from './relations/index.js';
 import {DatabaseSchema} from '../../database-schema.js';
 import {DatabaseSchema} from '../../database-schema.js';
-import {BlankValuesService} from '@e22m4u/js-empty-values';
 import {InvalidArgumentError} from '../../errors/index.js';
 import {InvalidArgumentError} from '../../errors/index.js';
 
 
 import {
 import {
@@ -480,7 +479,7 @@ describe('ModelDefinitionUtils', function () {
       expect(result).to.be.eql({foo: 'string'});
       expect(result).to.be.eql({foo: 'string'});
     });
     });
 
 
-    it('sets a default value if a property has a blank value', function () {
+    it('sets a default value if a property value is undefined', function () {
       const dbs = new DatabaseSchema();
       const dbs = new DatabaseSchema();
       dbs.defineModel({
       dbs.defineModel({
         name: 'model',
         name: 'model',
@@ -491,12 +490,9 @@ describe('ModelDefinitionUtils', function () {
           },
           },
         },
         },
       });
       });
-      dbs
-        .getService(BlankValuesService)
-        .setBlankValuesOf(DataType.STRING, ['blank']);
       const result = dbs
       const result = dbs
         .getService(ModelDefinitionUtils)
         .getService(ModelDefinitionUtils)
-        .setDefaultValuesToEmptyProperties('model', {foo: 'blank'});
+        .setDefaultValuesToEmptyProperties('model', {foo: undefined});
       expect(result).to.be.eql({foo: 'placeholder'});
       expect(result).to.be.eql({foo: 'placeholder'});
     });
     });
 
 

+ 4 - 8
src/definition/model/properties/property-uniqueness-validator.js

@@ -1,7 +1,5 @@
-import {DataType} from './data-type.js';
 import {Service} from '@e22m4u/js-service';
 import {Service} from '@e22m4u/js-service';
 import {isPlainObject} from '../../../utils/index.js';
 import {isPlainObject} from '../../../utils/index.js';
-import {BlankValuesService} from '@e22m4u/js-empty-values';
 import {PropertyUniqueness} from './property-uniqueness.js';
 import {PropertyUniqueness} from './property-uniqueness.js';
 import {InvalidArgumentError} from '../../../errors/index.js';
 import {InvalidArgumentError} from '../../../errors/index.js';
 import {ModelDefinitionUtils} from '../model-definition-utils.js';
 import {ModelDefinitionUtils} from '../model-definition-utils.js';
@@ -70,7 +68,6 @@ export class PropertyUniquenessValidator extends Service {
         propValue,
         propValue,
       );
       );
     let willBeReplaced = undefined;
     let willBeReplaced = undefined;
-    const blankValuesService = this.getService(BlankValuesService);
     for (const propName of propNames) {
     for (const propName of propNames) {
       const propDef = propDefs[propName];
       const propDef = propDefs[propName];
       if (
       if (
@@ -81,12 +78,11 @@ export class PropertyUniquenessValidator extends Service {
       ) {
       ) {
         continue;
         continue;
       }
       }
-      // sparse
+      // в режиме "sparse" проверка на уникальность
+      // должна игнорировать ложные значения
       const propValue = modelData[propName];
       const propValue = modelData[propName];
-      if (propDef.unique === PropertyUniqueness.SPARSE) {
-        const propType = propDef.type || DataType.ANY;
-        const isBlank = blankValuesService.isBlankOf(propType, propValue);
-        if (isBlank) continue;
+      if (propDef.unique === PropertyUniqueness.SPARSE && !propValue) {
+        continue;
       }
       }
       // create
       // create
       if (methodName === 'create') {
       if (methodName === 'create') {

+ 229 - 31
src/definition/model/properties/property-uniqueness-validator.spec.js

@@ -2,7 +2,6 @@ import {expect} from 'chai';
 import {DataType} from './data-type.js';
 import {DataType} from './data-type.js';
 import {format} from '@e22m4u/js-format';
 import {format} from '@e22m4u/js-format';
 import {DatabaseSchema} from '../../../database-schema.js';
 import {DatabaseSchema} from '../../../database-schema.js';
-import {BlankValuesService} from '@e22m4u/js-empty-values';
 import {PropertyUniqueness} from './property-uniqueness.js';
 import {PropertyUniqueness} from './property-uniqueness.js';
 import {PropertyUniquenessValidator} from './property-uniqueness-validator.js';
 import {PropertyUniquenessValidator} from './property-uniqueness-validator.js';
 import {DEFAULT_PRIMARY_KEY_PROPERTY_NAME as DEF_PK} from '../model-definition-utils.js';
 import {DEFAULT_PRIMARY_KEY_PROPERTY_NAME as DEF_PK} from '../model-definition-utils.js';
@@ -1862,7 +1861,7 @@ describe('PropertyUniquenessValidator', function () {
           expect(invoked).to.be.eq(1);
           expect(invoked).to.be.eq(1);
         });
         });
 
 
-        it('skips uniqueness checking for blank values', async function () {
+        it('skips uniqueness checking for undefined value', async function () {
           const dbs = new DatabaseSchema();
           const dbs = new DatabaseSchema();
           dbs.defineModel({
           dbs.defineModel({
             name: 'model',
             name: 'model',
@@ -1879,10 +1878,34 @@ describe('PropertyUniquenessValidator', function () {
           });
           });
           const puv = dbs.getService(PropertyUniquenessValidator);
           const puv = dbs.getService(PropertyUniquenessValidator);
           let invoked = 0;
           let invoked = 0;
-          dbs
-            .getService(BlankValuesService)
-            .setBlankValuesOf(DataType.STRING, ['val2']);
-          const modelData = {foo: 'val1', bar: 'val2'};
+          const modelData = {foo: 'val1', bar: undefined};
+          const countMethod = where => {
+            if (invoked === 0) expect(where).to.be.eql({foo: 'val1'});
+            invoked++;
+            return 0;
+          };
+          await puv.validate(countMethod, 'create', 'model', modelData);
+          expect(invoked).to.be.eql(1);
+        });
+
+        it('skips uniqueness checking for an empty string', async function () {
+          const dbs = new DatabaseSchema();
+          dbs.defineModel({
+            name: 'model',
+            properties: {
+              foo: {
+                type: DataType.STRING,
+                unique: PropertyUniqueness.SPARSE,
+              },
+              bar: {
+                type: DataType.STRING,
+                unique: PropertyUniqueness.SPARSE,
+              },
+            },
+          });
+          const puv = dbs.getService(PropertyUniquenessValidator);
+          let invoked = 0;
+          const modelData = {foo: 'val1', bar: ''};
           const countMethod = where => {
           const countMethod = where => {
             if (invoked === 0) expect(where).to.be.eql({foo: 'val1'});
             if (invoked === 0) expect(where).to.be.eql({foo: 'val1'});
             invoked++;
             invoked++;
@@ -1976,7 +1999,7 @@ describe('PropertyUniquenessValidator', function () {
           expect(invoked).to.be.eq(1);
           expect(invoked).to.be.eq(1);
         });
         });
 
 
-        it('skips uniqueness checking for blank values', async function () {
+        it('skips uniqueness checking for undefined value', async function () {
           const dbs = new DatabaseSchema();
           const dbs = new DatabaseSchema();
           dbs.defineModel({
           dbs.defineModel({
             name: 'model',
             name: 'model',
@@ -1993,11 +2016,46 @@ describe('PropertyUniquenessValidator', function () {
           });
           });
           const puv = dbs.getService(PropertyUniquenessValidator);
           const puv = dbs.getService(PropertyUniquenessValidator);
           let invoked = 0;
           let invoked = 0;
-          dbs
-            .getService(BlankValuesService)
-            .setBlankValuesOf(DataType.STRING, ['val2']);
           const idValue = 1;
           const idValue = 1;
-          const modelData = {foo: 'val1', bar: 'val2'};
+          const modelData = {foo: 'val1', bar: undefined};
+          const countMethod = where => {
+            if (invoked === 0)
+              expect(where).to.be.eql({
+                [DEF_PK]: {neq: idValue},
+                foo: 'val1',
+              });
+            invoked++;
+            return 0;
+          };
+          await puv.validate(
+            countMethod,
+            'replaceById',
+            'model',
+            modelData,
+            idValue,
+          );
+          expect(invoked).to.be.eql(1);
+        });
+
+        it('skips uniqueness checking for an empty string', async function () {
+          const dbs = new DatabaseSchema();
+          dbs.defineModel({
+            name: 'model',
+            properties: {
+              foo: {
+                type: DataType.STRING,
+                unique: PropertyUniqueness.SPARSE,
+              },
+              bar: {
+                type: DataType.STRING,
+                unique: PropertyUniqueness.SPARSE,
+              },
+            },
+          });
+          const puv = dbs.getService(PropertyUniquenessValidator);
+          let invoked = 0;
+          const idValue = 1;
+          const modelData = {foo: 'val1', bar: ''};
           const countMethod = where => {
           const countMethod = where => {
             if (invoked === 0)
             if (invoked === 0)
               expect(where).to.be.eql({
               expect(where).to.be.eql({
@@ -2241,7 +2299,7 @@ describe('PropertyUniquenessValidator', function () {
               expect(invoked).to.be.eq(3);
               expect(invoked).to.be.eq(3);
             });
             });
 
 
-            it('skips uniqueness checking for blank values', async function () {
+            it('skips uniqueness checking for undefined value', async function () {
               const dbs = new DatabaseSchema();
               const dbs = new DatabaseSchema();
               dbs.defineModel({
               dbs.defineModel({
                 name: 'model',
                 name: 'model',
@@ -2257,12 +2315,54 @@ describe('PropertyUniquenessValidator', function () {
                 },
                 },
               });
               });
               const puv = dbs.getService(PropertyUniquenessValidator);
               const puv = dbs.getService(PropertyUniquenessValidator);
-              dbs
-                .getService(BlankValuesService)
-                .setBlankValuesOf(DataType.STRING, ['val2']);
               let invoked = 0;
               let invoked = 0;
               const idValue = 1;
               const idValue = 1;
-              const modelData = {[DEF_PK]: idValue, foo: 'val1', bar: 'val2'};
+              const modelData = {
+                [DEF_PK]: idValue,
+                foo: 'val1',
+                bar: undefined,
+              };
+              const countMethod = where => {
+                if (invoked === 0) {
+                  expect(where).to.be.eql({[DEF_PK]: idValue});
+                } else if (invoked === 1) {
+                  expect(where).to.be.eql({foo: 'val1'});
+                }
+                invoked++;
+                return 0;
+              };
+              await puv.validate(
+                countMethod,
+                'replaceOrCreate',
+                'model',
+                modelData,
+              );
+              expect(invoked).to.be.eql(2);
+            });
+
+            it('skips uniqueness checking for an empty string', async function () {
+              const dbs = new DatabaseSchema();
+              dbs.defineModel({
+                name: 'model',
+                properties: {
+                  foo: {
+                    type: DataType.STRING,
+                    unique: PropertyUniqueness.SPARSE,
+                  },
+                  bar: {
+                    type: DataType.STRING,
+                    unique: PropertyUniqueness.SPARSE,
+                  },
+                },
+              });
+              const puv = dbs.getService(PropertyUniquenessValidator);
+              let invoked = 0;
+              const idValue = 1;
+              const modelData = {
+                [DEF_PK]: idValue,
+                foo: 'val1',
+                bar: undefined,
+              };
               const countMethod = where => {
               const countMethod = where => {
                 if (invoked === 0) {
                 if (invoked === 0) {
                   expect(where).to.be.eql({[DEF_PK]: idValue});
                   expect(where).to.be.eql({[DEF_PK]: idValue});
@@ -2420,7 +2520,7 @@ describe('PropertyUniquenessValidator', function () {
               expect(invoked).to.be.eq(3);
               expect(invoked).to.be.eq(3);
             });
             });
 
 
-            it('skips uniqueness checking for blank values', async function () {
+            it('skips uniqueness checking for undefined value', async function () {
               const dbs = new DatabaseSchema();
               const dbs = new DatabaseSchema();
               dbs.defineModel({
               dbs.defineModel({
                 name: 'model',
                 name: 'model',
@@ -2436,12 +2536,58 @@ describe('PropertyUniquenessValidator', function () {
                 },
                 },
               });
               });
               const puv = dbs.getService(PropertyUniquenessValidator);
               const puv = dbs.getService(PropertyUniquenessValidator);
-              dbs
-                .getService(BlankValuesService)
-                .setBlankValuesOf(DataType.STRING, ['val2']);
               let invoked = 0;
               let invoked = 0;
               const idValue = 1;
               const idValue = 1;
-              const modelData = {[DEF_PK]: idValue, foo: 'val1', bar: 'val2'};
+              const modelData = {
+                [DEF_PK]: idValue,
+                foo: 'val1',
+                bar: undefined,
+              };
+              const countMethod = where => {
+                invoked++;
+                if (invoked === 1) {
+                  expect(where).to.be.eql({[DEF_PK]: idValue});
+                  return 1;
+                } else if (invoked === 2) {
+                  expect(where).to.be.eql({
+                    [DEF_PK]: {neq: idValue},
+                    foo: 'val1',
+                  });
+                  return 0;
+                }
+              };
+              await puv.validate(
+                countMethod,
+                'replaceOrCreate',
+                'model',
+                modelData,
+              );
+              expect(invoked).to.be.eql(2);
+            });
+
+            it('skips uniqueness checking for an empty string', async function () {
+              const dbs = new DatabaseSchema();
+              dbs.defineModel({
+                name: 'model',
+                properties: {
+                  foo: {
+                    type: DataType.STRING,
+                    unique: PropertyUniqueness.SPARSE,
+                  },
+                  bar: {
+                    type: DataType.STRING,
+                    unique: PropertyUniqueness.SPARSE,
+                  },
+                },
+              });
+              const puv = dbs.getService(PropertyUniquenessValidator);
+              let invoked = 0;
+              const idValue = 1;
+              const modelData = {
+                [DEF_PK]: idValue,
+                foo: 'val1',
+                bar: '',
+              };
               const countMethod = where => {
               const countMethod = where => {
                 invoked++;
                 invoked++;
                 if (invoked === 1) {
                 if (invoked === 1) {
@@ -2558,7 +2704,7 @@ describe('PropertyUniquenessValidator', function () {
           await expect(promise2).not.to.be.rejected;
           await expect(promise2).not.to.be.rejected;
         });
         });
 
 
-        it('skips uniqueness checking for blank values', async function () {
+        it('skips uniqueness checking for undefined value', async function () {
           const dbs = new DatabaseSchema();
           const dbs = new DatabaseSchema();
           dbs.defineModel({
           dbs.defineModel({
             name: 'model',
             name: 'model',
@@ -2574,11 +2720,35 @@ describe('PropertyUniquenessValidator', function () {
             },
             },
           });
           });
           const puv = dbs.getService(PropertyUniquenessValidator);
           const puv = dbs.getService(PropertyUniquenessValidator);
-          dbs
-            .getService(BlankValuesService)
-            .setBlankValuesOf(DataType.STRING, ['val2']);
           let invoked = 0;
           let invoked = 0;
-          const modelData = {foo: 'val1', bar: 'val2'};
+          const modelData = {foo: 'val1', bar: undefined};
+          const countMethod = where => {
+            if (invoked === 0) expect(where).to.be.eql({foo: 'val1'});
+            invoked++;
+            return 0;
+          };
+          await puv.validate(countMethod, 'patch', 'model', modelData);
+          expect(invoked).to.be.eql(1);
+        });
+
+        it('skips uniqueness checking for an empty string', async function () {
+          const dbs = new DatabaseSchema();
+          dbs.defineModel({
+            name: 'model',
+            properties: {
+              foo: {
+                type: DataType.STRING,
+                unique: PropertyUniqueness.SPARSE,
+              },
+              bar: {
+                type: DataType.STRING,
+                unique: PropertyUniqueness.SPARSE,
+              },
+            },
+          });
+          const puv = dbs.getService(PropertyUniquenessValidator);
+          let invoked = 0;
+          const modelData = {foo: 'val1', bar: ''};
           const countMethod = where => {
           const countMethod = where => {
             if (invoked === 0) expect(where).to.be.eql({foo: 'val1'});
             if (invoked === 0) expect(where).to.be.eql({foo: 'val1'});
             invoked++;
             invoked++;
@@ -2697,7 +2867,7 @@ describe('PropertyUniquenessValidator', function () {
           await expect(promise2).not.to.be.rejected;
           await expect(promise2).not.to.be.rejected;
         });
         });
 
 
-        it('skips uniqueness checking for blank values', async function () {
+        it('skips uniqueness checking for undefined value', async function () {
           const dbs = new DatabaseSchema();
           const dbs = new DatabaseSchema();
           dbs.defineModel({
           dbs.defineModel({
             name: 'model',
             name: 'model',
@@ -2714,10 +2884,38 @@ describe('PropertyUniquenessValidator', function () {
           });
           });
           const puv = dbs.getService(PropertyUniquenessValidator);
           const puv = dbs.getService(PropertyUniquenessValidator);
           let invoked = 0;
           let invoked = 0;
-          dbs
-            .getService(BlankValuesService)
-            .setBlankValuesOf(DataType.STRING, ['val2']);
-          const modelData = {foo: 'val1', bar: 'val2'};
+          const modelData = {foo: 'val1', bar: undefined};
+          const countMethod = where => {
+            if (invoked === 0)
+              expect(where).to.be.eql({
+                [DEF_PK]: {neq: 1},
+                foo: 'val1',
+              });
+            invoked++;
+            return 0;
+          };
+          await puv.validate(countMethod, 'patchById', 'model', modelData, 1);
+          expect(invoked).to.be.eql(1);
+        });
+
+        it('skips uniqueness checking for an empty string', async function () {
+          const dbs = new DatabaseSchema();
+          dbs.defineModel({
+            name: 'model',
+            properties: {
+              foo: {
+                type: DataType.STRING,
+                unique: PropertyUniqueness.SPARSE,
+              },
+              bar: {
+                type: DataType.STRING,
+                unique: PropertyUniqueness.SPARSE,
+              },
+            },
+          });
+          const puv = dbs.getService(PropertyUniquenessValidator);
+          let invoked = 0;
+          const modelData = {foo: 'val1', bar: ''};
           const countMethod = where => {
           const countMethod = where => {
             if (invoked === 0)
             if (invoked === 0)
               expect(where).to.be.eql({
               expect(where).to.be.eql({

+ 7 - 12
src/definition/model/properties/required-property-validator.js

@@ -1,6 +1,5 @@
 import {DataType} from './data-type.js';
 import {DataType} from './data-type.js';
 import {Service} from '@e22m4u/js-service';
 import {Service} from '@e22m4u/js-service';
-import {BlankValuesService} from '@e22m4u/js-empty-values';
 import {InvalidArgumentError} from '../../../errors/index.js';
 import {InvalidArgumentError} from '../../../errors/index.js';
 import {ModelDefinitionUtils} from '../model-definition-utils.js';
 import {ModelDefinitionUtils} from '../model-definition-utils.js';
 
 
@@ -44,7 +43,6 @@ export class RequiredPropertyValidator extends Service {
         ModelDefinitionUtils,
         ModelDefinitionUtils,
       ).getPropertiesDefinitionInBaseModelHierarchy(modelName);
       ).getPropertiesDefinitionInBaseModelHierarchy(modelName);
     const propNames = Object.keys(isPartial ? modelData : propDefs);
     const propNames = Object.keys(isPartial ? modelData : propDefs);
-    const blankValuesService = this.getService(BlankValuesService);
     for (const propName of propNames) {
     for (const propName of propNames) {
       const propDef = propDefs[propName];
       const propDef = propDefs[propName];
       if (!propDef || typeof propDef !== 'object') {
       if (!propDef || typeof propDef !== 'object') {
@@ -52,16 +50,13 @@ export class RequiredPropertyValidator extends Service {
       }
       }
       // проверка основного значения
       // проверка основного значения
       const propValue = modelData[propName];
       const propValue = modelData[propName];
-      if (propDef.required) {
-        const propType = propDef.type || DataType.ANY;
-        if (blankValuesService.isBlankOf(propType, propValue)) {
-          throw new InvalidArgumentError(
-            'Property %v of the model %v is required, but %v was given.',
-            propName,
-            modelName,
-            propValue,
-          );
-        }
+      if (propDef.required && propValue == null) {
+        throw new InvalidArgumentError(
+          'Property %v of the model %v is required, but %v was given.',
+          propName,
+          modelName,
+          propValue,
+        );
       }
       }
       // проверка вложенного объекта
       // проверка вложенного объекта
       if (
       if (

+ 7 - 46
src/definition/model/properties/required-property-validator.spec.js

@@ -1,9 +1,8 @@
 import {expect} from 'chai';
 import {expect} from 'chai';
+import {DataType} from './data-type.js';
 import {format} from '@e22m4u/js-format';
 import {format} from '@e22m4u/js-format';
 import {DatabaseSchema} from '../../../database-schema.js';
 import {DatabaseSchema} from '../../../database-schema.js';
 import {RequiredPropertyValidator} from './required-property-validator.js';
 import {RequiredPropertyValidator} from './required-property-validator.js';
-import {DataType} from './data-type.js';
-import {BlankValuesService} from '@e22m4u/js-empty-values';
 
 
 describe('RequiredPropertyValidator', function () {
 describe('RequiredPropertyValidator', function () {
   describe('validate', function () {
   describe('validate', function () {
@@ -84,11 +83,9 @@ describe('RequiredPropertyValidator', function () {
       S.validate('model', {foo: 'bar'});
       S.validate('model', {foo: 'bar'});
     });
     });
 
 
-    it('should not throw an error if a required property is not blank', function () {
+    it('should not throw an error if a required property is defined', function () {
       const dbs = new DatabaseSchema();
       const dbs = new DatabaseSchema();
       const S = dbs.getService(RequiredPropertyValidator);
       const S = dbs.getService(RequiredPropertyValidator);
-      const blankValues = S.getService(BlankValuesService);
-      blankValues.setBlankValues([undefined]);
       dbs.defineModel({
       dbs.defineModel({
         name: 'model',
         name: 'model',
         properties: {
         properties: {
@@ -101,11 +98,9 @@ describe('RequiredPropertyValidator', function () {
       S.validate('model', {foo: 'bar'});
       S.validate('model', {foo: 'bar'});
     });
     });
 
 
-    it('should throw an error if a required property is blank', function () {
+    it('should throw an error if a required property is undefined', function () {
       const dbs = new DatabaseSchema();
       const dbs = new DatabaseSchema();
       const S = dbs.getService(RequiredPropertyValidator);
       const S = dbs.getService(RequiredPropertyValidator);
-      const blankValues = S.getService(BlankValuesService);
-      blankValues.setBlankValues([undefined]);
       dbs.defineModel({
       dbs.defineModel({
         name: 'model',
         name: 'model',
         properties: {
         properties: {
@@ -126,8 +121,6 @@ describe('RequiredPropertyValidator', function () {
       it('should not throw an error if no data is provided for an embedded model', function () {
       it('should not throw an error if no data is provided for an embedded model', function () {
         const dbs = new DatabaseSchema();
         const dbs = new DatabaseSchema();
         const S = dbs.getService(RequiredPropertyValidator);
         const S = dbs.getService(RequiredPropertyValidator);
-        const blankValues = S.getService(BlankValuesService);
-        blankValues.setBlankValues([undefined]);
         dbs.defineModel({
         dbs.defineModel({
           name: 'modelA',
           name: 'modelA',
           properties: {
           properties: {
@@ -151,8 +144,6 @@ describe('RequiredPropertyValidator', function () {
       it('should throw an error if an embedded model is required but not provided', function () {
       it('should throw an error if an embedded model is required but not provided', function () {
         const dbs = new DatabaseSchema();
         const dbs = new DatabaseSchema();
         const S = dbs.getService(RequiredPropertyValidator);
         const S = dbs.getService(RequiredPropertyValidator);
-        const blankValues = S.getService(BlankValuesService);
-        blankValues.setBlankValues([undefined]);
         dbs.defineModel({
         dbs.defineModel({
           name: 'modelA',
           name: 'modelA',
           properties: {
           properties: {
@@ -181,8 +172,6 @@ describe('RequiredPropertyValidator', function () {
       it('should allow a model data to have properties without a specified schema', function () {
       it('should allow a model data to have properties without a specified schema', function () {
         const dbs = new DatabaseSchema();
         const dbs = new DatabaseSchema();
         const S = dbs.getService(RequiredPropertyValidator);
         const S = dbs.getService(RequiredPropertyValidator);
-        const blankValues = S.getService(BlankValuesService);
-        blankValues.setBlankValues([undefined]);
         dbs.defineModel({
         dbs.defineModel({
           name: 'modelA',
           name: 'modelA',
           properties: {
           properties: {
@@ -206,8 +195,6 @@ describe('RequiredPropertyValidator', function () {
       it('should allow omit a model data when its model has a required property', function () {
       it('should allow omit a model data when its model has a required property', function () {
         const dbs = new DatabaseSchema();
         const dbs = new DatabaseSchema();
         const S = dbs.getService(RequiredPropertyValidator);
         const S = dbs.getService(RequiredPropertyValidator);
-        const blankValues = S.getService(BlankValuesService);
-        blankValues.setBlankValues([undefined]);
         dbs.defineModel({
         dbs.defineModel({
           name: 'modelA',
           name: 'modelA',
           properties: {
           properties: {
@@ -232,8 +219,6 @@ describe('RequiredPropertyValidator', function () {
       it('should allow omit an optional property for an embedded model', function () {
       it('should allow omit an optional property for an embedded model', function () {
         const dbs = new DatabaseSchema();
         const dbs = new DatabaseSchema();
         const S = dbs.getService(RequiredPropertyValidator);
         const S = dbs.getService(RequiredPropertyValidator);
-        const blankValues = S.getService(BlankValuesService);
-        blankValues.setBlankValues([undefined]);
         dbs.defineModel({
         dbs.defineModel({
           name: 'modelA',
           name: 'modelA',
           properties: {
           properties: {
@@ -257,8 +242,6 @@ describe('RequiredPropertyValidator', function () {
       it('should throw an error if a required property is not provided', function () {
       it('should throw an error if a required property is not provided', function () {
         const dbs = new DatabaseSchema();
         const dbs = new DatabaseSchema();
         const S = dbs.getService(RequiredPropertyValidator);
         const S = dbs.getService(RequiredPropertyValidator);
-        const blankValues = S.getService(BlankValuesService);
-        blankValues.setBlankValues([undefined]);
         dbs.defineModel({
         dbs.defineModel({
           name: 'modelA',
           name: 'modelA',
           properties: {
           properties: {
@@ -289,8 +272,6 @@ describe('RequiredPropertyValidator', function () {
       it('should allow omit an optional array', function () {
       it('should allow omit an optional array', function () {
         const dbs = new DatabaseSchema();
         const dbs = new DatabaseSchema();
         const S = dbs.getService(RequiredPropertyValidator);
         const S = dbs.getService(RequiredPropertyValidator);
-        const blankValues = S.getService(BlankValuesService);
-        blankValues.setBlankValues([undefined]);
         dbs.defineModel({
         dbs.defineModel({
           name: 'modelA',
           name: 'modelA',
           properties: {
           properties: {
@@ -315,8 +296,6 @@ describe('RequiredPropertyValidator', function () {
       it('should allow a required array to be empty', function () {
       it('should allow a required array to be empty', function () {
         const dbs = new DatabaseSchema();
         const dbs = new DatabaseSchema();
         const S = dbs.getService(RequiredPropertyValidator);
         const S = dbs.getService(RequiredPropertyValidator);
-        const blankValues = S.getService(BlankValuesService);
-        blankValues.setBlankValues([undefined]);
         dbs.defineModel({
         dbs.defineModel({
           name: 'modelA',
           name: 'modelA',
           properties: {
           properties: {
@@ -339,11 +318,9 @@ describe('RequiredPropertyValidator', function () {
         S.validate('modelA', {array: []});
         S.validate('modelA', {array: []});
       });
       });
 
 
-      it('should allow omit an optional array even if the item model has a required property', function () {
+      it('should allow omit an optional array even if an item model has a required property', function () {
         const dbs = new DatabaseSchema();
         const dbs = new DatabaseSchema();
         const S = dbs.getService(RequiredPropertyValidator);
         const S = dbs.getService(RequiredPropertyValidator);
-        const blankValues = S.getService(BlankValuesService);
-        blankValues.setBlankValues([undefined]);
         dbs.defineModel({
         dbs.defineModel({
           name: 'modelA',
           name: 'modelA',
           properties: {
           properties: {
@@ -366,11 +343,9 @@ describe('RequiredPropertyValidator', function () {
         S.validate('modelA', {});
         S.validate('modelA', {});
       });
       });
 
 
-      it('should allow an empty array even if the item model has a required property', function () {
+      it('should allow an empty array even if an item model has a required property', function () {
         const dbs = new DatabaseSchema();
         const dbs = new DatabaseSchema();
         const S = dbs.getService(RequiredPropertyValidator);
         const S = dbs.getService(RequiredPropertyValidator);
-        const blankValues = S.getService(BlankValuesService);
-        blankValues.setBlankValues([undefined]);
         dbs.defineModel({
         dbs.defineModel({
           name: 'modelA',
           name: 'modelA',
           properties: {
           properties: {
@@ -396,8 +371,6 @@ describe('RequiredPropertyValidator', function () {
       it('should throw an error when a required array is not provided', function () {
       it('should throw an error when a required array is not provided', function () {
         const dbs = new DatabaseSchema();
         const dbs = new DatabaseSchema();
         const S = dbs.getService(RequiredPropertyValidator);
         const S = dbs.getService(RequiredPropertyValidator);
-        const blankValues = S.getService(BlankValuesService);
-        blankValues.setBlankValues([undefined]);
         dbs.defineModel({
         dbs.defineModel({
           name: 'modelA',
           name: 'modelA',
           properties: {
           properties: {
@@ -427,8 +400,6 @@ describe('RequiredPropertyValidator', function () {
       it('should allow omit an optional property of the item model', function () {
       it('should allow omit an optional property of the item model', function () {
         const dbs = new DatabaseSchema();
         const dbs = new DatabaseSchema();
         const S = dbs.getService(RequiredPropertyValidator);
         const S = dbs.getService(RequiredPropertyValidator);
-        const blankValues = S.getService(BlankValuesService);
-        blankValues.setBlankValues([undefined]);
         dbs.defineModel({
         dbs.defineModel({
           name: 'modelA',
           name: 'modelA',
           properties: {
           properties: {
@@ -454,8 +425,6 @@ describe('RequiredPropertyValidator', function () {
       it('should allow an item date to have properties without a specified schema', function () {
       it('should allow an item date to have properties without a specified schema', function () {
         const dbs = new DatabaseSchema();
         const dbs = new DatabaseSchema();
         const S = dbs.getService(RequiredPropertyValidator);
         const S = dbs.getService(RequiredPropertyValidator);
-        const blankValues = S.getService(BlankValuesService);
-        blankValues.setBlankValues([undefined]);
         dbs.defineModel({
         dbs.defineModel({
           name: 'modelA',
           name: 'modelA',
           properties: {
           properties: {
@@ -480,11 +449,9 @@ describe('RequiredPropertyValidator', function () {
     });
     });
 
 
     describe('isPartial', function () {
     describe('isPartial', function () {
-      it('should throw an error if a required property is blank', function () {
+      it('should throw an error if a required property is undefined', function () {
         const dbs = new DatabaseSchema();
         const dbs = new DatabaseSchema();
         const S = dbs.getService(RequiredPropertyValidator);
         const S = dbs.getService(RequiredPropertyValidator);
-        const blankValues = S.getService(BlankValuesService);
-        blankValues.setBlankValues([undefined]);
         dbs.defineModel({
         dbs.defineModel({
           name: 'model',
           name: 'model',
           properties: {
           properties: {
@@ -501,11 +468,9 @@ describe('RequiredPropertyValidator', function () {
         );
         );
       });
       });
 
 
-      it('should not validate a required but not provided properties', function () {
+      it('should not validate required but not provided properties', function () {
         const dbs = new DatabaseSchema();
         const dbs = new DatabaseSchema();
         const S = dbs.getService(RequiredPropertyValidator);
         const S = dbs.getService(RequiredPropertyValidator);
-        const blankValues = S.getService(BlankValuesService);
-        blankValues.setBlankValues([undefined]);
         dbs.defineModel({
         dbs.defineModel({
           name: 'model',
           name: 'model',
           properties: {
           properties: {
@@ -521,8 +486,6 @@ describe('RequiredPropertyValidator', function () {
       it('should validate not provided properties of an embedded model', function () {
       it('should validate not provided properties of an embedded model', function () {
         const dbs = new DatabaseSchema();
         const dbs = new DatabaseSchema();
         const S = dbs.getService(RequiredPropertyValidator);
         const S = dbs.getService(RequiredPropertyValidator);
-        const blankValues = S.getService(BlankValuesService);
-        blankValues.setBlankValues([undefined]);
         dbs.defineModel({
         dbs.defineModel({
           name: 'modelA',
           name: 'modelA',
           properties: {
           properties: {
@@ -551,8 +514,6 @@ describe('RequiredPropertyValidator', function () {
       it('should validate not provided properties of an item model', function () {
       it('should validate not provided properties of an item model', function () {
         const dbs = new DatabaseSchema();
         const dbs = new DatabaseSchema();
         const S = dbs.getService(RequiredPropertyValidator);
         const S = dbs.getService(RequiredPropertyValidator);
-        const blankValues = S.getService(BlankValuesService);
-        blankValues.setBlankValues([undefined]);
         dbs.defineModel({
         dbs.defineModel({
           name: 'modelA',
           name: 'modelA',
           properties: {
           properties: {