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

refactor: removes validate and transform options

e22m4u 1 неделя назад
Родитель
Сommit
55d0ca6faa
61 измененных файлов с 32 добавлено и 10684 удалено
  1. 5 531
      README.md
  2. 24 846
      dist/cjs/index.cjs
  3. 0 4
      src/adapter/adapter.js
  4. 3 15
      src/adapter/adapter.spec.js
  5. 0 14
      src/adapter/decorator/data-transformation-decorator.d.ts
  6. 0 54
      src/adapter/decorator/data-transformation-decorator.js
  7. 0 193
      src/adapter/decorator/data-transformation-decorator.spec.js
  8. 0 14
      src/adapter/decorator/data-validation-decorator.d.ts
  9. 0 54
      src/adapter/decorator/data-validation-decorator.js
  10. 0 105
      src/adapter/decorator/data-validation-decorator.spec.js
  11. 0 2
      src/adapter/decorator/index.d.ts
  12. 0 2
      src/adapter/decorator/index.js
  13. 0 2
      src/definition/model/index.d.ts
  14. 0 2
      src/definition/model/index.js
  15. 0 16
      src/definition/model/model-data-transformer.d.ts
  16. 0 170
      src/definition/model/model-data-transformer.js
  17. 0 2312
      src/definition/model/model-data-transformer.spec.js
  18. 0 16
      src/definition/model/model-data-validator.d.ts
  19. 0 318
      src/definition/model/model-data-validator.js
  20. 0 4528
      src/definition/model/model-data-validator.spec.js
  21. 0 2
      src/definition/model/properties/index.d.ts
  22. 0 2
      src/definition/model/properties/index.js
  23. 0 169
      src/definition/model/properties/properties-definition-validator.js
  24. 0 162
      src/definition/model/properties/properties-definition-validator.spec.js
  25. 0 4
      src/definition/model/properties/property-definition.d.ts
  26. 0 3
      src/definition/model/properties/property-transformer/builtin/index.d.ts
  27. 0 3
      src/definition/model/properties/property-transformer/builtin/index.js
  28. 0 6
      src/definition/model/properties/property-transformer/builtin/to-lower-case-transformer.d.ts
  29. 0 19
      src/definition/model/properties/property-transformer/builtin/to-lower-case-transformer.js
  30. 0 39
      src/definition/model/properties/property-transformer/builtin/to-lower-case-transformer.spec.js
  31. 0 6
      src/definition/model/properties/property-transformer/builtin/to-upper-case-transformer.d.ts
  32. 0 19
      src/definition/model/properties/property-transformer/builtin/to-upper-case-transformer.js
  33. 0 39
      src/definition/model/properties/property-transformer/builtin/to-upper-case-transformer.spec.js
  34. 0 6
      src/definition/model/properties/property-transformer/builtin/trim-transformer.d.ts
  35. 0 19
      src/definition/model/properties/property-transformer/builtin/trim-transformer.js
  36. 0 39
      src/definition/model/properties/property-transformer/builtin/trim-transformer.spec.js
  37. 0 2
      src/definition/model/properties/property-transformer/index.d.ts
  38. 0 2
      src/definition/model/properties/property-transformer/index.js
  39. 0 29
      src/definition/model/properties/property-transformer/property-transformer-registry.d.ts
  40. 0 76
      src/definition/model/properties/property-transformer/property-transformer-registry.js
  41. 0 133
      src/definition/model/properties/property-transformer/property-transformer-registry.spec.js
  42. 0 27
      src/definition/model/properties/property-transformer/property-transformer.d.ts
  43. 0 1
      src/definition/model/properties/property-transformer/property-transformer.js
  44. 0 3
      src/definition/model/properties/property-validator/builtin/index.d.ts
  45. 0 3
      src/definition/model/properties/property-validator/builtin/index.js
  46. 0 6
      src/definition/model/properties/property-validator/builtin/max-length-validator.d.ts
  47. 0 28
      src/definition/model/properties/property-validator/builtin/max-length-validator.js
  48. 0 100
      src/definition/model/properties/property-validator/builtin/max-length-validator.spec.js
  49. 0 6
      src/definition/model/properties/property-validator/builtin/min-length-validator.d.ts
  50. 0 28
      src/definition/model/properties/property-validator/builtin/min-length-validator.js
  51. 0 100
      src/definition/model/properties/property-validator/builtin/min-length-validator.spec.js
  52. 0 6
      src/definition/model/properties/property-validator/builtin/regexp-validator.d.ts
  53. 0 30
      src/definition/model/properties/property-validator/builtin/regexp-validator.js
  54. 0 102
      src/definition/model/properties/property-validator/builtin/regexp-validator.spec.js
  55. 0 2
      src/definition/model/properties/property-validator/index.d.ts
  56. 0 2
      src/definition/model/properties/property-validator/index.js
  57. 0 29
      src/definition/model/properties/property-validator/property-validator-registry.d.ts
  58. 0 76
      src/definition/model/properties/property-validator/property-validator-registry.js
  59. 0 132
      src/definition/model/properties/property-validator/property-validator-registry.spec.js
  60. 0 25
      src/definition/model/properties/property-validator/property-validator.d.ts
  61. 0 1
      src/definition/model/properties/property-validator/property-validator.js

+ 5 - 531
README.md

@@ -15,14 +15,6 @@
 - [Источник данных](#источник-данных)
 - [Модель](#модель)
 - [Свойства](#свойства)
-- [Валидаторы](#валидаторы)
-  - [Глобальные валидаторы](#глобальные-валидаторы)
-  - [Регистрация глобальных валидаторов](#регистрация-глобальных-валидаторов)
-  - [Локальные валидаторы](#локальные-валидаторы)
-- [Трансформеры](#трансформеры)
-  - [Глобальные трансформеры](#глобальные-трансформеры)
-  - [Регистрация глобальных трансформеров](#регистрация-глобальных-трансформеров)
-  - [Локальные трансформеры](#локальные-трансформеры)
 - [Пустые значения](#пустые-значения)
   - [Переопределение пустых значений](#переопределение-пустых-значений)
 - [Репозиторий](#репозиторий)
@@ -86,10 +78,9 @@ const {DatabaseSchema} = require('@e22m4u/js-repository');
 Модуль позволяет абстрагироваться от различных интерфейсов баз данных,
 представляя их как именованные *источники данных*, подключаемые к *моделям*.
 *Модель* же описывает таблицу базы, колонки которой являются свойствами
-модели. Свойства модели могут иметь определенный *тип* допустимого значения,
-набор *валидаторов* и *трансформеров*, через которые проходят данные перед
-записью в базу. Кроме того, *модель* может определять классические связи
-«один к одному», «один ко многим» и другие типы отношений между моделями.
+модели. Свойства модели могут иметь определенный *тип* допустимого значения.
+Кроме того, *модель* может определять классические связи «один к одному»,
+«один ко многим» и другие типы отношений между моделями.
 
 Непосредственно чтение и запись данных производится с помощью *репозитория*,
 который есть у каждой модели с объявленным *источником данных*. Репозиторий
@@ -401,7 +392,6 @@ dbs.defineModel({
 - `columnType: string` тип колонки (определяется адаптером)
 - `required: boolean` объявить свойство обязательным
 - `default: any` значение по умолчанию
-- `validate: string | Function | array | object` см. [Валидаторы](#Валидаторы)
 - `unique: boolean | string` проверять значение на уникальность
 
 **Параметр `unique`**
@@ -483,522 +473,6 @@ dbs.defineModel({
 });
 ```
 
-## Валидаторы
-
-Валидаторы используются для проверки значения свойства перед записью в базу.
-Проверка значения валидатором выполняется сразу после проверки типа, указанного
-в определении свойства модели. [Пустые значения](#пустые-значения) пропускают
-проверку валидаторами, так как не имеют полезной нагрузки.
-
-### Глобальные валидаторы
-
-Модуль поставляется с набором глобальных валидаторов:
-
-- `regexp` проверка по регулярному выражению,  
-  *параметр: `string | RegExp` - регулярное выражение;*
-
-- `maxLength` максимальная длина строки или массива,  
-  *параметр: `number` - максимальная длина;*
-
-- `minLength` минимальная длина строки или массива,  
-  *параметр: `number` - минимальная длина;*
-
-Валидаторы указанные ниже находятся в разработке:
-
-- `isLowerCase` проверка регистра (только строчные буквы);
-- `isUpperCase` проверка регистра (только прописные буквы);
-- `isEmail` проверка формата электронного адреса;
-
-**Примеры**
-
-Использование глобального валидатора.
-
-```js
-dbs.defineModel({
-  name: 'user',
-  properties: {
-    email: {
-      type: DataType.STRING,
-      validate: 'isEmail',
-    },
-  },
-});
-```
-
-Использование глобальных валидаторов в виде массива.
-
-```js
-dbs.defineModel({
-  name: 'user',
-  properties: {
-    email: {
-      type: DataType.STRING,
-      validate: [
-        'isEmail',
-        'isLowerCase',
-      ],
-    },
-  },
-});
-```
-
-Использование глобальных валидаторов с передачей аргументов.
-
-```js
-dbs.defineModel({
-  name: 'user',
-  properties: {
-    name: {
-      type: DataType.STRING,
-      validate: {
-        minLength: 2,
-        maxLength: 24,
-        regexp: /^[a-zA-Z-']+$/,
-      },
-    },
-  },
-});
-```
-
-Глобальные валидаторы без параметров могут принимать любые аргументы.
-
-```js
-dbs.defineModel({
-  name: 'user',
-  properties: {
-    email: {
-      type: DataType.STRING,
-      validate: {
-        maxLength: 100,
-        // так как валидатор "isEmail" не имеет параметров,
-        // его определение допускает передачу любого значения
-        // в качестве аргумента
-        isEmail: true,
-      },
-    },
-  },
-});
-```
-
-### Регистрация глобальных валидаторов
-
-Валидатором является функция, в которую передается значение соответствующего
-поля перед записью в базу. Если во время проверки функция возвращает `false`,
-то выбрасывается стандартная ошибка. Подмена стандартной ошибки возможна
-с помощью выброса пользовательской ошибки непосредственно внутри проверяющей
-функции.
-
-Регистрация глобального валидатора выполняется методом `addValidator` сервиса
-`PropertyValidatorRegistry`, который принимает название валидатора и функцию
-для проверки значения.
-
-**Примеры**
-
-Регистрация глобального валидатора для проверки формата UUID.
-
-```js
-import {createError} from 'http-errors';
-import {format} from '@e22m4u/js-format';
-import {Errorf} from '@e22m4u/js-format';
-import {PropertyValidatorRegistry} from '@e22m4u/js-repository';
-
-// получение экземпляра сервиса
-const pvr = dbs.getService(PropertyValidatorRegistry);
-
-// регулярные выражения для разных версий UUID
-const uuidRegex = {
-  any: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,
-  v4: /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,
-};
-
-// регистрация глобального валидатора "isUuid",
-// принимающего объект настроек со свойством "version"
-pvr.addValidator('isUuid', (value, options, context) => {
-  // value   - проверяемое значение;
-  // options - параметры валидатора;
-  // context - информация о проверяемом свойстве;
-  console.log(options);
-  // {
-  //   version: 'v4'
-  // }
-  console.log(context);
-  // {
-  //   validatorName: 'isUuid',
-  //   modelName: 'device',
-  //   propName: 'deviceId'
-  // }
-
-  // пустые значения не передаются в валидаторы
-  // (условие ниже никогда не сработает)
-  if (typeof value !== 'string') return false;
-  // поиск регулярного выражения для указанной
-  // версии UUID (из параметров валидатора)
-  const version = options?.version || 'any';
-  const regex = uuidRegex[version];
-  // если регулярное выражение не найдено,
-  // то выбрасывается внутренняя ошибка
-  if (!regex)
-    throw new Errorf(
-      'Invalid UUID version %v specified for validator.',
-      version,
-    );
-  // при неудачной проверке выбрасывается
-  // ошибка 400 BadRequest
-  if (!regex.test(value)) {
-    const versionString = version !== 'any' ? ` (version ${version})` : '';
-    throw createError(400, format(
-      'The property %v of the model %v must be a valid UUID%s.',
-      context.propName,
-      context.modelName,
-      versionString,
-    ));
-  }
-  // при успешной проверке возвращается true,
-  // в противном случае выбрасывается стандартная
-  // ошибка проверки
-  return true;
-});
-```
-
-Использование глобального валидатора в определении свойства.
-
-```js
-// определение модели "device"
-dbs.defineModel({
-  name: 'device',
-  properties: {
-    deviceId: {
-      type: DataType.STRING,
-      required: true,
-      validate: {
-        // значение {version: 'v4'} будет передаваться
-        // вторым аргументом в функцию-валидатор
-        isUuid: {version: 'v4'},
-      },
-    },
-  },
-});
-```
-
-### Локальные валидаторы
-
-Функция-валидатор может быть передана непосредственно в определении свойства
-без предварительной регистрации. Для этого достаточно передать функцию
-в параметр `validate` в качестве значения или элемента массива наряду
-с другими валидаторами.
-
-**Примеры**
-
-Использование локального валидатора для проверки сложности пароля.
-
-```js
-// валидатор `passwordStrength` проверяет сложность пароля
-function passwordStrength(value, options, context) {
-  // value   - проверяемое значение;
-  // options - не используется;
-  // context - информация о свойстве;
-  console.log(context);
-  // {
-  //   validatorName: 'passwordStrength',
-  //   modelName: 'user',
-  //   propName: 'password'
-  // }
-  const errors = [];
-  if (value.length < 8)
-    errors.push('must be at least 8 characters long');
-  if (!/\d/.test(value))
-    errors.push('must contain at least one number');
-  if (!/[a-zA-Z]/.test(value))
-    errors.push('must contain at least one letter');
-  // если одно из условий сработало,
-  // то выбрасывается ошибка
-  if (errors.length > 0)
-    throw createError(400, format(
-      'Value of the property %v of the model %v %s.',
-      context.propName,
-      context.modelName,
-      errors.join(', '),
-    ));
-  // при успешной проверке возвращается true,
-  // в противном случае выбрасывается стандартная
-  // ошибка проверки
-  return true;
-}
-
-// определение модели "user"
-dbs.defineModel({
-  name: 'user',
-  properties: {
-    password: {
-      type: DataType.STRING,
-      required: true,
-      validate: passwordStrength, // <=
-      // или
-      // validate: [passwordStrength, ...]
-    },
-  },
-});
-```
-
-Использование анонимной функции-валидатора для проверки слага.
-
-```js
-// определение модели "article"
-dbs.defineModel({
-  name: 'article',
-  properties: {
-    slug: {
-      type: DataType.STRING,
-      validate: (value) => {
-        const re = /^[a-z0-9]+(-[a-z0-9]+)*$/;
-        return re.test(value);
-      },
-    },
-  },
-});
-```
-
-## Трансформеры
-
-Трансформеры используются для модификации значения свойства перед проверкой
-типа и передачей данных в базу. Трансформеры позволяют автоматически очищать
-или приводить данные к нужному формату. [Пустые значения](#Пустые-значения)
-не передаются в трансформеры, так как не имеют полезной нагрузки.
-
-### Глобальные трансформеры
-
-Модуль поставляется с набором глобальных трансформеров:
-
-- `trim` удаление пробельных символов с начала и конца строки;
-- `toUpperCase` перевод строки в верхний регистр;
-- `toLowerCase` перевод строки в нижний регистр;
-
-Трансформеры указанные ниже находятся в разработке:
-
-- `cut` усечение строки или массива до указанной длины,  
-  *параметр: `number` - максимальная длина;*
-
-- `truncate` усечение строки с добавлением троеточия,  
-  *параметр: `number` - максимальная длина;*
-
-- `capitalize` перевод первой буквы каждого слова в верхний регистр,  
-  *параметр: `{firstWordOnly?: boolean}`;*
-
-**Примеры**
-
-Использование глобального трансформера.
-
-```js
-dbs.defineModel({
-  name: 'user',
-  properties: {
-    username: {
-      type: DataType.STRING,
-      transform: 'toLowerCase',
-    },
-  },
-});
-```
-
-Использование глобальных трансформеров в виде массива.
-
-```js
-dbs.defineModel({
-  name: 'user',
-  properties: {
-    firstName: {
-      type: DataType.STRING,
-      transform: [
-        'trim',
-        'capitalize',
-      ],
-    },
-  },
-});
-```
-
-Использование глобальных трансформеров с передачей аргументов.
-
-```js
-dbs.defineModel({
-  name: 'article',
-  properties: {
-    annotation: {
-      type: DataType.STRING,
-      transform: {
-        truncate: 200,
-        capitalize: {firstWordOnly: true},
-      },
-    },
-  },
-});
-```
-
-Глобальные трансформеры без параметров могут принимать любые аргументы.
-
-```js
-dbs.defineModel({
-  name: 'user',
-  properties: {
-    firstName: {
-      type: DataType.STRING,
-      transform: {
-        cut: 60,
-        // так как трансформер "trim" не имеет параметров,
-        // его определение допускает передачу любого значения
-        // в качестве аргумента
-        trim: true,
-      },
-    },
-  },
-});
-```
-
-### Регистрация глобальных трансформеров
-
-Трансформером является функция, которая принимает значение свойства и возвращает
-новое значение. Функция может быть как синхронной, так и асинхронной (возвращать
-`Promise`).
-
-Регистрация глобального трансформера выполняется методом `addTransformer`
-сервиса `PropertyTransformerRegistry`, который принимает название трансформера
-и саму функцию.
-
-**Примеры**
-
-Регистрация глобального трансформера для удаления HTML-тегов.
-
-```js
-import {PropertyTransformerRegistry} from '@e22m4u/js-repository';
-
-// получение экземпляра сервиса
-const ptr = dbs.getService(PropertyTransformerRegistry);
-
-// регистрация глобального трансформера "stripTags"
-ptr.addTransformer('stripTags', (value, options, context) => {
-  // value   - трансформируемое значение;
-  // options - настройки трансформера (если переданы);
-  // context - информация о свойстве;
-  console.log(context);
-  // {
-  //   transformerName: 'stripTags',
-  //   modelName: 'comment',
-  //   propName: 'text'
-  // }
-  
-  if (typeof value !== 'string')
-    return value; // возвращаем как есть, если не строка
-  
-  return value.replace(/<[^>]*>?/gm, '');
-});
-```
-
-Использование глобального трансформера в определении модели.
-
-```js
-dbs.defineModel({
-  name: 'comment',
-  properties: {
-    text: {
-      type: DataType.STRING,
-      transform: 'stripTags',
-    },
-  },
-});
-```
-
-### Локальные трансформеры
-
-Функция-трансформер может быть передана непосредственно в определении свойства без предварительной регистрации. Для этого достаточно передать функцию в параметр `transform` в качестве значения или элемента массива.
-
-**Примеры**
-
-Использование локального трансформера для нормализации имен.
-
-```js
-// функция для нормализации имени
-function normalizeName(value, options, context) {
-  // value   - трансформируемое значение
-  // options - не используется
-  // context - информация о свойстве
-  if (!value || typeof value !== 'string') return value;
-  return value
-    .trim()        // удаление пробелов в начале и конце
-    .toLowerCase() // перевод к нижнему регистру
-    .split(' ')    // разделение на слова
-    // перевод к верхнему регистру первой буквы каждого слова
-    .map(word => word.charAt(0).toUpperCase() + word.slice(1))
-    .join(' ');    // сборка массива в строку
-}
-
-// определение модели "user"
-dbs.defineModel({
-  name: 'user',
-  properties: {
-    firstName: {
-      type: DataType.STRING,
-      transform: normalizeName, // <=
-    },
-    lastName: {
-      type: DataType.STRING,
-      transform: normalizeName, // <=
-    },
-  },
-});
-```
-
-Использование локального асинхронного трансформера для хэширования пароля.
-
-```js
-import * as bcrypt from 'bcrypt';
-
-// асинхронная функция для хеширования значения
-async function hash(value, options, context) {
-  // value   - трансформируемое значение
-  // options - не используется
-  // context - информация о свойстве
-  console.log(context);
-  // {
-  //   transformerName: 'hash',
-  //   modelName: 'user',
-  //   propName: 'password'
-  // }
-  const saltRounds = 10;
-  return bcrypt.hash(value, saltRounds);
-}
-
-// определение модели "user"
-dbs.defineModel({
-  name: 'user',
-  properties: {
-    password: {
-      type: DataType.STRING,
-      transform: hash, // <=
-      // или
-      // transform: [hash, ...]
-    },
-  },
-});
-```
-
-Использование анонимной функции-трансформера для коррекции слага.
-
-```js
-dbs.defineModel({
-  name: 'article',
-  properties: {
-    slug: {
-      type: DataType.STRING,
-      transform: (value) => {
-        if (typeof value !== 'string') return value;
-        return value.toLowerCase().replace(/\s+/g, '-');
-      },
-    },
-  },
-});
-```
-
-
 ## Пустые значения
 
 Разные типы свойств имеют свои наборы пустых значений. Эти наборы используются
@@ -1071,8 +545,8 @@ emptyValuesService.setEmptyValuesOf(DataType.NUMBER, [undefined, null]);
 ```
 
 После этого, значение `0` для свойств типа `DataType.NUMBER` больше не будет
-считаться пустым и будет проходить проверки валидаторами, а также не будет
-заменяться значением по умолчанию.
+считаться пустым и будет проходить проверку с опцией `required`, а также
+не будет заменяться значением по умолчанию.
 
 ## Репозиторий
 

Разница между файлами не показана из-за своего большого размера
+ 24 - 846
dist/cjs/index.cjs


+ 0 - 4
src/adapter/adapter.js

@@ -4,10 +4,8 @@ import {Service} from '@e22m4u/js-service';
 import {NotImplementedError} from '../errors/index.js';
 import {InclusionDecorator} from './decorator/index.js';
 import {DefaultValuesDecorator} from './decorator/index.js';
-import {DataValidationDecorator} from './decorator/index.js';
 import {DataSanitizingDecorator} from './decorator/index.js';
 import {FieldsFilteringDecorator} from './decorator/index.js';
-import {DataTransformationDecorator} from './decorator/index.js';
 import {PropertyUniquenessDecorator} from './decorator/index.js';
 
 /**
@@ -57,8 +55,6 @@ export class Adapter extends Service {
     if (this.constructor !== Adapter) {
       this.getService(DataSanitizingDecorator).decorate(this);
       this.getService(DefaultValuesDecorator).decorate(this);
-      this.getService(DataTransformationDecorator).decorate(this);
-      this.getService(DataValidationDecorator).decorate(this);
       this.getService(PropertyUniquenessDecorator).decorate(this);
       this.getService(FieldsFilteringDecorator).decorate(this);
       this.getService(InclusionDecorator).decorate(this);

+ 3 - 15
src/adapter/adapter.spec.js

@@ -7,10 +7,8 @@ import {ServiceContainer} from '@e22m4u/js-service';
 import {DatabaseSchema} from '../database-schema.js';
 import {InclusionDecorator} from './decorator/index.js';
 import {DefaultValuesDecorator} from './decorator/index.js';
-import {DataValidationDecorator} from './decorator/index.js';
 import {DataSanitizingDecorator} from './decorator/index.js';
 import {FieldsFilteringDecorator} from './decorator/index.js';
-import {DataTransformationDecorator} from './decorator/index.js';
 import {PropertyUniquenessDecorator} from './decorator/index.js';
 
 const sandbox = chai.spy.sandbox();
@@ -45,11 +43,9 @@ describe('Adapter', function () {
       const dbs = new DatabaseSchema();
       const dec1 = dbs.getService(DataSanitizingDecorator);
       const dec2 = dbs.getService(DefaultValuesDecorator);
-      const dec3 = dbs.getService(DataTransformationDecorator);
-      const dec4 = dbs.getService(DataValidationDecorator);
-      const dec5 = dbs.getService(PropertyUniquenessDecorator);
-      const dec6 = dbs.getService(FieldsFilteringDecorator);
-      const dec7 = dbs.getService(InclusionDecorator);
+      const dec3 = dbs.getService(PropertyUniquenessDecorator);
+      const dec4 = dbs.getService(FieldsFilteringDecorator);
+      const dec5 = dbs.getService(InclusionDecorator);
       const order = [];
       const decorate = function (ctx) {
         expect(ctx).to.be.instanceof(Adapter);
@@ -60,8 +56,6 @@ describe('Adapter', function () {
       sandbox.on(dec3, 'decorate', decorate);
       sandbox.on(dec4, 'decorate', decorate);
       sandbox.on(dec5, 'decorate', decorate);
-      sandbox.on(dec6, 'decorate', decorate);
-      sandbox.on(dec7, 'decorate', decorate);
       new Adapter(dbs.container);
       expect(order).to.be.empty;
       expect(dec1.decorate).to.be.not.called;
@@ -69,8 +63,6 @@ describe('Adapter', function () {
       expect(dec3.decorate).to.be.not.called;
       expect(dec4.decorate).to.be.not.called;
       expect(dec5.decorate).to.be.not.called;
-      expect(dec6.decorate).to.be.not.called;
-      expect(dec7.decorate).to.be.not.called;
       class ExtendedAdapter extends Adapter {}
       new ExtendedAdapter(dbs.container);
       expect(order[0]).to.be.eql(dec1);
@@ -78,15 +70,11 @@ describe('Adapter', function () {
       expect(order[2]).to.be.eql(dec3);
       expect(order[3]).to.be.eql(dec4);
       expect(order[4]).to.be.eql(dec5);
-      expect(order[5]).to.be.eql(dec6);
-      expect(order[6]).to.be.eql(dec7);
       expect(dec1.decorate).to.be.called.once;
       expect(dec2.decorate).to.be.called.once;
       expect(dec3.decorate).to.be.called.once;
       expect(dec4.decorate).to.be.called.once;
       expect(dec5.decorate).to.be.called.once;
-      expect(dec6.decorate).to.be.called.once;
-      expect(dec7.decorate).to.be.called.once;
     });
   });
 

+ 0 - 14
src/adapter/decorator/data-transformation-decorator.d.ts

@@ -1,14 +0,0 @@
-import {Adapter} from '../adapter.js';
-import {Service} from '@e22m4u/js-service';
-
-/**
- * Data transformation decorator.
- */
-export declare class DataTransformationDecorator extends Service {
-  /**
-   * Decorate.
-   *
-   * @param adapter
-   */
-  decorate(adapter: Adapter): void;
-}

+ 0 - 54
src/adapter/decorator/data-transformation-decorator.js

@@ -1,54 +0,0 @@
-import {Adapter} from '../adapter.js';
-import {Service} from '@e22m4u/js-service';
-import {InvalidArgumentError} from '../../errors/index.js';
-import {ModelDataTransformer} from '../../definition/index.js';
-
-/**
- * Data transformation decorator.
- */
-export class DataTransformationDecorator extends Service {
-  /**
-   * Decorate.
-   *
-   * @param {Adapter} adapter
-   */
-  decorate(adapter) {
-    if (!adapter || !(adapter instanceof Adapter))
-      throw new InvalidArgumentError(
-        'The first argument of DataTransformerDecorator.decorate should be ' +
-          'an Adapter instance, but %v was given.',
-        adapter,
-      );
-    const transformer = this.getService(ModelDataTransformer);
-
-    const create = adapter.create;
-    adapter.create = async function (modelName, modelData, filter) {
-      modelData = await transformer.transform(modelName, modelData);
-      return create.call(this, modelName, modelData, filter);
-    };
-
-    const replaceById = adapter.replaceById;
-    adapter.replaceById = async function (modelName, id, modelData, filter) {
-      modelData = await transformer.transform(modelName, modelData);
-      return replaceById.call(this, modelName, id, modelData, filter);
-    };
-
-    const replaceOrCreate = adapter.replaceOrCreate;
-    adapter.replaceOrCreate = async function (modelName, modelData, filter) {
-      modelData = await transformer.transform(modelName, modelData);
-      return replaceOrCreate.call(this, modelName, modelData, filter);
-    };
-
-    const patch = adapter.patch;
-    adapter.patch = async function (modelName, modelData, where) {
-      modelData = await transformer.transform(modelName, modelData, true);
-      return patch.call(this, modelName, modelData, where);
-    };
-
-    const patchById = adapter.patchById;
-    adapter.patchById = async function (modelName, id, modelData, filter) {
-      modelData = await transformer.transform(modelName, modelData, true);
-      return patchById.call(this, modelName, id, modelData, filter);
-    };
-  }
-}

+ 0 - 193
src/adapter/decorator/data-transformation-decorator.spec.js

@@ -1,193 +0,0 @@
-import {expect} from 'chai';
-import {chai} from '../../chai.js';
-import {Adapter} from '../adapter.js';
-import {DatabaseSchema} from '../../database-schema.js';
-import {ModelDataTransformer} from '../../definition/index.js';
-
-const MODEL_NAME = 'myModel';
-const MODEL_DATA = {kind: 'modelData'};
-const TRANSFORMED_DATA = {kind: 'transformedData'};
-const WHERE_CLAUSE = {kind: {existed: true}};
-const FILTER_CLAUSE = {where: WHERE_CLAUSE};
-const DUMMY_ID = 1;
-
-class TestAdapter extends Adapter {
-  create(modelName, modelData, filter = undefined) {
-    expect(modelName).to.be.eq(MODEL_NAME);
-    expect(modelData).to.be.eql(TRANSFORMED_DATA);
-    expect(filter).to.be.eql(FILTER_CLAUSE);
-    return Promise.resolve(modelData);
-  }
-  replaceById(modelName, id, modelData, filter = undefined) {
-    expect(modelName).to.be.eq(MODEL_NAME);
-    expect(id).to.be.eq(DUMMY_ID);
-    expect(modelData).to.be.eql(TRANSFORMED_DATA);
-    expect(filter).to.be.eql(FILTER_CLAUSE);
-    return Promise.resolve(modelData);
-  }
-  replaceOrCreate(modelName, modelData, filter = undefined) {
-    expect(modelName).to.be.eq(MODEL_NAME);
-    expect(modelData).to.be.eql(TRANSFORMED_DATA);
-    expect(filter).to.be.eql(FILTER_CLAUSE);
-    return Promise.resolve(modelData);
-  }
-  patch(modelName, modelData, where = undefined) {
-    expect(modelName).to.be.eq(MODEL_NAME);
-    expect(modelData).to.be.eql(TRANSFORMED_DATA);
-    expect(where).to.be.eql(WHERE_CLAUSE);
-    return Promise.resolve(modelData);
-  }
-  patchById(modelName, id, modelData, filter = undefined) {
-    expect(modelName).to.be.eq(MODEL_NAME);
-    expect(id).to.be.eq(DUMMY_ID);
-    expect(modelData).to.be.eql(TRANSFORMED_DATA);
-    expect(filter).to.be.eql(FILTER_CLAUSE);
-    return Promise.resolve(modelData);
-  }
-}
-
-const dbs = new DatabaseSchema();
-dbs.defineModel({name: MODEL_NAME});
-const A = dbs.getService(TestAdapter);
-const T = dbs.getService(ModelDataTransformer);
-const sandbox = chai.spy.sandbox();
-
-describe('DataTransformationDecorator', function () {
-  afterEach(function () {
-    sandbox.restore();
-  });
-
-  describe('overrides the "create" method', function () {
-    it('transforms the given data', async function () {
-      sandbox.on(T, 'transform', () => TRANSFORMED_DATA);
-      const res = await A.create(MODEL_NAME, MODEL_DATA, FILTER_CLAUSE);
-      expect(res).to.be.eql(TRANSFORMED_DATA);
-      expect(T.transform).to.be.called.once;
-      expect(T.transform).to.be.called.with.exactly(MODEL_NAME, MODEL_DATA);
-    });
-
-    it('resolves the transformation promise', async function () {
-      sandbox.on(T, 'transform', () => Promise.resolve(TRANSFORMED_DATA));
-      const res = await A.create(MODEL_NAME, MODEL_DATA, FILTER_CLAUSE);
-      expect(res).to.be.eql(TRANSFORMED_DATA);
-      expect(T.transform).to.be.called.once;
-      expect(T.transform).to.be.called.with.exactly(MODEL_NAME, MODEL_DATA);
-    });
-  });
-
-  describe('overrides the "replaceById" method', function () {
-    it('transforms the given data', async function () {
-      sandbox.on(T, 'transform', () => TRANSFORMED_DATA);
-      const res = await A.replaceById(
-        MODEL_NAME,
-        DUMMY_ID,
-        MODEL_DATA,
-        FILTER_CLAUSE,
-      );
-      expect(res).to.be.eql(TRANSFORMED_DATA);
-      expect(T.transform).to.be.called.once;
-      expect(T.transform).to.be.called.with.exactly(MODEL_NAME, MODEL_DATA);
-    });
-
-    it('resolves the transformation promise', async function () {
-      sandbox.on(T, 'transform', () => Promise.resolve(TRANSFORMED_DATA));
-      const res = await A.replaceById(
-        MODEL_NAME,
-        DUMMY_ID,
-        MODEL_DATA,
-        FILTER_CLAUSE,
-      );
-      expect(res).to.be.eql(TRANSFORMED_DATA);
-      expect(T.transform).to.be.called.once;
-      expect(T.transform).to.be.called.with.exactly(MODEL_NAME, MODEL_DATA);
-    });
-  });
-
-  describe('overrides the "replaceOrCreate" method', function () {
-    it('transforms the given data', async function () {
-      sandbox.on(T, 'transform', () => TRANSFORMED_DATA);
-      const res = await A.replaceOrCreate(
-        MODEL_NAME,
-        MODEL_DATA,
-        FILTER_CLAUSE,
-      );
-      expect(res).to.be.eql(TRANSFORMED_DATA);
-      expect(T.transform).to.be.called.once;
-      expect(T.transform).to.be.called.with.exactly(MODEL_NAME, MODEL_DATA);
-    });
-
-    it('resolves the transformation promise', async function () {
-      sandbox.on(T, 'transform', () => Promise.resolve(TRANSFORMED_DATA));
-      const res = await A.replaceOrCreate(
-        MODEL_NAME,
-        MODEL_DATA,
-        FILTER_CLAUSE,
-      );
-      expect(res).to.be.eql(TRANSFORMED_DATA);
-      expect(T.transform).to.be.called.once;
-      expect(T.transform).to.be.called.with.exactly(MODEL_NAME, MODEL_DATA);
-    });
-  });
-
-  describe('overrides the "patch" method', function () {
-    it('transforms the given data', async function () {
-      sandbox.on(T, 'transform', () => TRANSFORMED_DATA);
-      const res = await A.patch(MODEL_NAME, MODEL_DATA, WHERE_CLAUSE);
-      expect(res).to.be.eql(TRANSFORMED_DATA);
-      expect(T.transform).to.be.called.once;
-      expect(T.transform).to.be.called.with.exactly(
-        MODEL_NAME,
-        MODEL_DATA,
-        true,
-      );
-    });
-
-    it('resolves the transformation promise', async function () {
-      sandbox.on(T, 'transform', () => Promise.resolve(TRANSFORMED_DATA));
-      const res = await A.patch(MODEL_NAME, MODEL_DATA, WHERE_CLAUSE);
-      expect(res).to.be.eql(TRANSFORMED_DATA);
-      expect(T.transform).to.be.called.once;
-      expect(T.transform).to.be.called.with.exactly(
-        MODEL_NAME,
-        MODEL_DATA,
-        true,
-      );
-    });
-  });
-
-  describe('overrides the "patchById" method', function () {
-    it('transforms the given data', async function () {
-      sandbox.on(T, 'transform', () => TRANSFORMED_DATA);
-      const res = await A.patchById(
-        MODEL_NAME,
-        DUMMY_ID,
-        MODEL_DATA,
-        FILTER_CLAUSE,
-      );
-      expect(res).to.be.eql(TRANSFORMED_DATA);
-      expect(T.transform).to.be.called.once;
-      expect(T.transform).to.be.called.with.exactly(
-        MODEL_NAME,
-        MODEL_DATA,
-        true,
-      );
-    });
-
-    it('resolves the transformation promise', async function () {
-      sandbox.on(T, 'transform', () => Promise.resolve(TRANSFORMED_DATA));
-      const res = await A.patchById(
-        MODEL_NAME,
-        DUMMY_ID,
-        MODEL_DATA,
-        FILTER_CLAUSE,
-      );
-      expect(res).to.be.eql(TRANSFORMED_DATA);
-      expect(T.transform).to.be.called.once;
-      expect(T.transform).to.be.called.with.exactly(
-        MODEL_NAME,
-        MODEL_DATA,
-        true,
-      );
-    });
-  });
-});

+ 0 - 14
src/adapter/decorator/data-validation-decorator.d.ts

@@ -1,14 +0,0 @@
-import {Service} from '@e22m4u/js-service';
-import {Adapter} from '../adapter.js';
-
-/**
- * Data validation decorator.
- */
-export declare class DataValidationDecorator extends Service {
-  /**
-   * Decorate.
-   *
-   * @param adapter
-   */
-  decorate(adapter: Adapter): void;
-}

+ 0 - 54
src/adapter/decorator/data-validation-decorator.js

@@ -1,54 +0,0 @@
-import {Adapter} from '../adapter.js';
-import {Service} from '@e22m4u/js-service';
-import {InvalidArgumentError} from '../../errors/index.js';
-import {ModelDataValidator} from '../../definition/index.js';
-
-/**
- * Data validation decorator.
- */
-export class DataValidationDecorator extends Service {
-  /**
-   * Decorate.
-   *
-   * @param {Adapter} adapter
-   */
-  decorate(adapter) {
-    if (!adapter || !(adapter instanceof Adapter))
-      throw new InvalidArgumentError(
-        'The first argument of DataValidationDecorator.decorate should be ' +
-          'an Adapter instance, but %v was given.',
-        adapter,
-      );
-    const validator = this.getService(ModelDataValidator);
-
-    const create = adapter.create;
-    adapter.create = function (modelName, modelData, filter) {
-      validator.validate(modelName, modelData);
-      return create.call(this, modelName, modelData, filter);
-    };
-
-    const replaceById = adapter.replaceById;
-    adapter.replaceById = function (modelName, id, modelData, filter) {
-      validator.validate(modelName, modelData);
-      return replaceById.call(this, modelName, id, modelData, filter);
-    };
-
-    const replaceOrCreate = adapter.replaceOrCreate;
-    adapter.replaceOrCreate = function (modelName, modelData, filter) {
-      validator.validate(modelName, modelData);
-      return replaceOrCreate.call(this, modelName, modelData, filter);
-    };
-
-    const patch = adapter.patch;
-    adapter.patch = function (modelName, modelData, where) {
-      validator.validate(modelName, modelData, true);
-      return patch.call(this, modelName, modelData, where);
-    };
-
-    const patchById = adapter.patchById;
-    adapter.patchById = function (modelName, id, modelData, filter) {
-      validator.validate(modelName, modelData, true);
-      return patchById.call(this, modelName, id, modelData, filter);
-    };
-  }
-}

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

@@ -1,105 +0,0 @@
-import {expect} from 'chai';
-import {chai} from '../../chai.js';
-import {Adapter} from '../adapter.js';
-import {DatabaseSchema} from '../../database-schema.js';
-import {ModelDataValidator} from '../../definition/index.js';
-
-const dbs = new DatabaseSchema();
-dbs.defineModel({name: 'model'});
-
-class TestAdapter extends Adapter {
-  // eslint-disable-next-line no-unused-vars
-  create(modelName, modelData, filter = undefined) {
-    return Promise.resolve(modelData);
-  }
-
-  // eslint-disable-next-line no-unused-vars
-  replaceById(modelName, id, modelData, filter = undefined) {
-    return Promise.resolve(modelData);
-  }
-
-  // eslint-disable-next-line no-unused-vars
-  replaceOrCreate(modelName, modelData, filter = undefined) {
-    return Promise.resolve(modelData);
-  }
-
-  // eslint-disable-next-line no-unused-vars
-  patch(modelName, modelData, where = undefined) {
-    return Promise.resolve(modelData);
-  }
-
-  // eslint-disable-next-line no-unused-vars
-  patchById(modelName, id, modelData, filter = undefined) {
-    return Promise.resolve(modelData);
-  }
-}
-
-const A = dbs.getService(TestAdapter);
-const V = dbs.getService(ModelDataValidator);
-const sandbox = chai.spy.sandbox();
-
-describe('DataValidationDecorator', function () {
-  afterEach(function () {
-    sandbox.restore();
-  });
-
-  it('overrides the "create" method and validates a given data', async function () {
-    const data = {kind: 'data'};
-    sandbox.on(V, 'validate', (modelName, modelData, isPartial = false) => {
-      expect(modelName).to.be.eq('model');
-      expect(modelData).to.be.eql(data);
-      expect(isPartial).to.be.false;
-    });
-    const res = await A.create('model', data);
-    expect(res).to.be.eql(data);
-    expect(V.validate).to.be.called.once;
-  });
-
-  it('overrides the "replaceById" method and validates a given data', async function () {
-    const data = {kind: 'data'};
-    sandbox.on(V, 'validate', (modelName, modelData, isPartial = false) => {
-      expect(modelName).to.be.eq('model');
-      expect(modelData).to.be.eql(data);
-      expect(isPartial).to.be.false;
-    });
-    const res = await A.replaceById('model', 1, data);
-    expect(res).to.be.eql(data);
-    expect(V.validate).to.be.called.once;
-  });
-
-  it('overrides the "replaceOrCreate" method and validates a given data', async function () {
-    const data = {kind: 'data'};
-    sandbox.on(V, 'validate', (modelName, modelData, isPartial = false) => {
-      expect(modelName).to.be.eq('model');
-      expect(modelData).to.be.eql(data);
-      expect(isPartial).to.be.false;
-    });
-    const res = await A.replaceOrCreate('model', data);
-    expect(res).to.be.eql(data);
-    expect(V.validate).to.be.called.once;
-  });
-
-  it('overrides the "patch" method and validates a given data', async function () {
-    const data = {kind: 'data'};
-    sandbox.on(V, 'validate', (modelName, modelData, isPartial = false) => {
-      expect(modelName).to.be.eq('model');
-      expect(modelData).to.be.eql(data);
-      expect(isPartial).to.be.true;
-    });
-    const res = await A.patch('model', data);
-    expect(res).to.be.eql(data);
-    expect(V.validate).to.be.called.once;
-  });
-
-  it('overrides the "patchById" method and validates a given data', async function () {
-    const data = {kind: 'data'};
-    sandbox.on(V, 'validate', (modelName, modelData, isPartial = false) => {
-      expect(modelName).to.be.eq('model');
-      expect(modelData).to.be.eql(data);
-      expect(isPartial).to.be.true;
-    });
-    const res = await A.patchById('model', 1, data);
-    expect(res).to.be.eql(data);
-    expect(V.validate).to.be.called.once;
-  });
-});

+ 0 - 2
src/adapter/decorator/index.d.ts

@@ -1,7 +1,5 @@
 export * from './inclusion-decorator.js';
 export * from './default-values-decorator.js';
 export * from './data-sanitizing-decorator.js';
-export * from './data-validation-decorator.js';
 export * from './fields-filtering-decorator.js';
-export * from './data-transformation-decorator.js';
 export * from './property-uniqueness-decorator.js';

+ 0 - 2
src/adapter/decorator/index.js

@@ -1,7 +1,5 @@
 export * from './inclusion-decorator.js';
 export * from './default-values-decorator.js';
 export * from './data-sanitizing-decorator.js';
-export * from './data-validation-decorator.js';
 export * from './fields-filtering-decorator.js';
-export * from './data-transformation-decorator.js';
 export * from './property-uniqueness-decorator.js';

+ 0 - 2
src/definition/model/index.d.ts

@@ -1,8 +1,6 @@
 export * from './relations/index.js';
 export * from './properties/index.js';
 export * from './model-definition.js';
-export * from './model-data-validator.js';
 export * from './model-data-sanitizer.js';
-export * from './model-data-transformer.js';
 export * from './model-definition-utils.js';
 export * from './model-definition-validator.js';

+ 0 - 2
src/definition/model/index.js

@@ -1,8 +1,6 @@
 export * from './relations/index.js';
 export * from './properties/index.js';
 export * from './model-definition.js';
-export * from './model-data-validator.js';
 export * from './model-data-sanitizer.js';
-export * from './model-data-transformer.js';
 export * from './model-definition-utils.js';
 export * from './model-definition-validator.js';

+ 0 - 16
src/definition/model/model-data-transformer.d.ts

@@ -1,16 +0,0 @@
-import {ModelData} from '../../types.js';
-import {Service} from '@e22m4u/js-service';
-import {ValueOrPromise} from '../../types.js';
-
-/**
- * Model data transformer.
- */
-export declare class ModelDataTransformer extends Service {
-  /**
-   * Transform.
-   *
-   * @param modelName
-   * @param modelData
-   */
-  transform(modelName: string, modelData: ModelData): ValueOrPromise<ModelData>;
-}

+ 0 - 170
src/definition/model/model-data-transformer.js

@@ -1,170 +0,0 @@
-import {Service} from '@e22m4u/js-service';
-import {cloneDeep} from '../../utils/index.js';
-import {isPlainObject} 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 (!isPlainObject(modelData))
-      throw new InvalidArgumentError(
-        'The data of the model %v should be an Object, but %v was 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 {*|Promise<*>}
-   */
-  _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,
-      transformerOrName,
-      transformerOptions = undefined,
-    ) => {
-      let transformerName, transformerFn;
-      // если второй аргумент является строкой, то строка
-      // воспринимается как название зарегистрированного
-      // трансформера
-      if (typeof transformerOrName === 'string') {
-        transformerName = transformerOrName;
-        transformerFn = transformerRegistry.getTransformer(transformerName);
-      }
-      // если второй аргумент является функцией,
-      // то функция воспринимается как трансформер
-      else if (typeof transformerOrName === 'function') {
-        transformerName =
-          transformerOrName.name && transformerOrName.name !== 'transform'
-            ? transformerOrName.name
-            : undefined;
-        transformerFn = transformerOrName;
-      }
-      // если второй аргумент не является строкой
-      // и функцией, то выбрасывается ошибка
-      else {
-        throw new InvalidArgumentError(
-          'Transformer must be a non-empty String or ' +
-            'a Function, but %v was given.',
-          transformerOrName,
-        );
-      }
-      const context = {transformerName, modelName, propName};
-      return transformerFn(value, transformerOptions, context);
-    };
-    // если значением опции "transform" является строка,
-    // то строка воспринимается как название трансформера
-    if (transformDef && typeof transformDef === 'string') {
-      return transformFn(propValue, transformDef);
-    }
-    // если значением опции "transform" является функция,
-    // то функция воспринимается как трансформер
-    else if (transformDef && typeof transformDef === 'function') {
-      return transformFn(propValue, transformDef);
-    }
-    // если значение опции "transform" является массив, то каждый
-    // элемент массива воспринимается как название трансформера
-    // или функция-валидатор
-    else if (Array.isArray(transformDef)) {
-      return transformDef.reduce((valueOrPromise, transformerOrName) => {
-        if (
-          !transformerOrName ||
-          (typeof transformerOrName !== 'string' &&
-            typeof transformerOrName !== 'function')
-        ) {
-          throw new InvalidArgumentError(
-            'The provided option "transform" for the property %v ' +
-              'in the model %v has an Array value that should contain ' +
-              'transformer names or transformer functions, but %v was given.',
-            propName,
-            modelName,
-            transformerOrName,
-          );
-        }
-        return transformPromise(valueOrPromise, value => {
-          return transformFn(value, transformerOrName);
-        });
-      }, propValue);
-    }
-    // если значение опции "transform" является объектом,
-    // то ключи объекта воспринимаются как названия трансформеров,
-    // а их значения аргументами
-    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,
-      );
-    }
-    // если значение опции "transform" не является строкой,
-    // функцией и массивом, то выбрасывается ошибка
-    else {
-      throw new InvalidArgumentError(
-        'The provided option "transform" for the property %v in the model %v ' +
-          'should be either a transformer name, a transformer function, an array ' +
-          'of transformer names or functions, or an object mapping transformer ' +
-          'names to their arguments, but %v was given.',
-        propName,
-        modelName,
-        transformDef,
-      );
-    }
-  }
-}

+ 0 - 2312
src/definition/model/model-data-transformer.spec.js

@@ -1,2312 +0,0 @@
-import {expect} from 'chai';
-import {format} from '@e22m4u/js-format';
-import {DataType} from './properties/index.js';
-import {DatabaseSchema} from '../../database-schema.js';
-import {EmptyValuesService} from '@e22m4u/js-empty-values';
-import {DefinitionRegistry} from '../definition-registry.js';
-import {ModelDataTransformer} from './model-data-transformer.js';
-import {PropertyTransformerRegistry} from './properties/index.js';
-
-describe('ModelDataTransformer', function () {
-  describe('transform', function () {
-    it('throws an error if the given model name is not defined', function () {
-      const dbs = new DatabaseSchema();
-      const T = dbs.getService(ModelDataTransformer);
-      const throwable = () => T.transform('model', {});
-      expect(throwable).to.throw('The model "model" is not defined.');
-    });
-
-    it('throws an error if the given model data is not a pure object', function () {
-      const dbs = new DatabaseSchema();
-      const T = dbs.getService(ModelDataTransformer);
-      const throwable = v => () => T.transform('model', v);
-      const error = v =>
-        format(
-          'The data of the model "model" should be an Object, but %s was given.',
-          v,
-        );
-      expect(throwable('str')).to.throw(error('"str"'));
-      expect(throwable('')).to.throw(error('""'));
-      expect(throwable(10)).to.throw(error('10'));
-      expect(throwable(0)).to.throw(error('0'));
-      expect(throwable(true)).to.throw(error('true'));
-      expect(throwable(false)).to.throw(error('false'));
-      expect(throwable(undefined)).to.throw(error('undefined'));
-      expect(throwable(null)).to.throw(error('null'));
-      expect(throwable([])).to.throw(error('Array'));
-      expect(throwable(new Date())).to.throw(error('Date'));
-    });
-
-    it('does nothing with the given model if no transformers are set', function () {
-      const dbs = new DatabaseSchema();
-      dbs.defineModel({
-        name: 'model',
-        properties: {
-          foo: DataType.STRING,
-          bar: {
-            type: DataType.STRING,
-            default: 'test',
-          },
-        },
-      });
-      const T = dbs.getService(ModelDataTransformer);
-      const modelData = {baz: 'qux'};
-      const res = T.transform('model', modelData);
-      expect(res).to.be.eql(modelData);
-    });
-
-    it('the option "transform" requires a non-empty String, a Function, an Array or an Object', function () {
-      const dbs = new DatabaseSchema();
-      dbs
-        .getService(PropertyTransformerRegistry)
-        .addTransformer('myTransformer', () => 'transformed');
-      dbs.defineModel({
-        name: 'model',
-        properties: {
-          foo: {
-            type: DataType.ANY,
-            transform: undefined,
-          },
-        },
-      });
-      const T = dbs.getService(ModelDataTransformer);
-      const throwable = v => () => {
-        const models = dbs.getService(DefinitionRegistry)['_models'];
-        models.model.properties.foo.transform = v;
-        T.transform('model', {foo: 'bar'});
-      };
-      const error = v =>
-        format(
-          'The provided option "transform" for the property "foo" in the model "model" ' +
-            'should be either a transformer name, a transformer function, an array ' +
-            'of transformer names or functions, or an object mapping transformer ' +
-            'names to their arguments, but %s was given.',
-          v,
-        );
-      expect(throwable('')).to.throw(error('""'));
-      expect(throwable(10)).to.throw(error('10'));
-      expect(throwable(0)).to.throw(error('0'));
-      expect(throwable(true)).to.throw(error('true'));
-      expect(throwable(false)).to.throw(error('false'));
-      throwable('myTransformer')();
-      throwable(() => 10)();
-      throwable(() => Promise.resolve('bar'))();
-      throwable(['myTransformer'])();
-      throwable([() => Promise.resolve('bar')])();
-      throwable([])();
-      throwable({myTransformer: true})();
-      throwable({})();
-    });
-
-    describe('when the option "transform" is a String', function () {
-      it('should not transform the non-provided property', function () {
-        let calls = 0;
-        const dbs = new DatabaseSchema();
-        const reg = dbs.getService(PropertyTransformerRegistry);
-        reg.addTransformer('myTransformer', () => {
-          calls++;
-          throw new Error('Should not to be called.');
-        });
-        dbs.defineModel({
-          name: 'model',
-          properties: {
-            foo: {
-              type: DataType.ANY,
-              transform: 'myTransformer',
-            },
-          },
-        });
-        const T = dbs.getService(ModelDataTransformer);
-        const res = T.transform('model', {});
-        expect(res).to.be.eql({});
-        expect(calls).to.be.eq(0);
-      });
-
-      it('should not transform non-provided properties when the option "isPartial" is true', function () {
-        let calls = 0;
-        const dbs = new DatabaseSchema();
-        const reg = dbs.getService(PropertyTransformerRegistry);
-        reg.addTransformer('myTransformer', value => {
-          calls++;
-          return String(value);
-        });
-        dbs.defineModel({
-          name: 'model',
-          properties: {
-            foo: {
-              type: DataType.ANY,
-              transform: 'myTransformer',
-            },
-            bar: {
-              type: DataType.ANY,
-              transform: 'myTransformer',
-            },
-          },
-        });
-        const T = dbs.getService(ModelDataTransformer);
-        const res = T.transform('model', {}, true);
-        expect(res).to.be.eql({});
-        expect(calls).to.be.eq(0);
-      });
-
-      it('should not transform undefined and null values', function () {
-        let calls = 0;
-        const dbs = new DatabaseSchema();
-        const reg = dbs.getService(PropertyTransformerRegistry);
-        reg.addTransformer('myTransformer', () => {
-          calls++;
-          throw new Error('Should not to be called.');
-        });
-        dbs.defineModel({
-          name: 'model',
-          properties: {
-            foo: {
-              type: DataType.ANY,
-              transform: 'myTransformer',
-            },
-          },
-        });
-        const T = dbs.getService(ModelDataTransformer);
-        const res1 = T.transform('model', {foo: undefined});
-        const res2 = T.transform('model', {foo: null});
-        expect(res1).to.be.eql({foo: undefined});
-        expect(res2).to.be.eql({foo: null});
-        expect(calls).to.be.eq(0);
-      });
-
-      it('should not transform the empty value', function () {
-        let calls = 0;
-        const dbs = new DatabaseSchema();
-        const reg = dbs.getService(PropertyTransformerRegistry);
-        reg.addTransformer('myTransformer', () => {
-          calls++;
-          throw new Error('Should not to be called.');
-        });
-        dbs.defineModel({
-          name: 'model',
-          properties: {
-            foo: {
-              type: DataType.ANY,
-              transform: 'myTransformer',
-            },
-          },
-        });
-        dbs.getService(EmptyValuesService).setEmptyValuesOf(DataType.ANY, [10]);
-        const T = dbs.getService(ModelDataTransformer);
-        const res = T.transform('model', {foo: 10});
-        expect(res).to.be.eql({foo: 10});
-        expect(calls).to.be.eq(0);
-      });
-
-      it('should transform the property by the transformer', function () {
-        let calls = 0;
-        const dbs = new DatabaseSchema();
-        const reg = dbs.getService(PropertyTransformerRegistry);
-        reg.addTransformer('myTransformer', value => {
-          calls++;
-          return String(value);
-        });
-        dbs.defineModel({
-          name: 'model',
-          properties: {
-            foo: {
-              type: DataType.ANY,
-              transform: 'myTransformer',
-            },
-          },
-        });
-        const T = dbs.getService(ModelDataTransformer);
-        const res = T.transform('model', {foo: 10});
-        expect(res).to.be.eql({foo: '10'});
-        expect(calls).to.be.eq(1);
-      });
-
-      it('should transform properties by transformers', function () {
-        let calls = 0;
-        const dbs = new DatabaseSchema();
-        const reg = dbs.getService(PropertyTransformerRegistry);
-        reg.addTransformer('myTransformer', value => {
-          calls++;
-          return String(value);
-        });
-        dbs.defineModel({
-          name: 'model',
-          properties: {
-            foo: {
-              type: DataType.ANY,
-              transform: ['myTransformer'],
-            },
-            bar: {
-              type: DataType.ANY,
-              transform: ['myTransformer'],
-            },
-          },
-        });
-        const T = dbs.getService(ModelDataTransformer);
-        const res = T.transform('model', {foo: 1, bar: 2});
-        expect(res).to.be.eql({foo: '1', bar: '2'});
-        expect(calls).to.be.eq(2);
-      });
-
-      it('should pass arguments to the transformer', function () {
-        let calls = 0;
-        const dbs = new DatabaseSchema();
-        const reg = dbs.getService(PropertyTransformerRegistry);
-        reg.addTransformer('myTransformer', (value, options, context) => {
-          calls++;
-          expect(value).to.be.eq(10);
-          expect(options).to.be.undefined;
-          expect(context).to.be.eql({
-            transformerName: 'myTransformer',
-            modelName: 'model',
-            propName: 'foo',
-          });
-          return String(value);
-        });
-        dbs.defineModel({
-          name: 'model',
-          properties: {
-            foo: {
-              type: DataType.ANY,
-              transform: 'myTransformer',
-            },
-          },
-        });
-        const T = dbs.getService(ModelDataTransformer);
-        const res = T.transform('model', {foo: 10});
-        expect(res).to.be.eql({foo: '10'});
-        expect(calls).to.be.eq(1);
-      });
-
-      it('should transform the property by the asynchronous transformer', async function () {
-        let calls = 0;
-        const dbs = new DatabaseSchema();
-        const reg = dbs.getService(PropertyTransformerRegistry);
-        reg.addTransformer('myTransformer', value => {
-          calls++;
-          return Promise.resolve(String(value));
-        });
-        dbs.defineModel({
-          name: 'model',
-          properties: {
-            foo: {
-              type: DataType.ANY,
-              transform: 'myTransformer',
-            },
-          },
-        });
-        const T = dbs.getService(ModelDataTransformer);
-        const promise = T.transform('model', {foo: 10});
-        expect(promise).to.be.instanceof(Promise);
-        const res = await promise;
-        expect(res).to.be.eql({foo: '10'});
-        expect(calls).to.be.eq(1);
-      });
-
-      it('should transform properties by the asynchronous transformer', async function () {
-        let calls = 0;
-        const dbs = new DatabaseSchema();
-        const reg = dbs.getService(PropertyTransformerRegistry);
-        reg.addTransformer('myTransformer', value => {
-          calls++;
-          return Promise.resolve(String(value));
-        });
-        dbs.defineModel({
-          name: 'model',
-          properties: {
-            foo: {
-              type: DataType.ANY,
-              transform: 'myTransformer',
-            },
-            bar: {
-              type: DataType.ANY,
-              transform: 'myTransformer',
-            },
-          },
-        });
-        const T = dbs.getService(ModelDataTransformer);
-        const promise = T.transform('model', {foo: 10, bar: 20});
-        expect(promise).to.be.instanceof(Promise);
-        const res = await promise;
-        expect(res).to.be.eql({foo: '10', bar: '20'});
-        expect(calls).to.be.eq(2);
-      });
-
-      it('should throw an error from the transformer', async function () {
-        let calls = 0;
-        const dbs = new DatabaseSchema();
-        const reg = dbs.getService(PropertyTransformerRegistry);
-        reg.addTransformer('myTransformer', () => {
-          calls++;
-          throw new Error('My error');
-        });
-        dbs.defineModel({
-          name: 'model',
-          properties: {
-            foo: {
-              type: DataType.ANY,
-              transform: 'myTransformer',
-            },
-          },
-        });
-        const T = dbs.getService(ModelDataTransformer);
-        const throwable = () => T.transform('model', {foo: 10});
-        expect(throwable).to.throw('My error');
-        expect(calls).to.be.eq(1);
-      });
-
-      it('should throw an error from the asynchronous transformer', async function () {
-        let calls = 0;
-        const dbs = new DatabaseSchema();
-        const reg = dbs.getService(PropertyTransformerRegistry);
-        reg.addTransformer('myTransformer', async () => {
-          calls++;
-          throw new Error('My error');
-        });
-        dbs.defineModel({
-          name: 'model',
-          properties: {
-            foo: {
-              type: DataType.ANY,
-              transform: 'myTransformer',
-            },
-          },
-        });
-        const T = dbs.getService(ModelDataTransformer);
-        const promise = T.transform('model', {foo: 10});
-        await expect(promise).to.rejectedWith('My error');
-        expect(calls).to.be.eq(1);
-      });
-    });
-
-    describe('when the option "transform" is a Function', function () {
-      describe('named transformers', function () {
-        it('should not transform the non-provided property', function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          const myTransformer = function () {
-            calls++;
-            throw new Error('Should not to be called.');
-          };
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform: myTransformer,
-              },
-            },
-          });
-          const T = dbs.getService(ModelDataTransformer);
-          const res = T.transform('model', {});
-          expect(res).to.be.eql({});
-          expect(calls).to.be.eq(0);
-        });
-
-        it('should not transform non-provided properties when the option "isPartial" is true', function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          const myTransformer = function () {
-            calls++;
-            throw new Error('Should not to be called.');
-          };
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform: myTransformer,
-              },
-              bar: {
-                type: DataType.ANY,
-                transform: myTransformer,
-              },
-            },
-          });
-          const T = dbs.getService(ModelDataTransformer);
-          const res = T.transform('model', {}, true);
-          expect(res).to.be.eql({});
-          expect(calls).to.be.eq(0);
-        });
-
-        it('should not transform undefined and null values', function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          const myTransformer = function () {
-            calls++;
-            throw new Error('Should not to be called.');
-          };
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform: myTransformer,
-              },
-            },
-          });
-          const T = dbs.getService(ModelDataTransformer);
-          const res1 = T.transform('model', {foo: undefined});
-          const res2 = T.transform('model', {foo: null});
-          expect(res1).to.be.eql({foo: undefined});
-          expect(res2).to.be.eql({foo: null});
-          expect(calls).to.be.eq(0);
-        });
-
-        it('should not transform the empty value', function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          const myTransformer = function () {
-            calls++;
-            throw new Error('Should not to be called.');
-          };
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform: myTransformer,
-              },
-            },
-          });
-          dbs
-            .getService(EmptyValuesService)
-            .setEmptyValuesOf(DataType.ANY, [10]);
-          const T = dbs.getService(ModelDataTransformer);
-          const res = T.transform('model', {foo: 10});
-          expect(res).to.be.eql({foo: 10});
-          expect(calls).to.be.eq(0);
-        });
-
-        it('should transform the property by the transformer', function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          const myTransformer = function (value) {
-            calls++;
-            return String(value);
-          };
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform: myTransformer,
-              },
-            },
-          });
-          const T = dbs.getService(ModelDataTransformer);
-          const res = T.transform('model', {foo: 10});
-          expect(res).to.be.eql({foo: '10'});
-          expect(calls).to.be.eq(1);
-        });
-
-        it('should transform properties by transformers', function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          const myTransformer = function (value) {
-            calls++;
-            return String(value);
-          };
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform: myTransformer,
-              },
-              bar: {
-                type: DataType.ANY,
-                transform: myTransformer,
-              },
-            },
-          });
-          const T = dbs.getService(ModelDataTransformer);
-          const res = T.transform('model', {foo: 1, bar: 2});
-          expect(res).to.be.eql({foo: '1', bar: '2'});
-          expect(calls).to.be.eq(2);
-        });
-
-        it('should pass arguments to the transformer', function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          const myTransformer = function (value, options, context) {
-            calls++;
-            expect(value).to.be.eq(10);
-            expect(options).to.be.undefined;
-            expect(context).to.be.eql({
-              transformerName: 'myTransformer',
-              modelName: 'model',
-              propName: 'foo',
-            });
-            return String(value);
-          };
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform: myTransformer,
-              },
-            },
-          });
-          const T = dbs.getService(ModelDataTransformer);
-          const res = T.transform('model', {foo: 10});
-          expect(res).to.be.eql({foo: '10'});
-          expect(calls).to.be.eq(1);
-        });
-
-        it('should transform the property by the asynchronous transformer', async function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          const myTransformer = function (value) {
-            calls++;
-            return Promise.resolve(String(value));
-          };
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform: myTransformer,
-              },
-            },
-          });
-          const T = dbs.getService(ModelDataTransformer);
-          const promise = T.transform('model', {foo: 10});
-          expect(promise).to.be.instanceof(Promise);
-          const res = await promise;
-          expect(res).to.be.eql({foo: '10'});
-          expect(calls).to.be.eq(1);
-        });
-
-        it('should transform properties by the asynchronous transformer', async function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          const myTransformer = function (value) {
-            calls++;
-            return Promise.resolve(String(value));
-          };
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform: myTransformer,
-              },
-              bar: {
-                type: DataType.ANY,
-                transform: myTransformer,
-              },
-            },
-          });
-          const T = dbs.getService(ModelDataTransformer);
-          const promise = T.transform('model', {foo: 10, bar: 20});
-          expect(promise).to.be.instanceof(Promise);
-          const res = await promise;
-          expect(res).to.be.eql({foo: '10', bar: '20'});
-          expect(calls).to.be.eq(2);
-        });
-
-        it('should throw an error from the transformer', async function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          const myTransformer = function () {
-            calls++;
-            throw new Error('My error');
-          };
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform: myTransformer,
-              },
-            },
-          });
-          const T = dbs.getService(ModelDataTransformer);
-          const throwable = () => T.transform('model', {foo: 10});
-          expect(throwable).to.throw('My error');
-          expect(calls).to.be.eq(1);
-        });
-
-        it('should throw an error from the asynchronous transformer', async function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          const myTransformer = async function () {
-            calls++;
-            throw new Error('My error');
-          };
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform: myTransformer,
-              },
-            },
-          });
-          const T = dbs.getService(ModelDataTransformer);
-          const promise = T.transform('model', {foo: 10});
-          await expect(promise).to.rejectedWith('My error');
-          expect(calls).to.be.eq(1);
-        });
-      });
-
-      describe('anonymous transformers', function () {
-        it('should not transform the non-provided property', function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform() {
-                  calls++;
-                  throw new Error('Should not to be called.');
-                },
-              },
-            },
-          });
-          const T = dbs.getService(ModelDataTransformer);
-          const res = T.transform('model', {});
-          expect(res).to.be.eql({});
-          expect(calls).to.be.eq(0);
-        });
-
-        it('should not transform non-provided properties when the option "isPartial" is true', function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform() {
-                  calls++;
-                  throw new Error('Should not to be called.');
-                },
-              },
-              bar: {
-                type: DataType.ANY,
-                transform() {
-                  calls++;
-                  throw new Error('Should not to be called.');
-                },
-              },
-            },
-          });
-          const T = dbs.getService(ModelDataTransformer);
-          const res = T.transform('model', {}, true);
-          expect(res).to.be.eql({});
-          expect(calls).to.be.eq(0);
-        });
-
-        it('should not transform undefined and null values', function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform() {
-                  calls++;
-                  throw new Error('Should not to be called.');
-                },
-              },
-            },
-          });
-          const T = dbs.getService(ModelDataTransformer);
-          const res1 = T.transform('model', {foo: undefined});
-          const res2 = T.transform('model', {foo: null});
-          expect(res1).to.be.eql({foo: undefined});
-          expect(res2).to.be.eql({foo: null});
-          expect(calls).to.be.eq(0);
-        });
-
-        it('should not transform the empty value', function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform() {
-                  calls++;
-                  throw new Error('Should not to be called.');
-                },
-              },
-            },
-          });
-          dbs
-            .getService(EmptyValuesService)
-            .setEmptyValuesOf(DataType.ANY, [10]);
-          const T = dbs.getService(ModelDataTransformer);
-          const res = T.transform('model', {foo: 10});
-          expect(res).to.be.eql({foo: 10});
-          expect(calls).to.be.eq(0);
-        });
-
-        it('should transform the property by the transformer', function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform(value) {
-                  calls++;
-                  return String(value);
-                },
-              },
-            },
-          });
-          const T = dbs.getService(ModelDataTransformer);
-          const res = T.transform('model', {foo: 10});
-          expect(res).to.be.eql({foo: '10'});
-          expect(calls).to.be.eq(1);
-        });
-
-        it('should transform properties by transformers', function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform(value) {
-                  calls++;
-                  return String(value);
-                },
-              },
-              bar: {
-                type: DataType.ANY,
-                transform(value) {
-                  calls++;
-                  return String(value);
-                },
-              },
-            },
-          });
-          const T = dbs.getService(ModelDataTransformer);
-          const res = T.transform('model', {foo: 1, bar: 2});
-          expect(res).to.be.eql({foo: '1', bar: '2'});
-          expect(calls).to.be.eq(2);
-        });
-
-        it('should pass arguments to the transformer', function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform(value, options, context) {
-                  calls++;
-                  expect(value).to.be.eq(10);
-                  expect(options).to.be.undefined;
-                  expect(context).to.be.eql({
-                    transformerName: undefined,
-                    modelName: 'model',
-                    propName: 'foo',
-                  });
-                  return String(value);
-                },
-              },
-            },
-          });
-          const T = dbs.getService(ModelDataTransformer);
-          const res = T.transform('model', {foo: 10});
-          expect(res).to.be.eql({foo: '10'});
-          expect(calls).to.be.eq(1);
-        });
-
-        it('should transform the property by the asynchronous transformer', async function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform(value) {
-                  calls++;
-                  return Promise.resolve(String(value));
-                },
-              },
-            },
-          });
-          const T = dbs.getService(ModelDataTransformer);
-          const promise = T.transform('model', {foo: 10});
-          expect(promise).to.be.instanceof(Promise);
-          const res = await promise;
-          expect(res).to.be.eql({foo: '10'});
-          expect(calls).to.be.eq(1);
-        });
-
-        it('should transform properties by the asynchronous transformer', async function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform(value) {
-                  calls++;
-                  return Promise.resolve(String(value));
-                },
-              },
-              bar: {
-                type: DataType.ANY,
-                transform(value) {
-                  calls++;
-                  return Promise.resolve(String(value));
-                },
-              },
-            },
-          });
-          const T = dbs.getService(ModelDataTransformer);
-          const promise = T.transform('model', {foo: 10, bar: 20});
-          expect(promise).to.be.instanceof(Promise);
-          const res = await promise;
-          expect(res).to.be.eql({foo: '10', bar: '20'});
-          expect(calls).to.be.eq(2);
-        });
-
-        it('should throw an error from the transformer', async function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform() {
-                  calls++;
-                  throw new Error('My error');
-                },
-              },
-            },
-          });
-          const T = dbs.getService(ModelDataTransformer);
-          const throwable = () => T.transform('model', {foo: 10});
-          expect(throwable).to.throw('My error');
-          expect(calls).to.be.eq(1);
-        });
-
-        it('should throw an error from the asynchronous transformer', async function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                async transform() {
-                  calls++;
-                  throw new Error('My error');
-                },
-              },
-            },
-          });
-          const T = dbs.getService(ModelDataTransformer);
-          const promise = T.transform('model', {foo: 10});
-          await expect(promise).to.rejectedWith('My error');
-          expect(calls).to.be.eq(1);
-        });
-      });
-    });
-
-    describe('when the option "transform" is an Array', function () {
-      describe('when an Array element is a String', function () {
-        it('should not transform the non-provided property', function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          const reg = dbs.getService(PropertyTransformerRegistry);
-          reg.addTransformer('myTransformer', () => {
-            calls++;
-            throw new Error('Should not to be called.');
-          });
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform: ['myTransformer'],
-              },
-            },
-          });
-          const T = dbs.getService(ModelDataTransformer);
-          const res = T.transform('model', {});
-          expect(res).to.be.eql({});
-          expect(calls).to.be.eq(0);
-        });
-
-        it('should not transform non-provided properties when the option "isPartial" is true', function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          const reg = dbs.getService(PropertyTransformerRegistry);
-          reg.addTransformer('myTransformer', () => {
-            calls++;
-            throw new Error('Should not to be called.');
-          });
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform: ['myTransformer'],
-              },
-              bar: {
-                type: DataType.ANY,
-                transform: ['myTransformer'],
-              },
-            },
-          });
-          const T = dbs.getService(ModelDataTransformer);
-          const res = T.transform('model', {}, true);
-          expect(res).to.be.eql({});
-          expect(calls).to.be.eq(0);
-        });
-
-        it('should not transform undefined and null values', function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          const reg = dbs.getService(PropertyTransformerRegistry);
-          reg.addTransformer('myTransformer', () => {
-            calls++;
-            throw new Error('Should not to be called.');
-          });
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform: ['myTransformer'],
-              },
-            },
-          });
-          const T = dbs.getService(ModelDataTransformer);
-          const res1 = T.transform('model', {foo: undefined});
-          const res2 = T.transform('model', {foo: null});
-          expect(res1).to.be.eql({foo: undefined});
-          expect(res2).to.be.eql({foo: null});
-          expect(calls).to.be.eq(0);
-        });
-
-        it('should not transform the empty value', function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          const reg = dbs.getService(PropertyTransformerRegistry);
-          reg.addTransformer('myTransformer', () => {
-            calls++;
-            throw new Error('Should not to be called.');
-          });
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform: ['myTransformer'],
-              },
-            },
-          });
-          dbs
-            .getService(EmptyValuesService)
-            .setEmptyValuesOf(DataType.ANY, [10]);
-          const T = dbs.getService(ModelDataTransformer);
-          const res = T.transform('model', {foo: 10});
-          expect(res).to.be.eql({foo: 10});
-          expect(calls).to.be.eq(0);
-        });
-
-        it('should transform the property by the transformer', function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          const reg = dbs.getService(PropertyTransformerRegistry);
-          reg.addTransformer('myTransformer', value => {
-            calls++;
-            return String(value);
-          });
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform: ['myTransformer'],
-              },
-            },
-          });
-          const T = dbs.getService(ModelDataTransformer);
-          const res = T.transform('model', {foo: 10});
-          expect(res).to.be.eql({foo: '10'});
-          expect(calls).to.be.eq(1);
-        });
-
-        it('should transform properties by transformers', function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          const reg = dbs.getService(PropertyTransformerRegistry);
-          reg.addTransformer('myTransformer', value => {
-            calls++;
-            return String(value);
-          });
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform: ['myTransformer'],
-              },
-              bar: {
-                type: DataType.ANY,
-                transform: ['myTransformer'],
-              },
-            },
-          });
-          const T = dbs.getService(ModelDataTransformer);
-          const res = T.transform('model', {foo: 1, bar: 2});
-          expect(res).to.be.eql({foo: '1', bar: '2'});
-          expect(calls).to.be.eq(2);
-        });
-
-        it('should pass arguments to the transformer', function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          const reg = dbs.getService(PropertyTransformerRegistry);
-          reg.addTransformer('myTransformer', (value, options, context) => {
-            calls++;
-            expect(value).to.be.eq(10);
-            expect(options).to.be.undefined;
-            expect(context).to.be.eql({
-              transformerName: 'myTransformer',
-              modelName: 'model',
-              propName: 'foo',
-            });
-            return String(value);
-          });
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform: ['myTransformer'],
-              },
-            },
-          });
-          const T = dbs.getService(ModelDataTransformer);
-          const res = T.transform('model', {foo: 10});
-          expect(res).to.be.eql({foo: '10'});
-          expect(calls).to.be.eq(1);
-        });
-
-        it('should transform the property by the asynchronous transformer', async function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          const reg = dbs.getService(PropertyTransformerRegistry);
-          reg.addTransformer('myTransformer', value => {
-            calls++;
-            return Promise.resolve(String(value));
-          });
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform: ['myTransformer'],
-              },
-            },
-          });
-          const T = dbs.getService(ModelDataTransformer);
-          const promise = T.transform('model', {foo: 10});
-          expect(promise).to.be.instanceof(Promise);
-          const res = await promise;
-          expect(res).to.be.eql({foo: '10'});
-          expect(calls).to.be.eq(1);
-        });
-
-        it('should transform properties by the asynchronous transformer', async function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          const reg = dbs.getService(PropertyTransformerRegistry);
-          reg.addTransformer('myTransformer', value => {
-            calls++;
-            return Promise.resolve(String(value));
-          });
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform: ['myTransformer'],
-              },
-              bar: {
-                type: DataType.ANY,
-                transform: ['myTransformer'],
-              },
-            },
-          });
-          const T = dbs.getService(ModelDataTransformer);
-          const promise = T.transform('model', {foo: 10, bar: 20});
-          expect(promise).to.be.instanceof(Promise);
-          const res = await promise;
-          expect(res).to.be.eql({foo: '10', bar: '20'});
-          expect(calls).to.be.eq(2);
-        });
-
-        it('should throw an error from the transformer', async function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          const reg = dbs.getService(PropertyTransformerRegistry);
-          reg.addTransformer('myTransformer', () => {
-            calls++;
-            throw new Error('My error');
-          });
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform: ['myTransformer'],
-              },
-            },
-          });
-          const T = dbs.getService(ModelDataTransformer);
-          const throwable = () => T.transform('model', {foo: 10});
-          expect(throwable).to.throw('My error');
-          expect(calls).to.be.eq(1);
-        });
-
-        it('should throw an error from the asynchronous transformer', async function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          const reg = dbs.getService(PropertyTransformerRegistry);
-          reg.addTransformer('myTransformer', async () => {
-            calls++;
-            throw new Error('My error');
-          });
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform: ['myTransformer'],
-              },
-            },
-          });
-          const T = dbs.getService(ModelDataTransformer);
-          const promise = T.transform('model', {foo: 10});
-          await expect(promise).to.rejectedWith('My error');
-          expect(calls).to.be.eq(1);
-        });
-
-        it('should transform the property by transformers with the correct order', function () {
-          const order = [];
-          const dbs = new DatabaseSchema();
-          const reg = dbs.getService(PropertyTransformerRegistry);
-          reg.addTransformer('myTransformer1', value => {
-            order.push('myTransformer1');
-            return String(value);
-          });
-          reg.addTransformer('myTransformer2', value => {
-            order.push('myTransformer2');
-            return value.toUpperCase();
-          });
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform: ['myTransformer1', 'myTransformer2'],
-              },
-            },
-          });
-          const T = dbs.getService(ModelDataTransformer);
-          const res = T.transform('model', {foo: true});
-          expect(res).to.be.eql({foo: 'TRUE'});
-          expect(order).to.be.eql(['myTransformer1', 'myTransformer2']);
-        });
-
-        it('should transform the property by asynchronous transformers with the correct order', async function () {
-          const order = [];
-          const dbs = new DatabaseSchema();
-          const reg = dbs.getService(PropertyTransformerRegistry);
-          reg.addTransformer('myTransformer1', async value => {
-            order.push('myTransformer1');
-            return String(value);
-          });
-          reg.addTransformer('myTransformer2', async value => {
-            order.push('myTransformer2');
-            return value.toUpperCase();
-          });
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                transform: ['myTransformer1', 'myTransformer2'],
-              },
-            },
-          });
-          const T = dbs.getService(ModelDataTransformer);
-          const res = await T.transform('model', {foo: true});
-          expect(res).to.be.eql({foo: 'TRUE'});
-          expect(order).to.be.eql(['myTransformer1', 'myTransformer2']);
-        });
-      });
-
-      describe('when an Array element is a Function', function () {
-        describe('named transformers', function () {
-          it('should not transform the non-provided property', function () {
-            let calls = 0;
-            const dbs = new DatabaseSchema();
-            const myTransformer = function () {
-              calls++;
-              throw new Error('Should not to be called.');
-            };
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  transform: [myTransformer],
-                },
-              },
-            });
-            const T = dbs.getService(ModelDataTransformer);
-            const res = T.transform('model', {});
-            expect(res).to.be.eql({});
-            expect(calls).to.be.eq(0);
-          });
-
-          it('should not transform non-provided properties when the option "isPartial" is true', function () {
-            let calls = 0;
-            const dbs = new DatabaseSchema();
-            const myTransformer = function () {
-              calls++;
-              throw new Error('Should not to be called.');
-            };
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  transform: [myTransformer],
-                },
-                bar: {
-                  type: DataType.ANY,
-                  transform: [myTransformer],
-                },
-              },
-            });
-            const T = dbs.getService(ModelDataTransformer);
-            const res = T.transform('model', {}, true);
-            expect(res).to.be.eql({});
-            expect(calls).to.be.eq(0);
-          });
-
-          it('should not transform undefined and null values', function () {
-            let calls = 0;
-            const dbs = new DatabaseSchema();
-            const myTransformer = function () {
-              calls++;
-              throw new Error('Should not to be called.');
-            };
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  transform: [myTransformer],
-                },
-              },
-            });
-            const T = dbs.getService(ModelDataTransformer);
-            const res1 = T.transform('model', {foo: undefined});
-            const res2 = T.transform('model', {foo: null});
-            expect(res1).to.be.eql({foo: undefined});
-            expect(res2).to.be.eql({foo: null});
-            expect(calls).to.be.eq(0);
-          });
-
-          it('should not transform the empty value', function () {
-            let calls = 0;
-            const dbs = new DatabaseSchema();
-            const myTransformer = function () {
-              calls++;
-              throw new Error('Should not to be called.');
-            };
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  transform: [myTransformer],
-                },
-              },
-            });
-            dbs
-              .getService(EmptyValuesService)
-              .setEmptyValuesOf(DataType.ANY, [10]);
-            const T = dbs.getService(ModelDataTransformer);
-            const res = T.transform('model', {foo: 10});
-            expect(res).to.be.eql({foo: 10});
-            expect(calls).to.be.eq(0);
-          });
-
-          it('should transform the property by the transformer', function () {
-            let calls = 0;
-            const dbs = new DatabaseSchema();
-            const myTransformer = function (value) {
-              calls++;
-              return String(value);
-            };
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  transform: [myTransformer],
-                },
-              },
-            });
-            const T = dbs.getService(ModelDataTransformer);
-            const res = T.transform('model', {foo: 10});
-            expect(res).to.be.eql({foo: '10'});
-            expect(calls).to.be.eq(1);
-          });
-
-          it('should transform properties by transformers', function () {
-            let calls = 0;
-            const dbs = new DatabaseSchema();
-            const myTransformer = function (value) {
-              calls++;
-              return String(value);
-            };
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  transform: [myTransformer],
-                },
-                bar: {
-                  type: DataType.ANY,
-                  transform: [myTransformer],
-                },
-              },
-            });
-            const T = dbs.getService(ModelDataTransformer);
-            const res = T.transform('model', {foo: 1, bar: 2});
-            expect(res).to.be.eql({foo: '1', bar: '2'});
-            expect(calls).to.be.eq(2);
-          });
-
-          it('should pass arguments to the transformer', function () {
-            let calls = 0;
-            const dbs = new DatabaseSchema();
-            const myTransformer = function (value, options, context) {
-              calls++;
-              expect(value).to.be.eq(10);
-              expect(options).to.be.undefined;
-              expect(context).to.be.eql({
-                transformerName: 'myTransformer',
-                modelName: 'model',
-                propName: 'foo',
-              });
-              return String(value);
-            };
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  transform: [myTransformer],
-                },
-              },
-            });
-            const T = dbs.getService(ModelDataTransformer);
-            const res = T.transform('model', {foo: 10});
-            expect(res).to.be.eql({foo: '10'});
-            expect(calls).to.be.eq(1);
-          });
-
-          it('should transform the property by the asynchronous transformer', async function () {
-            let calls = 0;
-            const dbs = new DatabaseSchema();
-            const myTransformer = function (value) {
-              calls++;
-              return Promise.resolve(String(value));
-            };
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  transform: [myTransformer],
-                },
-              },
-            });
-            const T = dbs.getService(ModelDataTransformer);
-            const promise = T.transform('model', {foo: 10});
-            expect(promise).to.be.instanceof(Promise);
-            const res = await promise;
-            expect(res).to.be.eql({foo: '10'});
-            expect(calls).to.be.eq(1);
-          });
-
-          it('should transform properties by the asynchronous transformer', async function () {
-            let calls = 0;
-            const dbs = new DatabaseSchema();
-            const myTransformer = function (value) {
-              calls++;
-              return Promise.resolve(String(value));
-            };
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  transform: [myTransformer],
-                },
-                bar: {
-                  type: DataType.ANY,
-                  transform: [myTransformer],
-                },
-              },
-            });
-            const T = dbs.getService(ModelDataTransformer);
-            const promise = T.transform('model', {foo: 10, bar: 20});
-            expect(promise).to.be.instanceof(Promise);
-            const res = await promise;
-            expect(res).to.be.eql({foo: '10', bar: '20'});
-            expect(calls).to.be.eq(2);
-          });
-
-          it('should throw an error from the transformer', async function () {
-            let calls = 0;
-            const dbs = new DatabaseSchema();
-            const myTransformer = function () {
-              calls++;
-              throw new Error('My error');
-            };
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  transform: [myTransformer],
-                },
-              },
-            });
-            const T = dbs.getService(ModelDataTransformer);
-            const throwable = () => T.transform('model', {foo: 10});
-            expect(throwable).to.throw('My error');
-            expect(calls).to.be.eq(1);
-          });
-
-          it('should throw an error from the asynchronous transformer', async function () {
-            let calls = 0;
-            const dbs = new DatabaseSchema();
-            const myTransformer = async function () {
-              calls++;
-              throw new Error('My error');
-            };
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  transform: [myTransformer],
-                },
-              },
-            });
-            const T = dbs.getService(ModelDataTransformer);
-            const promise = T.transform('model', {foo: 10});
-            await expect(promise).to.rejectedWith('My error');
-            expect(calls).to.be.eq(1);
-          });
-
-          it('should transform the property by transformers with the correct order', function () {
-            const order = [];
-            const dbs = new DatabaseSchema();
-            const myTransformer1 = function (value) {
-              order.push('myTransformer1');
-              return String(value);
-            };
-            const myTransformer2 = function (value) {
-              order.push('myTransformer2');
-              return value.toUpperCase();
-            };
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  transform: [myTransformer1, myTransformer2],
-                },
-              },
-            });
-            const T = dbs.getService(ModelDataTransformer);
-            const res = T.transform('model', {foo: true});
-            expect(res).to.be.eql({foo: 'TRUE'});
-            expect(order).to.be.eql(['myTransformer1', 'myTransformer2']);
-          });
-
-          it('should transform the property by asynchronous transformers with the correct order', async function () {
-            const order = [];
-            const dbs = new DatabaseSchema();
-            const myTransformer1 = async function (value) {
-              order.push('myTransformer1');
-              return String(value);
-            };
-            const myTransformer2 = async function (value) {
-              order.push('myTransformer2');
-              return value.toUpperCase();
-            };
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  transform: [myTransformer1, myTransformer2],
-                },
-              },
-            });
-            const T = dbs.getService(ModelDataTransformer);
-            const res = await T.transform('model', {foo: true});
-            expect(res).to.be.eql({foo: 'TRUE'});
-            expect(order).to.be.eql(['myTransformer1', 'myTransformer2']);
-          });
-        });
-
-        describe('anonymous transformers', function () {
-          it('should not transform the non-provided property', function () {
-            let calls = 0;
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  transform: [
-                    () => {
-                      calls++;
-                      throw new Error('Should not to be called.');
-                    },
-                  ],
-                },
-              },
-            });
-            const T = dbs.getService(ModelDataTransformer);
-            const res = T.transform('model', {});
-            expect(res).to.be.eql({});
-            expect(calls).to.be.eq(0);
-          });
-
-          it('should not transform non-provided properties when the option "isPartial" is true', function () {
-            let calls = 0;
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  transform: [
-                    () => {
-                      calls++;
-                      throw new Error('Should not to be called.');
-                    },
-                  ],
-                },
-                bar: {
-                  type: DataType.ANY,
-                  transform: [
-                    () => {
-                      calls++;
-                      throw new Error('Should not to be called.');
-                    },
-                  ],
-                },
-              },
-            });
-            const T = dbs.getService(ModelDataTransformer);
-            const res = T.transform('model', {}, true);
-            expect(res).to.be.eql({});
-            expect(calls).to.be.eq(0);
-          });
-
-          it('should not transform undefined and null values', function () {
-            let calls = 0;
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  transform: [
-                    () => {
-                      calls++;
-                      throw new Error('Should not to be called.');
-                    },
-                  ],
-                },
-              },
-            });
-            const T = dbs.getService(ModelDataTransformer);
-            const res1 = T.transform('model', {foo: undefined});
-            const res2 = T.transform('model', {foo: null});
-            expect(res1).to.be.eql({foo: undefined});
-            expect(res2).to.be.eql({foo: null});
-            expect(calls).to.be.eq(0);
-          });
-
-          it('should not transform the empty value', function () {
-            let calls = 0;
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  transform: [
-                    () => {
-                      calls++;
-                      throw new Error('Should not to be called.');
-                    },
-                  ],
-                },
-              },
-            });
-            dbs
-              .getService(EmptyValuesService)
-              .setEmptyValuesOf(DataType.ANY, [10]);
-            const T = dbs.getService(ModelDataTransformer);
-            const res = T.transform('model', {foo: 10});
-            expect(res).to.be.eql({foo: 10});
-            expect(calls).to.be.eq(0);
-          });
-
-          it('should transform the property by the transformer', function () {
-            let calls = 0;
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  transform: [
-                    value => {
-                      calls++;
-                      return String(value);
-                    },
-                  ],
-                },
-              },
-            });
-            const T = dbs.getService(ModelDataTransformer);
-            const res = T.transform('model', {foo: 10});
-            expect(res).to.be.eql({foo: '10'});
-            expect(calls).to.be.eq(1);
-          });
-
-          it('should transform properties by transformers', function () {
-            let calls = 0;
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  transform: [
-                    value => {
-                      calls++;
-                      return String(value);
-                    },
-                  ],
-                },
-                bar: {
-                  type: DataType.ANY,
-                  transform: [
-                    value => {
-                      calls++;
-                      return String(value);
-                    },
-                  ],
-                },
-              },
-            });
-            const T = dbs.getService(ModelDataTransformer);
-            const res = T.transform('model', {foo: 1, bar: 2});
-            expect(res).to.be.eql({foo: '1', bar: '2'});
-            expect(calls).to.be.eq(2);
-          });
-
-          it('should pass arguments to the transformer', function () {
-            let calls = 0;
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  transform: [
-                    (value, options, context) => {
-                      calls++;
-                      expect(value).to.be.eq(10);
-                      expect(options).to.be.undefined;
-                      expect(context).to.be.eql({
-                        transformerName: undefined,
-                        modelName: 'model',
-                        propName: 'foo',
-                      });
-                      return String(value);
-                    },
-                  ],
-                },
-              },
-            });
-            const T = dbs.getService(ModelDataTransformer);
-            const res = T.transform('model', {foo: 10});
-            expect(res).to.be.eql({foo: '10'});
-            expect(calls).to.be.eq(1);
-          });
-
-          it('should transform the property by the asynchronous transformer', async function () {
-            let calls = 0;
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  transform: [
-                    value => {
-                      calls++;
-                      return Promise.resolve(String(value));
-                    },
-                  ],
-                },
-              },
-            });
-            const T = dbs.getService(ModelDataTransformer);
-            const promise = T.transform('model', {foo: 10});
-            expect(promise).to.be.instanceof(Promise);
-            const res = await promise;
-            expect(res).to.be.eql({foo: '10'});
-            expect(calls).to.be.eq(1);
-          });
-
-          it('should transform properties by the asynchronous transformer', async function () {
-            let calls = 0;
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  transform: [
-                    value => {
-                      calls++;
-                      return Promise.resolve(String(value));
-                    },
-                  ],
-                },
-                bar: {
-                  type: DataType.ANY,
-                  transform: [
-                    value => {
-                      calls++;
-                      return Promise.resolve(String(value));
-                    },
-                  ],
-                },
-              },
-            });
-            const T = dbs.getService(ModelDataTransformer);
-            const promise = T.transform('model', {foo: 10, bar: 20});
-            expect(promise).to.be.instanceof(Promise);
-            const res = await promise;
-            expect(res).to.be.eql({foo: '10', bar: '20'});
-            expect(calls).to.be.eq(2);
-          });
-
-          it('should throw an error from the transformer', async function () {
-            let calls = 0;
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  transform: [
-                    () => {
-                      calls++;
-                      throw new Error('My error');
-                    },
-                  ],
-                },
-              },
-            });
-            const T = dbs.getService(ModelDataTransformer);
-            const throwable = () => T.transform('model', {foo: 10});
-            expect(throwable).to.throw('My error');
-            expect(calls).to.be.eq(1);
-          });
-
-          it('should throw an error from the asynchronous transformer', async function () {
-            let calls = 0;
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  transform: [
-                    async () => {
-                      calls++;
-                      throw new Error('My error');
-                    },
-                  ],
-                },
-              },
-            });
-            const T = dbs.getService(ModelDataTransformer);
-            const promise = T.transform('model', {foo: 10});
-            await expect(promise).to.rejectedWith('My error');
-            expect(calls).to.be.eq(1);
-          });
-
-          it('should transform the property by transformers with the correct order', function () {
-            const order = [];
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  transform: [
-                    value => {
-                      order.push('myTransformer1');
-                      return String(value);
-                    },
-                    value => {
-                      order.push('myTransformer2');
-                      return value.toUpperCase();
-                    },
-                  ],
-                },
-              },
-            });
-            const T = dbs.getService(ModelDataTransformer);
-            const res = T.transform('model', {foo: true});
-            expect(res).to.be.eql({foo: 'TRUE'});
-            expect(order).to.be.eql(['myTransformer1', 'myTransformer2']);
-          });
-
-          it('should transform the property by asynchronous transformers with the correct order', async function () {
-            const order = [];
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  transform: [
-                    async value => {
-                      order.push('myTransformer1');
-                      return String(value);
-                    },
-                    async value => {
-                      order.push('myTransformer2');
-                      return value.toUpperCase();
-                    },
-                  ],
-                },
-              },
-            });
-            const T = dbs.getService(ModelDataTransformer);
-            const res = await T.transform('model', {foo: true});
-            expect(res).to.be.eql({foo: 'TRUE'});
-            expect(order).to.be.eql(['myTransformer1', 'myTransformer2']);
-          });
-        });
-      });
-    });
-
-    describe('when the option "transform" is an Object', function () {
-      it('should not transform the non-provided property', function () {
-        let calls = 0;
-        const dbs = new DatabaseSchema();
-        const reg = dbs.getService(PropertyTransformerRegistry);
-        reg.addTransformer('myTransformer', () => {
-          calls++;
-          throw new Error('Should not to be called.');
-        });
-        dbs.defineModel({
-          name: 'model',
-          properties: {
-            foo: {
-              type: DataType.ANY,
-              transform: {
-                myTransformer: true,
-              },
-            },
-          },
-        });
-        const T = dbs.getService(ModelDataTransformer);
-        const res = T.transform('model', {});
-        expect(res).to.be.eql({});
-        expect(calls).to.be.eq(0);
-      });
-
-      it('should not transform non-provided properties when the option "isPartial" is true', function () {
-        let calls = 0;
-        const dbs = new DatabaseSchema();
-        const reg = dbs.getService(PropertyTransformerRegistry);
-        reg.addTransformer('myTransformer', () => {
-          calls++;
-          throw new Error('Should not to be called.');
-        });
-        dbs.defineModel({
-          name: 'model',
-          properties: {
-            foo: {
-              type: DataType.ANY,
-              transform: {
-                myTransformer: true,
-              },
-            },
-            bar: {
-              type: DataType.ANY,
-              transform: {
-                myTransformer: true,
-              },
-            },
-          },
-        });
-        const T = dbs.getService(ModelDataTransformer);
-        const res = T.transform('model', {}, true);
-        expect(res).to.be.eql({});
-        expect(calls).to.be.eq(0);
-      });
-
-      it('should not transform undefined and null values', function () {
-        let calls = 0;
-        const dbs = new DatabaseSchema();
-        const reg = dbs.getService(PropertyTransformerRegistry);
-        reg.addTransformer('myTransformer', () => {
-          calls++;
-          throw new Error('Should not to be called.');
-        });
-        dbs.defineModel({
-          name: 'model',
-          properties: {
-            foo: {
-              type: DataType.ANY,
-              transform: {
-                myTransformer: true,
-              },
-            },
-          },
-        });
-        const T = dbs.getService(ModelDataTransformer);
-        const res1 = T.transform('model', {foo: undefined});
-        const res2 = T.transform('model', {foo: null});
-        expect(res1).to.be.eql({foo: undefined});
-        expect(res2).to.be.eql({foo: null});
-        expect(calls).to.be.eq(0);
-      });
-
-      it('should not transform the empty value', function () {
-        let calls = 0;
-        const dbs = new DatabaseSchema();
-        const reg = dbs.getService(PropertyTransformerRegistry);
-        reg.addTransformer('myTransformer', () => {
-          calls++;
-          throw new Error('Should not to be called.');
-        });
-        dbs.defineModel({
-          name: 'model',
-          properties: {
-            foo: {
-              type: DataType.ANY,
-              transform: {
-                myTransformer: true,
-              },
-            },
-          },
-        });
-        dbs.getService(EmptyValuesService).setEmptyValuesOf(DataType.ANY, [10]);
-        const T = dbs.getService(ModelDataTransformer);
-        const res = T.transform('model', {foo: 10});
-        expect(res).to.be.eql({foo: 10});
-        expect(calls).to.be.eq(0);
-      });
-
-      it('should transform the property by the transformer', function () {
-        let calls = 0;
-        const dbs = new DatabaseSchema();
-        const reg = dbs.getService(PropertyTransformerRegistry);
-        reg.addTransformer('myTransformer', value => {
-          calls++;
-          return String(value);
-        });
-        dbs.defineModel({
-          name: 'model',
-          properties: {
-            foo: {
-              type: DataType.ANY,
-              transform: {
-                myTransformer: true,
-              },
-            },
-          },
-        });
-        const T = dbs.getService(ModelDataTransformer);
-        const res = T.transform('model', {foo: 10});
-        expect(res).to.be.eql({foo: '10'});
-        expect(calls).to.be.eq(1);
-      });
-
-      it('should transform properties by transformers', function () {
-        let calls = 0;
-        const dbs = new DatabaseSchema();
-        const reg = dbs.getService(PropertyTransformerRegistry);
-        reg.addTransformer('myTransformer', value => {
-          calls++;
-          return String(value);
-        });
-        dbs.defineModel({
-          name: 'model',
-          properties: {
-            foo: {
-              type: DataType.ANY,
-              transform: {
-                myTransformer: true,
-              },
-            },
-            bar: {
-              type: DataType.ANY,
-              transform: {
-                myTransformer: true,
-              },
-            },
-          },
-        });
-        const T = dbs.getService(ModelDataTransformer);
-        const res = T.transform('model', {foo: 1, bar: 2});
-        expect(res).to.be.eql({foo: '1', bar: '2'});
-        expect(calls).to.be.eq(2);
-      });
-
-      it('should pass arguments to the transformer', function () {
-        let calls = 0;
-        const dbs = new DatabaseSchema();
-        const reg = dbs.getService(PropertyTransformerRegistry);
-        reg.addTransformer('myTransformer', (value, options, context) => {
-          calls++;
-          expect(value).to.be.eq(10);
-          expect(options).to.be.eq('test');
-          expect(context).to.be.eql({
-            transformerName: 'myTransformer',
-            modelName: 'model',
-            propName: 'foo',
-          });
-          return String(value);
-        });
-        dbs.defineModel({
-          name: 'model',
-          properties: {
-            foo: {
-              type: DataType.ANY,
-              transform: {
-                myTransformer: 'test',
-              },
-            },
-          },
-        });
-        const T = dbs.getService(ModelDataTransformer);
-        const res = T.transform('model', {foo: 10});
-        expect(res).to.be.eql({foo: '10'});
-        expect(calls).to.be.eq(1);
-      });
-
-      it('should transform the property by the asynchronous transformer', async function () {
-        let calls = 0;
-        const dbs = new DatabaseSchema();
-        const reg = dbs.getService(PropertyTransformerRegistry);
-        reg.addTransformer('myTransformer', value => {
-          calls++;
-          return Promise.resolve(String(value));
-        });
-        dbs.defineModel({
-          name: 'model',
-          properties: {
-            foo: {
-              type: DataType.ANY,
-              transform: {
-                myTransformer: true,
-              },
-            },
-          },
-        });
-        const T = dbs.getService(ModelDataTransformer);
-        const promise = T.transform('model', {foo: 10});
-        expect(promise).to.be.instanceof(Promise);
-        const res = await promise;
-        expect(res).to.be.eql({foo: '10'});
-        expect(calls).to.be.eq(1);
-      });
-
-      it('should transform properties by the asynchronous transformer', async function () {
-        let calls = 0;
-        const dbs = new DatabaseSchema();
-        const reg = dbs.getService(PropertyTransformerRegistry);
-        reg.addTransformer('myTransformer', value => {
-          calls++;
-          return Promise.resolve(String(value));
-        });
-        dbs.defineModel({
-          name: 'model',
-          properties: {
-            foo: {
-              type: DataType.ANY,
-              transform: {
-                myTransformer: true,
-              },
-            },
-            bar: {
-              type: DataType.ANY,
-              transform: {
-                myTransformer: true,
-              },
-            },
-          },
-        });
-        const T = dbs.getService(ModelDataTransformer);
-        const promise = T.transform('model', {foo: 10, bar: 20});
-        expect(promise).to.be.instanceof(Promise);
-        const res = await promise;
-        expect(res).to.be.eql({foo: '10', bar: '20'});
-        expect(calls).to.be.eq(2);
-      });
-
-      it('should throw an error from the transformer', async function () {
-        let calls = 0;
-        const dbs = new DatabaseSchema();
-        const reg = dbs.getService(PropertyTransformerRegistry);
-        reg.addTransformer('myTransformer', () => {
-          calls++;
-          throw new Error('My error');
-        });
-        dbs.defineModel({
-          name: 'model',
-          properties: {
-            foo: {
-              type: DataType.ANY,
-              transform: {
-                myTransformer: true,
-              },
-            },
-          },
-        });
-        const T = dbs.getService(ModelDataTransformer);
-        const throwable = () => T.transform('model', {foo: 10});
-        expect(throwable).to.throw('My error');
-        expect(calls).to.be.eq(1);
-      });
-
-      it('should throw an error from the asynchronous transformer', async function () {
-        let calls = 0;
-        const dbs = new DatabaseSchema();
-        const reg = dbs.getService(PropertyTransformerRegistry);
-        reg.addTransformer('myTransformer', async () => {
-          calls++;
-          throw new Error('My error');
-        });
-        dbs.defineModel({
-          name: 'model',
-          properties: {
-            foo: {
-              type: DataType.ANY,
-              transform: {
-                myTransformer: true,
-              },
-            },
-          },
-        });
-        const T = dbs.getService(ModelDataTransformer);
-        const promise = T.transform('model', {foo: 10});
-        await expect(promise).to.rejectedWith('My error');
-        expect(calls).to.be.eq(1);
-      });
-
-      it('should transform the property by transformers with the correct order', function () {
-        const order = [];
-        const dbs = new DatabaseSchema();
-        const reg = dbs.getService(PropertyTransformerRegistry);
-        reg.addTransformer('myTransformer1', value => {
-          order.push('myTransformer1');
-          return String(value);
-        });
-        reg.addTransformer('myTransformer2', value => {
-          order.push('myTransformer2');
-          return value.toUpperCase();
-        });
-        dbs.defineModel({
-          name: 'model',
-          properties: {
-            foo: {
-              type: DataType.ANY,
-              transform: {
-                myTransformer1: true,
-                myTransformer2: true,
-              },
-            },
-          },
-        });
-        const T = dbs.getService(ModelDataTransformer);
-        const res = T.transform('model', {foo: true});
-        expect(res).to.be.eql({foo: 'TRUE'});
-        expect(order).to.be.eql(['myTransformer1', 'myTransformer2']);
-      });
-
-      it('should transform the property by asynchronous transformers with the correct order', async function () {
-        const order = [];
-        const dbs = new DatabaseSchema();
-        const reg = dbs.getService(PropertyTransformerRegistry);
-        reg.addTransformer('myTransformer1', async value => {
-          order.push('myTransformer1');
-          return String(value);
-        });
-        reg.addTransformer('myTransformer2', async value => {
-          order.push('myTransformer2');
-          return value.toUpperCase();
-        });
-        dbs.defineModel({
-          name: 'model',
-          properties: {
-            foo: {
-              type: DataType.ANY,
-              transform: {
-                myTransformer1: true,
-                myTransformer2: true,
-              },
-            },
-          },
-        });
-        const T = dbs.getService(ModelDataTransformer);
-        const res = await T.transform('model', {foo: true});
-        expect(res).to.be.eql({foo: 'TRUE'});
-        expect(order).to.be.eql(['myTransformer1', 'myTransformer2']);
-      });
-    });
-  });
-});

+ 0 - 16
src/definition/model/model-data-validator.d.ts

@@ -1,16 +0,0 @@
-import {ModelData} from '../../types.js';
-import {Service} from '@e22m4u/js-service';
-
-/**
- * Model data validator.
- */
-export declare class ModelDataValidator extends Service {
-  /**
-   * Validate.
-   *
-   * @param modelName
-   * @param modelData
-   * @param isPartial
-   */
-  validate(modelName: string, modelData: ModelData, isPartial?: boolean): void;
-}

+ 0 - 318
src/definition/model/model-data-validator.js

@@ -1,318 +0,0 @@
-import {Service} from '@e22m4u/js-service';
-import {DataType} from './properties/index.js';
-import {getCtorName} from '../../utils/index.js';
-import {isPlainObject} from '../../utils/index.js';
-import {EmptyValuesService} from '@e22m4u/js-empty-values';
-import {InvalidArgumentError} from '../../errors/index.js';
-import {PropertyValidatorRegistry} from './properties/index.js';
-import {ModelDefinitionUtils} from './model-definition-utils.js';
-
-/**
- * Model data validator.
- */
-export class ModelDataValidator extends Service {
-  /**
-   * Validate.
-   *
-   * @param {string} modelName
-   * @param {object} modelData
-   * @param {boolean} isPartial
-   * @returns {undefined}
-   */
-  validate(modelName, modelData, isPartial = false) {
-    if (!isPlainObject(modelData))
-      throw new InvalidArgumentError(
-        'The data of the model %v should be an Object, but %v was given.',
-        modelName,
-        modelData,
-      );
-    const propDefs =
-      this.getService(
-        ModelDefinitionUtils,
-      ).getPropertiesDefinitionInBaseModelHierarchy(modelName);
-    const propNames = Object.keys(isPartial ? modelData : propDefs);
-    propNames.forEach(propName => {
-      const propDef = propDefs[propName];
-      if (!propDef) return;
-      this._validatePropertyValue(
-        modelName,
-        propName,
-        propDef,
-        modelData[propName],
-      );
-    });
-  }
-
-  /**
-   * Validate property value.
-   *
-   * @param {string} modelName
-   * @param {string} propName
-   * @param {string|object} propDef
-   * @param {*} propValue
-   * @returns {undefined}
-   */
-  _validatePropertyValue(modelName, propName, propDef, propValue) {
-    const propType =
-      this.getService(ModelDefinitionUtils).getDataTypeFromPropertyDefinition(
-        propDef,
-      );
-    const isEmpty = this.getService(EmptyValuesService).isEmptyByType(
-      propType,
-      propValue,
-    );
-    if (isEmpty) {
-      // skips validation
-      // for an empty value
-      const isRequired =
-        typeof propDef === 'string' ? false : Boolean(propDef.required);
-      if (!isRequired) return;
-      // a required property should
-      // not have an empty value
-      throw new InvalidArgumentError(
-        'The property %v of the model %v is required, but %v was given.',
-        propName,
-        modelName,
-        propValue,
-      );
-    }
-    // проверка соответствия типа значения
-    this._validateValueByPropertyType(modelName, propName, propDef, propValue);
-    // проверка значения валидаторами
-    this._validateValueByPropertyValidators(
-      modelName,
-      propName,
-      propDef,
-      propValue,
-    );
-  }
-
-  /**
-   * Validate value by property type.
-   *
-   * @param {string} modelName
-   * @param {string} propName
-   * @param {string|object} propDef
-   * @param {*} propValue
-   * @param {boolean} isArrayValue
-   * @returns {undefined}
-   */
-  _validateValueByPropertyType(
-    modelName,
-    propName,
-    propDef,
-    propValue,
-    isArrayValue = false,
-  ) {
-    let expectingType;
-    if (isArrayValue) {
-      if (typeof propDef === 'object') {
-        expectingType = propDef.itemType ?? DataType.ANY;
-      } else {
-        expectingType = DataType.ANY;
-      }
-    } else {
-      expectingType = typeof propDef !== 'string' ? propDef.type : propDef;
-    }
-
-    const createError = expected => {
-      const pattern = isArrayValue
-        ? 'The array property %v of the model %v must have %s element, but %s was given.'
-        : 'The property %v of the model %v must have %s, but %s was given.';
-      const ctorName = getCtorName(propValue);
-      const givenStr = ctorName ?? typeof propValue;
-      return new InvalidArgumentError(
-        pattern,
-        propName,
-        modelName,
-        expected,
-        givenStr,
-      );
-    };
-    switch (expectingType) {
-      // STRING
-      case DataType.STRING:
-        if (typeof propValue !== 'string') throw createError('a String');
-        break;
-      // NUMBER
-      case DataType.NUMBER:
-        if (typeof propValue !== 'number') throw createError('a Number');
-        break;
-      // BOOLEAN
-      case DataType.BOOLEAN:
-        if (typeof propValue !== 'boolean') throw createError('a Boolean');
-        break;
-      // ARRAY
-      case DataType.ARRAY:
-        if (!Array.isArray(propValue)) throw createError('an Array');
-        propValue.forEach(value =>
-          this._validateValueByPropertyType(
-            modelName,
-            propName,
-            propDef,
-            value,
-            true,
-          ),
-        );
-        break;
-      // OBJECT
-      case DataType.OBJECT: {
-        if (!isPlainObject(propValue)) throw createError('an Object');
-        if (typeof propDef === 'object') {
-          const modelOptionField = isArrayValue ? 'itemModel' : 'model';
-          const modelOptionValue = propDef[modelOptionField];
-          if (modelOptionValue) this.validate(modelOptionValue, propValue);
-        }
-        break;
-      }
-    }
-  }
-
-  /**
-   * Validate value by property validators.
-   *
-   * @param {string} modelName
-   * @param {string} propName
-   * @param {string|object} propDef
-   * @param {*} propValue
-   * @returns {undefined}
-   */
-  _validateValueByPropertyValidators(modelName, propName, propDef, propValue) {
-    if (typeof propDef === 'string' || propDef.validate == null) return;
-    const validateDef = propDef.validate;
-    const validatorRegistry = this.getService(PropertyValidatorRegistry);
-    const createError = validatorName => {
-      if (validatorName) {
-        return new InvalidArgumentError(
-          'The property %v of the model %v has the invalid value %v ' +
-            'that caught by the property validator %v.',
-          propName,
-          modelName,
-          propValue,
-          validatorName,
-        );
-      } else {
-        return new InvalidArgumentError(
-          'The property %v of the model %v has the invalid value %v ' +
-            'that caught by a property validator.',
-          propName,
-          modelName,
-          propValue,
-        );
-      }
-    };
-    // объявление функции для проверки значения
-    // с помощью указанного валидатора
-    const validateBy = (validatorOrName, validatorOptions = undefined) => {
-      let validatorName, validatorFn;
-      // если первый аргумент является строкой, то строка
-      // воспринимается как название зарегистрированного
-      // валидатора
-      if (typeof validatorOrName === 'string') {
-        validatorName = validatorOrName;
-        validatorFn = validatorRegistry.getValidator(validatorName);
-      }
-      // если первый аргумент является функцией,
-      // то функция воспринимается как валидатор
-      else if (typeof validatorOrName === 'function') {
-        validatorName =
-          validatorOrName.name && validatorOrName.name !== 'validate'
-            ? validatorOrName.name
-            : undefined;
-        validatorFn = validatorOrName;
-      }
-      // если первый аргумент не является строкой
-      // и функцией, то выбрасывается ошибка
-      else {
-        throw new InvalidArgumentError(
-          'Validator must be a non-empty String or ' +
-            'a Function, but %v was given.',
-          validatorOrName,
-        );
-      }
-      const context = {validatorName, modelName, propName};
-      const valid = validatorFn(propValue, validatorOptions, context);
-      // если валидатор возвращает Promise,
-      // то выбрасывается ошибка
-      if (valid instanceof Promise) {
-        if (validatorName) {
-          throw new InvalidArgumentError(
-            'Asynchronous property validators are not supported, ' +
-              'but the property %v of the model %v has the property ' +
-              'validator %v that returns a Promise.',
-            propName,
-            modelName,
-            validatorName,
-          );
-        } else {
-          throw new InvalidArgumentError(
-            'Asynchronous property validators are not supported, ' +
-              'but the property %v of the model %v has a property ' +
-              'validator that returns a Promise.',
-            propName,
-            modelName,
-          );
-        }
-      }
-      // если валидатор вернул значение отличное
-      // от true, то выбрасывается ошибка
-      else if (valid !== true) {
-        throw createError(validatorName);
-      }
-    };
-    // если значением опции "validate" является строка,
-    // то строка воспринимается как название валидатора
-    if (validateDef && typeof validateDef === 'string') {
-      validateBy(validateDef);
-    }
-    // если значение опции "validate" является функция,
-    // то функция воспринимается как валидатор
-    else if (validateDef && typeof validateDef === 'function') {
-      validateBy(validateDef);
-    }
-    // если значение опции "validate" является массив, то каждый
-    // элемент массива воспринимается как название валидатора
-    // или функция-валидатор
-    else if (Array.isArray(validateDef)) {
-      validateDef.forEach(validatorOrName => {
-        if (
-          !validatorOrName ||
-          (typeof validatorOrName !== 'string' &&
-            typeof validatorOrName !== 'function')
-        ) {
-          throw new InvalidArgumentError(
-            'The provided option "validate" for the property %v in the model %v ' +
-              'has an Array value that should contain validator names or validator ' +
-              'functions, but %v was given.',
-            propName,
-            modelName,
-            validatorOrName,
-          );
-        }
-        validateBy(validatorOrName);
-      });
-    }
-    // если значение опции "validate" является объектом,
-    // то ключи объекта воспринимаются как названия валидаторов,
-    // а их значения аргументами
-    else if (validateDef !== null && typeof validateDef === 'object') {
-      Object.keys(validateDef).forEach(validatorName => {
-        const validatorOptions = validateDef[validatorName];
-        validateBy(validatorName, validatorOptions);
-      });
-    }
-    // если значение опции "validate" не является строкой,
-    // функцией и массивом, то выбрасывается ошибка
-    else {
-      throw new InvalidArgumentError(
-        'The provided option "validate" for the property %v in the model %v ' +
-          'should be either a validator name, a validator function, an array ' +
-          'of validator names or functions, or an object mapping validator ' +
-          'names to their arguments, but %v was given.',
-        propName,
-        modelName,
-        validateDef,
-      );
-    }
-  }
-}

+ 0 - 4528
src/definition/model/model-data-validator.spec.js

@@ -1,4528 +0,0 @@
-import {expect} from 'chai';
-import {format} from '@e22m4u/js-format';
-import {DataType} from './properties/index.js';
-import {DatabaseSchema} from '../../database-schema.js';
-import {EmptyValuesService} from '@e22m4u/js-empty-values';
-import {ModelDataValidator} from './model-data-validator.js';
-import {DefinitionRegistry} from '../definition-registry.js';
-import {PropertyValidatorRegistry} from './properties/index.js';
-
-describe('ModelDataValidator', function () {
-  describe('validate', function () {
-    it('does not throw an error if a model does not have a property of a given data', function () {
-      const dbs = new DatabaseSchema();
-      dbs.defineModel({name: 'model'});
-      dbs.getService(ModelDataValidator).validate('model', {foo: 'bar'});
-    });
-
-    it('throws an error if a given data is not a pure object', function () {
-      const throwable = modelData => () => {
-        const dbs = new DatabaseSchema();
-        dbs.defineModel({
-          name: 'model',
-          datasource: 'datasource',
-        });
-        dbs.getService(ModelDataValidator).validate('model', modelData);
-      };
-      const error = v =>
-        format(
-          'The data of the model "model" should be an Object, but %s was given.',
-          v,
-        );
-      expect(throwable('str')).to.throw(error('"str"'));
-      expect(throwable(10)).to.throw(error('10'));
-      expect(throwable(true)).to.throw(error('true'));
-      expect(throwable(false)).to.throw(error('false'));
-      expect(throwable([])).to.throw(error('Array'));
-      expect(throwable(null)).to.throw(error('null'));
-      expect(throwable(undefined)).to.throw(error('undefined'));
-    });
-
-    it('uses a base model hierarchy to validate a given data', function () {
-      const dbs = new DatabaseSchema();
-      dbs.defineModel({
-        name: 'modelA',
-        properties: {
-          foo: DataType.STRING,
-        },
-      });
-      dbs.defineModel({
-        name: 'modelB',
-        base: 'modelA',
-      });
-      const throwable = () =>
-        dbs.getService(ModelDataValidator).validate('modelB', {foo: 10});
-      expect(throwable).to.throw(
-        'The property "foo" of the model "modelB" must ' +
-          'have a String, but Number was given.',
-      );
-    });
-
-    it('throws an error if a given data does not have a required property', function () {
-      const dbs = new DatabaseSchema();
-      dbs.defineModel({
-        name: 'model',
-        properties: {
-          foo: {
-            type: DataType.STRING,
-            required: true,
-          },
-        },
-      });
-      const throwable = () =>
-        dbs.getService(ModelDataValidator).validate('model', {});
-      expect(throwable).to.throw(
-        'The property "foo" of the model "model" ' +
-          'is required, but undefined was given.',
-      );
-    });
-
-    it('throws an error if a required property is undefined', function () {
-      const dbs = new DatabaseSchema();
-      dbs.defineModel({
-        name: 'model',
-        properties: {
-          foo: {
-            type: DataType.STRING,
-            required: true,
-          },
-        },
-      });
-      const throwable = () =>
-        dbs.getService(ModelDataValidator).validate('model', {foo: undefined});
-      expect(throwable).to.throw(
-        'The property "foo" of the model "model" is required, but undefined was given.',
-      );
-    });
-
-    it('throws an error if a required property is null', function () {
-      const dbs = new DatabaseSchema();
-      dbs.defineModel({
-        name: 'model',
-        properties: {
-          foo: {
-            type: DataType.STRING,
-            required: true,
-          },
-        },
-      });
-      const throwable = () =>
-        dbs.getService(ModelDataValidator).validate('model', {foo: null});
-      expect(throwable).to.throw(
-        'The property "foo" of the model "model" is required, but null was given.',
-      );
-    });
-
-    it('throws an error if a required property has an empty value', function () {
-      const dbs = new DatabaseSchema();
-      dbs.defineModel({
-        name: 'model',
-        properties: {
-          foo: {
-            type: DataType.STRING,
-            required: true,
-          },
-        },
-      });
-      dbs
-        .getService(EmptyValuesService)
-        .setEmptyValuesOf(DataType.STRING, ['empty']);
-      const throwable = () =>
-        dbs.getService(ModelDataValidator).validate('model', {foo: 'empty'});
-      expect(throwable).to.throw(
-        'The property "foo" of the model "model" ' +
-          'is required, but "empty" was given.',
-      );
-    });
-
-    it('should validate property type before passing value through property validators', function () {
-      const dbs = new DatabaseSchema();
-      dbs.defineModel({
-        name: 'model',
-        properties: {
-          foo: {
-            type: DataType.STRING,
-            validate: () => false,
-          },
-        },
-      });
-      const typeCheckFail = () =>
-        dbs.getService(ModelDataValidator).validate('model', {foo: 10});
-      expect(typeCheckFail).to.throw(
-        'The property "foo" of the model "model" must have ' +
-          'a String, but Number was given.',
-      );
-      const validatorCheckFail = () =>
-        dbs.getService(ModelDataValidator).validate('model', {foo: 'test'});
-      expect(validatorCheckFail).to.throw(
-        'The property "foo" of the model "model" has the invalid value "test" ' +
-          'that caught by a property validator.',
-      );
-    });
-
-    describe('an option "isPartial" is true', function () {
-      it('does not throw an error if a given data does not have a required property', function () {
-        const dbs = new DatabaseSchema();
-        dbs.defineModel({
-          name: 'model',
-          properties: {
-            foo: {
-              type: DataType.STRING,
-              required: true,
-            },
-          },
-        });
-        dbs.getService(ModelDataValidator).validate('model', {}, true);
-      });
-
-      it('throws an error if a required property is undefined', function () {
-        const dbs = new DatabaseSchema();
-        dbs.defineModel({
-          name: 'model',
-          properties: {
-            foo: {
-              type: DataType.STRING,
-              required: true,
-            },
-          },
-        });
-        const throwable = () =>
-          dbs
-            .getService(ModelDataValidator)
-            .validate('model', {foo: undefined}, true);
-        expect(throwable).to.throw(
-          'The property "foo" of the model "model" ' +
-            'is required, but undefined was given.',
-        );
-      });
-
-      it('throws an error if a required property is null', function () {
-        const dbs = new DatabaseSchema();
-        dbs.defineModel({
-          name: 'model',
-          properties: {
-            foo: {
-              type: DataType.STRING,
-              required: true,
-            },
-          },
-        });
-        const throwable = () =>
-          dbs
-            .getService(ModelDataValidator)
-            .validate('model', {foo: null}, true);
-        expect(throwable).to.throw(
-          'The property "foo" of the model "model" is required, but null was given.',
-        );
-      });
-
-      it('throws an error if a required property has an empty value', function () {
-        const dbs = new DatabaseSchema();
-        dbs.defineModel({
-          name: 'model',
-          properties: {
-            foo: {
-              type: DataType.STRING,
-              required: true,
-            },
-          },
-        });
-        dbs
-          .getService(EmptyValuesService)
-          .setEmptyValuesOf(DataType.STRING, [5]);
-        const throwable = () =>
-          dbs.getService(ModelDataValidator).validate('model', {foo: 5}, true);
-        expect(throwable).to.throw(
-          'The property "foo" of the model "model" is required, but 5 was given.',
-        );
-      });
-    });
-
-    describe('validate by property type', function () {
-      it('should not validate the empty value', function () {
-        const dbs = new DatabaseSchema();
-        dbs.defineModel({
-          name: 'model',
-          datasource: 'datasource',
-          properties: {
-            foo: {
-              type: DataType.STRING,
-            },
-          },
-        });
-        dbs
-          .getService(EmptyValuesService)
-          .setEmptyValuesOf(DataType.STRING, [5]);
-        dbs.getService(ModelDataValidator).validate('model', {foo: 5});
-      });
-
-      describe('DataType.ANY', function () {
-        describe('ShortPropertyDefinition', function () {
-          it('does not throw an error if an undefined given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.ANY,
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: undefined,
-            });
-          });
-
-          it('does not throw an error if a null given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.ANY,
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: null,
-            });
-          });
-
-          it('does not throw an error if a string given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.ANY,
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: 'bar',
-            });
-          });
-
-          it('does not throw an error if a number given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.ANY,
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: 10,
-            });
-          });
-
-          it('does not throw an error if true given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.ANY,
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: true,
-            });
-          });
-
-          it('does not throw an error if false given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.ANY,
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: false,
-            });
-          });
-
-          it('does not throw an error if an array given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.ANY,
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: [],
-            });
-          });
-
-          it('does not throw an error if an object given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.ANY,
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: {},
-            });
-          });
-        });
-
-        describe('FullPropertyDefinition', function () {
-          it('does not throw an error if an undefined given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: undefined,
-            });
-          });
-
-          it('does not throw an error if a null given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: null,
-            });
-          });
-
-          it('does not throw an error if a string given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: 'bar',
-            });
-          });
-
-          it('does not throw an error if a number given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: 10,
-            });
-          });
-
-          it('does not throw an error if true given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: true,
-            });
-          });
-
-          it('does not throw an error if false given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: false,
-            });
-          });
-
-          it('does not throw an error if an array given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: [],
-            });
-          });
-
-          it('does not throw an error if an object given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: {},
-            });
-          });
-        });
-      });
-
-      describe('DataType.STRING', function () {
-        describe('ShortPropertyDefinition', function () {
-          it('does not throw an error if an undefined given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.STRING,
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: undefined,
-            });
-          });
-
-          it('does not throw an error if a null given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.STRING,
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: null,
-            });
-          });
-
-          it('does not throw an error if a string given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.STRING,
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: 'bar',
-            });
-          });
-
-          it('throws an error if a number given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.STRING,
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 10,
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'a String, but Number was given.',
-            );
-          });
-
-          it('throws an error if true given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.STRING,
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: true,
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'a String, but Boolean was given.',
-            );
-          });
-
-          it('throws an error if false given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.STRING,
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: false,
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'a String, but Boolean was given.',
-            );
-          });
-
-          it('throws an error if an array given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.STRING,
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: [],
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'a String, but Array was given.',
-            );
-          });
-
-          it('throws an error if an object given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.STRING,
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: {},
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'a String, but Object was given.',
-            );
-          });
-        });
-
-        describe('FullPropertyDefinition', function () {
-          it('does not throw an error if an undefined given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.STRING,
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: undefined,
-            });
-          });
-
-          it('does not throw an error if a null given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.STRING,
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: null,
-            });
-          });
-
-          it('does not throw an error if a string given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.STRING,
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: 'bar',
-            });
-          });
-
-          it('throws an error if a number given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.STRING,
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 10,
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'a String, but Number was given.',
-            );
-          });
-
-          it('throws an error if true given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.STRING,
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: true,
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'a String, but Boolean was given.',
-            );
-          });
-
-          it('throws an error if false given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.STRING,
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: false,
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'a String, but Boolean was given.',
-            );
-          });
-
-          it('throws an error if an array given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.STRING,
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: [],
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'a String, but Array was given.',
-            );
-          });
-
-          it('throws an error if an object given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.STRING,
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: {},
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'a String, but Object was given.',
-            );
-          });
-        });
-      });
-
-      describe('DataType.NUMBER', function () {
-        describe('ShortPropertyDefinition', function () {
-          it('does not throw an error if an undefined given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.NUMBER,
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: undefined,
-            });
-          });
-
-          it('does not throw an error if a null given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.NUMBER,
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: null,
-            });
-          });
-
-          it('throws an error if a string given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.NUMBER,
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 'bar',
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'a Number, but String was given.',
-            );
-          });
-
-          it('does not throw an error if a number given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.NUMBER,
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: 10,
-            });
-          });
-
-          it('throws an error if true given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.NUMBER,
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: true,
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'a Number, but Boolean was given.',
-            );
-          });
-
-          it('throws an error if false given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.NUMBER,
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: false,
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'a Number, but Boolean was given.',
-            );
-          });
-
-          it('throws an error if an array given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.NUMBER,
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: [],
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'a Number, but Array was given.',
-            );
-          });
-
-          it('throws an error if an object given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.NUMBER,
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: {},
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'a Number, but Object was given.',
-            );
-          });
-        });
-
-        describe('FullPropertyDefinition', function () {
-          it('does not throw an error if an undefined given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.NUMBER,
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: undefined,
-            });
-          });
-
-          it('does not throw an error if a null given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.NUMBER,
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: null,
-            });
-          });
-
-          it('throws an error if a string given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.NUMBER,
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 'bar',
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'a Number, but String was given.',
-            );
-          });
-
-          it('does not throw an error if a number given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.NUMBER,
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: 10,
-            });
-          });
-
-          it('throws an error if true given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.NUMBER,
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: true,
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'a Number, but Boolean was given.',
-            );
-          });
-
-          it('throws an error if false given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.NUMBER,
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: false,
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'a Number, but Boolean was given.',
-            );
-          });
-
-          it('throws an error if an array given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.NUMBER,
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: [],
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'a Number, but Array was given.',
-            );
-          });
-
-          it('throws an error if an object given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.NUMBER,
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: {},
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'a Number, but Object was given.',
-            );
-          });
-        });
-      });
-
-      describe('DataType.BOOLEAN', function () {
-        describe('ShortPropertyDefinition', function () {
-          it('does not throw an error if an undefined given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.BOOLEAN,
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: undefined,
-            });
-          });
-
-          it('does not throw an error if a null given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.BOOLEAN,
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: null,
-            });
-          });
-
-          it('throws an error if a string given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.BOOLEAN,
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 'bar',
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'a Boolean, but String was given.',
-            );
-          });
-
-          it('throws an error if a number given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.BOOLEAN,
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 10,
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'a Boolean, but Number was given.',
-            );
-          });
-
-          it('does not throw an error if true given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.BOOLEAN,
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: true,
-            });
-          });
-
-          it('does not throw an error if false given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.BOOLEAN,
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: false,
-            });
-          });
-
-          it('throws an error if an array given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.BOOLEAN,
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: [],
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'a Boolean, but Array was given.',
-            );
-          });
-
-          it('throws an error if an object given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.BOOLEAN,
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: {},
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'a Boolean, but Object was given.',
-            );
-          });
-        });
-
-        describe('FullPropertyDefinition', function () {
-          it('does not throw an error if an undefined given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.BOOLEAN,
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: undefined,
-            });
-          });
-
-          it('does not throw an error if a null given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.BOOLEAN,
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: null,
-            });
-          });
-
-          it('throws an error if a string given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.BOOLEAN,
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 'bar',
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'a Boolean, but String was given.',
-            );
-          });
-
-          it('throws an error if a number given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.BOOLEAN,
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 10,
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'a Boolean, but Number was given.',
-            );
-          });
-
-          it('does not throw an error if true given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.BOOLEAN,
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: true,
-            });
-          });
-
-          it('does not throw an error if false given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.BOOLEAN,
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: false,
-            });
-          });
-
-          it('throws an error if an array given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.BOOLEAN,
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: [],
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'a Boolean, but Array was given.',
-            );
-          });
-
-          it('throws an error if an object given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.BOOLEAN,
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: {},
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'a Boolean, but Object was given.',
-            );
-          });
-        });
-      });
-
-      describe('DataType.ARRAY', function () {
-        describe('ShortPropertyDefinition', function () {
-          it('does not throw an error if an undefined given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.ARRAY,
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: undefined,
-            });
-          });
-
-          it('does not throw an error if a null given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.ARRAY,
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: null,
-            });
-          });
-
-          it('throws an error if a string given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.ARRAY,
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 'bar',
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'an Array, but String was given.',
-            );
-          });
-
-          it('throws an error if a number given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.ARRAY,
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 10,
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'an Array, but Number was given.',
-            );
-          });
-
-          it('throws an error if true given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.ARRAY,
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: true,
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'an Array, but Boolean was given.',
-            );
-          });
-
-          it('throws an error if false given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.ARRAY,
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: false,
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'an Array, but Boolean was given.',
-            );
-          });
-
-          it('does not throw an error if an array given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.ARRAY,
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: [],
-            });
-          });
-
-          it('throws an error if an object given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.ARRAY,
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: {},
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'an Array, but Object was given.',
-            );
-          });
-        });
-
-        describe('FullPropertyDefinition', function () {
-          it('does not throw an error if an undefined given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.ARRAY,
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: undefined,
-            });
-          });
-
-          it('does not throw an error if a null given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.ARRAY,
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: null,
-            });
-          });
-
-          it('throws an error if a string given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.ARRAY,
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 'bar',
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'an Array, but String was given.',
-            );
-          });
-
-          it('throws an error if a number given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.ARRAY,
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 10,
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'an Array, but Number was given.',
-            );
-          });
-
-          it('throws an error if true given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.ARRAY,
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: true,
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'an Array, but Boolean was given.',
-            );
-          });
-
-          it('throws an error if false given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.ARRAY,
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: false,
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'an Array, but Boolean was given.',
-            );
-          });
-
-          it('does not throw an error if an array given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.ARRAY,
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: [],
-            });
-          });
-
-          it('throws an error if an object given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.ARRAY,
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: {},
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'an Array, but Object was given.',
-            );
-          });
-
-          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 dbs = new DatabaseSchema();
-              dbs.defineModel({
-                name: 'model',
-                properties: {
-                  foo: {
-                    type: DataType.ARRAY,
-                    itemType: DataType.OBJECT,
-                  },
-                },
-              });
-              const value = {foo: [{a: 1}, {b: 2}]};
-              dbs.getService(ModelDataValidator).validate('model', value);
-            });
-
-            it('throws an error when the given object element has an invalid model', function () {
-              const dbs = new DatabaseSchema();
-              dbs.defineModel({
-                name: 'modelA',
-                properties: {
-                  foo: DataType.STRING,
-                },
-              });
-              dbs.defineModel({
-                name: 'modelB',
-                datasource: 'datasource',
-                properties: {
-                  bar: {
-                    type: DataType.ARRAY,
-                    itemType: DataType.OBJECT,
-                    itemModel: 'modelA',
-                  },
-                },
-              });
-              const throwable = () =>
-                dbs.getService(ModelDataValidator).validate('modelB', {
-                  bar: [{foo: 10}],
-                });
-              expect(throwable).to.throw(
-                'The property "foo" of the model "modelA" must have ' +
-                  'a String, but Number was given.',
-              );
-            });
-
-            it('does not throw an error when the given object element has a valid model', function () {
-              const dbs = new DatabaseSchema();
-              dbs.defineModel({
-                name: 'modelA',
-                properties: {
-                  foo: DataType.STRING,
-                },
-              });
-              dbs.defineModel({
-                name: 'modelB',
-                datasource: 'datasource',
-                properties: {
-                  bar: {
-                    type: DataType.ARRAY,
-                    itemType: DataType.OBJECT,
-                    itemModel: 'modelA',
-                  },
-                },
-              });
-              dbs.getService(ModelDataValidator).validate('modelB', {
-                bar: [{foo: '10'}],
-              });
-            });
-          });
-        });
-      });
-
-      describe('DataType.OBJECT', function () {
-        describe('ShortPropertyDefinition', function () {
-          it('does not throw an error if an undefined given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.OBJECT,
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: undefined,
-            });
-          });
-
-          it('does not throw an error if a null given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.OBJECT,
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: null,
-            });
-          });
-
-          it('throws an error if a string given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.OBJECT,
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 'bar',
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'an Object, but String was given.',
-            );
-          });
-
-          it('throws an error if a number given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.OBJECT,
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 10,
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'an Object, but Number was given.',
-            );
-          });
-
-          it('throws an error if true given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.OBJECT,
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: true,
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'an Object, but Boolean was given.',
-            );
-          });
-
-          it('throws an error if false given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.OBJECT,
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: false,
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'an Object, but Boolean was given.',
-            );
-          });
-
-          it('throws an error if an array given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.OBJECT,
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: [],
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'an Object, but Array was given.',
-            );
-          });
-
-          it('does not throw an error if an object given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: DataType.OBJECT,
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: {},
-            });
-          });
-        });
-
-        describe('FullPropertyDefinition', function () {
-          it('does not throw an error if an undefined given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.OBJECT,
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: undefined,
-            });
-          });
-
-          it('does not throw an error if a null given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.OBJECT,
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: null,
-            });
-          });
-
-          it('throws an error if a string given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.OBJECT,
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 'bar',
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'an Object, but String was given.',
-            );
-          });
-
-          it('throws an error if a number given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.OBJECT,
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 10,
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'an Object, but Number was given.',
-            );
-          });
-
-          it('throws an error if true given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.OBJECT,
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: true,
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'an Object, but Boolean was given.',
-            );
-          });
-
-          it('throws an error if false given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.OBJECT,
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: false,
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'an Object, but Boolean was given.',
-            );
-          });
-
-          it('throws an error if an array given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.OBJECT,
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: [],
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" must have ' +
-                'an Object, but Array was given.',
-            );
-          });
-
-          it('does not throw an error if an object given', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              datasource: 'datasource',
-              properties: {
-                foo: {
-                  type: DataType.OBJECT,
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: {},
-            });
-          });
-
-          describe('the "model" option', function () {
-            it('throws an error when the given object has an invalid model', function () {
-              const dbs = new DatabaseSchema();
-              dbs.defineModel({
-                name: 'modelA',
-                properties: {
-                  foo: DataType.STRING,
-                },
-              });
-              dbs.defineModel({
-                name: 'modelB',
-                datasource: 'datasource',
-                properties: {
-                  bar: {
-                    type: DataType.OBJECT,
-                    model: 'modelA',
-                  },
-                },
-              });
-              const throwable = () =>
-                dbs.getService(ModelDataValidator).validate('modelB', {
-                  bar: {foo: 10},
-                });
-              expect(throwable).to.throw(
-                'The property "foo" of the model "modelA" must have ' +
-                  'a String, but Number was given.',
-              );
-            });
-
-            it('does not throw an error when the given object has a valid model', function () {
-              const dbs = new DatabaseSchema();
-              dbs.defineModel({
-                name: 'modelA',
-                properties: {
-                  foo: DataType.STRING,
-                },
-              });
-              dbs.defineModel({
-                name: 'modelB',
-                datasource: 'datasource',
-                properties: {
-                  bar: {
-                    type: DataType.OBJECT,
-                    model: 'modelA',
-                  },
-                },
-              });
-              dbs.getService(ModelDataValidator).validate('modelB', {
-                bar: {foo: '10'},
-              });
-            });
-          });
-        });
-      });
-    });
-
-    describe('validate by property validators', function () {
-      describe('when the option "validate" is a String', function () {
-        it('should not validate the non-provided property', function () {
-          const dbs = new DatabaseSchema();
-          const reg = dbs.getService(PropertyValidatorRegistry);
-          reg.addValidator('myValidator', function () {
-            throw new Error('Should not to be called.');
-          });
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                validate: 'myValidator',
-              },
-            },
-          });
-          const validator = dbs.getService(ModelDataValidator);
-          validator.validate('model', {});
-        });
-
-        it('should not validate undefined and null values', function () {
-          const dbs = new DatabaseSchema();
-          const reg = dbs.getService(PropertyValidatorRegistry);
-          reg.addValidator('myValidator', function () {
-            throw new Error('Should not to be called.');
-          });
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                validate: 'myValidator',
-              },
-            },
-          });
-          const validator = dbs.getService(ModelDataValidator);
-          validator.validate('model', {foo: undefined});
-          validator.validate('model', {foo: null});
-        });
-
-        it('should not validate the empty value', function () {
-          const dbs = new DatabaseSchema();
-          const reg = dbs.getService(PropertyValidatorRegistry);
-          reg.addValidator('myValidator', function () {
-            throw new Error('Should not to be called.');
-          });
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.STRING,
-                validate: 'myValidator',
-              },
-            },
-          });
-          dbs
-            .getService(EmptyValuesService)
-            .setEmptyValuesOf(DataType.STRING, [5]);
-          dbs.getService(ModelDataValidator).validate('model', {foo: 5});
-        });
-
-        it('should throw the error for the non-existent validator name', function () {
-          const dbs = new DatabaseSchema();
-          const modelDef = {
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                validate: undefined,
-              },
-            },
-          };
-          dbs.defineModel(modelDef);
-          modelDef.properties.foo.validate = 'myValidator';
-          const throwable = () =>
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: 'test',
-            });
-          expect(throwable).to.throw(
-            'The property validator "myValidator" is not defined.',
-          );
-        });
-
-        it('should throw the error from the validator', function () {
-          const dbs = new DatabaseSchema();
-          const reg = dbs.getService(PropertyValidatorRegistry);
-          reg.addValidator('myValidator', function () {
-            throw Error('My error');
-          });
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                validate: 'myValidator',
-              },
-            },
-          });
-          const throwable = () =>
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: 'test',
-            });
-          expect(throwable).to.throw('My error');
-        });
-
-        it('should allow the given value if the validator returns true', function () {
-          let called = 0;
-          const dbs = new DatabaseSchema();
-          const reg = dbs.getService(PropertyValidatorRegistry);
-          reg.addValidator('myValidator', function () {
-            called++;
-            return true;
-          });
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                validate: 'myValidator',
-              },
-            },
-          });
-          dbs.getService(ModelDataValidator).validate('model', {
-            foo: 'test',
-          });
-          expect(called).to.be.eq(1);
-        });
-
-        it('should throw the error if the validator returns a promise', function () {
-          let called = 0;
-          const dbs = new DatabaseSchema();
-          const reg = dbs.getService(PropertyValidatorRegistry);
-          reg.addValidator('myValidator', function () {
-            called++;
-            return Promise.resolve(true);
-          });
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                validate: 'myValidator',
-              },
-            },
-          });
-          const throwable = () =>
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: 'test',
-            });
-          expect(throwable).to.throw(
-            'Asynchronous property validators are not supported, ' +
-              'but the property "foo" of the model "model" has the property ' +
-              'validator "myValidator" that returns a Promise.',
-          );
-          expect(called).to.be.eq(1);
-        });
-
-        it('should throw the error for a non-true result from the validator', function () {
-          const testFn = v => {
-            let called = 0;
-            const dbs = new DatabaseSchema();
-            const reg = dbs.getService(PropertyValidatorRegistry);
-            reg.addValidator('myValidator', function () {
-              called++;
-              return v;
-            });
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  validate: 'myValidator',
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 'test',
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" has the invalid value "test" ' +
-                'that caught by the property validator "myValidator".',
-            );
-            expect(called).to.be.eq(1);
-          };
-          testFn('str');
-          testFn('');
-          testFn(10);
-          testFn(0);
-          testFn(false);
-          testFn(undefined);
-          testFn(null);
-          testFn({});
-          testFn([]);
-          testFn(() => undefined);
-        });
-
-        it('should pass arguments to the validator', function () {
-          let called = 0;
-          const dbs = new DatabaseSchema();
-          const reg = dbs.getService(PropertyValidatorRegistry);
-          reg.addValidator('myValidator', function (value, options, context) {
-            expect(value).to.be.eq('test');
-            expect(options).to.be.undefined;
-            expect(context).to.be.eql({
-              validatorName: 'myValidator',
-              modelName: 'model',
-              propName: 'foo',
-            });
-            called++;
-            return true;
-          });
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                validate: 'myValidator',
-              },
-            },
-          });
-          dbs.getService(ModelDataValidator).validate('model', {
-            foo: 'test',
-          });
-          expect(called).to.be.eq(1);
-        });
-
-        it('should invoke the validator only once per value', function () {
-          let invoked = 0;
-          const dbs = new DatabaseSchema();
-          const reg = dbs.getService(PropertyValidatorRegistry);
-          reg.addValidator('myValidator', function () {
-            invoked++;
-            return true;
-          });
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                validate: 'myValidator',
-              },
-            },
-          });
-          dbs.getService(ModelDataValidator).validate('model', {
-            foo: 'test',
-          });
-          expect(invoked).to.be.eq(1);
-        });
-      });
-
-      describe('when the option "validate" is a Function', function () {
-        describe('named validators', function () {
-          it('should not validate the non-provided property', function () {
-            const dbs = new DatabaseSchema();
-            const myValidator = function () {
-              throw new Error('Should not to be called.');
-            };
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  validate: myValidator,
-                },
-              },
-            });
-            const validator = dbs.getService(ModelDataValidator);
-            validator.validate('model', {});
-          });
-
-          it('should not validate undefined and null values', function () {
-            const dbs = new DatabaseSchema();
-            const myValidator = () => {
-              throw new Error('Should not to be called.');
-            };
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  validate: myValidator,
-                },
-              },
-            });
-            const validator = dbs.getService(ModelDataValidator);
-            validator.validate('model', {foo: undefined});
-            validator.validate('model', {foo: null});
-          });
-
-          it('should not validate the empty value', function () {
-            const dbs = new DatabaseSchema();
-            const myValidator = function () {
-              throw new Error('Should not to be called.');
-            };
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.STRING,
-                  validate: myValidator,
-                },
-              },
-            });
-            dbs
-              .getService(EmptyValuesService)
-              .setEmptyValuesOf(DataType.STRING, [5]);
-            dbs.getService(ModelDataValidator).validate('model', {foo: 5});
-          });
-
-          it('should throw the error from the validator', function () {
-            const dbs = new DatabaseSchema();
-            const myValidator = function () {
-              throw Error('My error');
-            };
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  validate: myValidator,
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 'test',
-              });
-            expect(throwable).to.throw('My error');
-          });
-
-          it('should allow the given value if the validator returns true', function () {
-            const dbs = new DatabaseSchema();
-            let called = 0;
-            const myValidator = function () {
-              called++;
-              return true;
-            };
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  validate: myValidator,
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: 'test',
-            });
-            expect(called).to.be.eq(1);
-          });
-
-          it('should throw the error if the validator returns a promise', function () {
-            const dbs = new DatabaseSchema();
-            const myValidator = function () {
-              return Promise.resolve(true);
-            };
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  validate: myValidator,
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 'test',
-              });
-            expect(throwable).to.throw(
-              'Asynchronous property validators are not supported, ' +
-                'but the property "foo" of the model "model" has the property ' +
-                'validator "myValidator" that returns a Promise.',
-            );
-          });
-
-          it('should throw the error for a non-true result from the validator', function () {
-            const testFn = v => {
-              const dbs = new DatabaseSchema();
-              const myValidator = function () {
-                return v;
-              };
-              dbs.defineModel({
-                name: 'model',
-                properties: {
-                  foo: {
-                    type: DataType.ANY,
-                    validate: myValidator,
-                  },
-                },
-              });
-              const throwable = () =>
-                dbs.getService(ModelDataValidator).validate('model', {
-                  foo: 'test',
-                });
-              expect(throwable).to.throw(
-                'The property "foo" of the model "model" has the invalid value "test" ' +
-                  'that caught by the property validator "myValidator".',
-              );
-            };
-            testFn('str');
-            testFn('');
-            testFn(10);
-            testFn(0);
-            testFn(false);
-            testFn(undefined);
-            testFn(null);
-            testFn({});
-            testFn([]);
-            testFn(() => undefined);
-          });
-
-          it('should pass arguments to the validator', function () {
-            let called = 0;
-            const dbs = new DatabaseSchema();
-            const myValidator = function (value, options, context) {
-              expect(value).to.be.eq('test');
-              expect(options).to.be.undefined;
-              expect(context).to.be.eql({
-                validatorName: 'myValidator',
-                modelName: 'model',
-                propName: 'foo',
-              });
-              called++;
-              return true;
-            };
-            dbs
-              .getService(PropertyValidatorRegistry)
-              .addValidator('myValidator', myValidator);
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  validate: 'myValidator',
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: 'test',
-            });
-            expect(called).to.be.eq(1);
-          });
-
-          it('should invoke the validator only once per value', function () {
-            let invoked = 0;
-            const myValidator = function () {
-              invoked++;
-              return true;
-            };
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  validate: myValidator,
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: 'test',
-            });
-            expect(invoked).to.be.eq(1);
-          });
-        });
-
-        describe('anonymous validators', function () {
-          it('should not validate the non-provided property', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  validate() {
-                    throw new Error('Should not to be called.');
-                  },
-                },
-              },
-            });
-            const validator = dbs.getService(ModelDataValidator);
-            validator.validate('model', {});
-          });
-
-          it('should not validate undefined and null values', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  validate() {
-                    throw new Error('Should not to be called.');
-                  },
-                },
-              },
-            });
-            const validator = dbs.getService(ModelDataValidator);
-            validator.validate('model', {foo: undefined});
-            validator.validate('model', {foo: null});
-          });
-
-          it('should not validate the empty value', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.STRING,
-                  validate() {
-                    throw new Error('Should not to be called.');
-                  },
-                },
-              },
-            });
-            dbs
-              .getService(EmptyValuesService)
-              .setEmptyValuesOf(DataType.STRING, [5]);
-            dbs.getService(ModelDataValidator).validate('model', {foo: 5});
-          });
-
-          it('should throw the error from the validator', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  validate() {
-                    throw Error('My error');
-                  },
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 'test',
-              });
-            expect(throwable).to.throw('My error');
-          });
-
-          it('should allow the given value if the validator returns true', function () {
-            const dbs = new DatabaseSchema();
-            let called = 0;
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  validate() {
-                    called++;
-                    return true;
-                  },
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: 'test',
-            });
-            expect(called).to.be.eq(1);
-          });
-
-          it('should throw the error if the validator returns a promise', function () {
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  validate() {
-                    return Promise.resolve(true);
-                  },
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 'test',
-              });
-            expect(throwable).to.throw(
-              'Asynchronous property validators are not supported, ' +
-                'but the property "foo" of the model "model" has a property ' +
-                'validator that returns a Promise.',
-            );
-          });
-
-          it('should throw the error for a non-true result from the validator', function () {
-            const testFn = v => {
-              const dbs = new DatabaseSchema();
-              dbs.defineModel({
-                name: 'model',
-                properties: {
-                  foo: {
-                    type: DataType.ANY,
-                    validate() {
-                      return v;
-                    },
-                  },
-                },
-              });
-              const throwable = () =>
-                dbs.getService(ModelDataValidator).validate('model', {
-                  foo: 'test',
-                });
-              expect(throwable).to.throw(
-                'The property "foo" of the model "model" has the invalid value "test" ' +
-                  'that caught by a property validator.',
-              );
-            };
-            testFn('str');
-            testFn('');
-            testFn(10);
-            testFn(0);
-            testFn(false);
-            testFn(undefined);
-            testFn(null);
-            testFn({});
-            testFn([]);
-            testFn(() => undefined);
-          });
-
-          it('should pass arguments to the validator', function () {
-            let called = 0;
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  validate(value, options, context) {
-                    expect(value).to.be.eq('test');
-                    expect(options).to.be.undefined;
-                    expect(context).to.be.eql({
-                      validatorName: undefined,
-                      modelName: 'model',
-                      propName: 'foo',
-                    });
-                    called++;
-                    return true;
-                  },
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: 'test',
-            });
-            expect(called).to.be.eq(1);
-          });
-
-          it('should invoke the validator only once per value', function () {
-            let invoked = 0;
-            const dbs = new DatabaseSchema();
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  validate() {
-                    invoked++;
-                    return true;
-                  },
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: 'test',
-            });
-            expect(invoked).to.be.eq(1);
-          });
-        });
-      });
-
-      describe('when the option "validate" is an Array', function () {
-        it('does nothing for an empty array validators', function () {
-          const dbs = new DatabaseSchema();
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                validate: [],
-              },
-            },
-          });
-          dbs.getService(ModelDataValidator).validate('model', {
-            foo: 'test',
-          });
-        });
-
-        it('the option "validate" requires a non-empty String, a Function, an Array or an Object', function () {
-          const dbs = new DatabaseSchema();
-          dbs
-            .getService(PropertyValidatorRegistry)
-            .addValidator('myValidator', () => true);
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                validate: undefined,
-              },
-            },
-          });
-          const V = dbs.getService(ModelDataValidator);
-          const throwable = v => () => {
-            const models = dbs.getService(DefinitionRegistry)['_models'];
-            models.model.properties.foo.validate = v;
-            V.validate('model', {foo: 'bar'});
-          };
-          const error = v =>
-            format(
-              'The provided option "validate" for the property "foo" in the model "model" ' +
-                'should be either a validator name, a validator function, an array ' +
-                'of validator names or functions, or an object mapping validator ' +
-                'names to their arguments, but %s was given.',
-              v,
-            );
-          expect(throwable('')).to.throw(error('""'));
-          expect(throwable(10)).to.throw(error('10'));
-          expect(throwable(0)).to.throw(error('0'));
-          expect(throwable(true)).to.throw(error('true'));
-          expect(throwable(false)).to.throw(error('false'));
-          throwable('myValidator')();
-          throwable(() => true)();
-          throwable(['myValidator'])();
-          throwable([() => true])();
-          throwable([])();
-          throwable({myValidator: true})();
-          throwable({})();
-        });
-
-        it('the option "validate" with an Array value requires elements to be a non-empty String or a Function', function () {
-          const dbs = new DatabaseSchema();
-          dbs
-            .getService(PropertyValidatorRegistry)
-            .addValidator('myValidator', () => true);
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                validate: undefined,
-              },
-            },
-          });
-          const V = dbs.getService(ModelDataValidator);
-          const throwable = v => () => {
-            const models = dbs.getService(DefinitionRegistry)['_models'];
-            models.model.properties.foo.validate = [v];
-            V.validate('model', {foo: 'bar'});
-          };
-          const error = v =>
-            format(
-              'The provided option "validate" for the property "foo" in the model "model" ' +
-                'has an Array value that should contain validator names or validator ' +
-                'functions, but %s was given.',
-              v,
-            );
-          expect(throwable('')).to.throw(error('""'));
-          expect(throwable(10)).to.throw(error('10'));
-          expect(throwable(0)).to.throw(error('0'));
-          expect(throwable(true)).to.throw(error('true'));
-          expect(throwable(false)).to.throw(error('false'));
-          expect(throwable([1, 2, 3])).to.throw(error('Array'));
-          expect(throwable({foo: 'bar'})).to.throw(error('Object'));
-          expect(throwable(null)).to.throw(error('null'));
-          expect(throwable(undefined)).to.throw(error('undefined'));
-          throwable('myValidator')();
-          throwable(() => true)();
-        });
-
-        describe('when an array element is a String', function () {
-          it('should not validate the non-provided property', function () {
-            let calls = 0;
-            const dbs = new DatabaseSchema();
-            const reg = dbs.getService(PropertyValidatorRegistry);
-            reg.addValidator('myValidator1', function () {
-              calls++;
-              throw new Error('Should not to be called.');
-            });
-            reg.addValidator('myValidator2', function () {
-              calls++;
-              throw new Error('Should not to be called.');
-            });
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  validate: ['myValidator1', 'myValidator2'],
-                },
-              },
-            });
-            const validator = dbs.getService(ModelDataValidator);
-            validator.validate('model', {});
-            expect(calls).to.be.eq(0);
-          });
-
-          it('should not validate undefined and null values', function () {
-            let calls = 0;
-            const dbs = new DatabaseSchema();
-            const reg = dbs.getService(PropertyValidatorRegistry);
-            reg.addValidator('myValidator1', function () {
-              calls++;
-              throw new Error('Should not to be called.');
-            });
-            reg.addValidator('myValidator2', function () {
-              calls++;
-              throw new Error('Should not to be called.');
-            });
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  validate: ['myValidator1', 'myValidator2'],
-                },
-              },
-            });
-            const validator = dbs.getService(ModelDataValidator);
-            validator.validate('model', {foo: undefined});
-            validator.validate('model', {foo: null});
-            expect(calls).to.be.eq(0);
-          });
-
-          it('should not validate the empty value', function () {
-            let calls = 0;
-            const dbs = new DatabaseSchema();
-            const reg = dbs.getService(PropertyValidatorRegistry);
-            reg.addValidator('myValidator1', function () {
-              calls++;
-              throw new Error('Should not to be called.');
-            });
-            reg.addValidator('myValidator2', function () {
-              calls++;
-              throw new Error('Should not to be called.');
-            });
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.STRING,
-                  validate: ['myValidator1', 'myValidator2'],
-                },
-              },
-            });
-            dbs
-              .getService(EmptyValuesService)
-              .setEmptyValuesOf(DataType.STRING, [5]);
-            dbs.getService(ModelDataValidator).validate('model', {foo: 5});
-            expect(calls).to.be.eq(0);
-          });
-
-          it('should throw the error for the non-existent validator name', function () {
-            let called = 0;
-            const dbs = new DatabaseSchema();
-            const reg = dbs.getService(PropertyValidatorRegistry);
-            reg.addValidator('myValidator1', function () {
-              called++;
-              return true;
-            });
-            const modelDef = {
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  validate: ['myValidator1'],
-                },
-              },
-            };
-            dbs.defineModel(modelDef);
-            modelDef.properties.foo.validate.push('myValidator2');
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 'test',
-              });
-            expect(throwable).to.throw(
-              'The property validator "myValidator2" is not defined.',
-            );
-            expect(called).to.be.eq(1);
-          });
-
-          it('should throw the error from the first validator', function () {
-            let called = 0;
-            const dbs = new DatabaseSchema();
-            const reg = dbs.getService(PropertyValidatorRegistry);
-            reg.addValidator('myValidator1', function () {
-              called++;
-              throw Error('My error');
-            });
-            reg.addValidator('myValidator2', function () {
-              called++;
-              return false;
-            });
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  validate: ['myValidator1', 'myValidator2'],
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 'test',
-              });
-            expect(throwable).to.throw('My error');
-            expect(called).to.be.eq(1);
-          });
-
-          it('should throw the error from the second validator', function () {
-            let called = 0;
-            const dbs = new DatabaseSchema();
-            const reg = dbs.getService(PropertyValidatorRegistry);
-            reg.addValidator('myValidator1', function () {
-              called++;
-              return true;
-            });
-            reg.addValidator('myValidator2', function () {
-              called++;
-              throw Error('My error');
-            });
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  validate: ['myValidator1', 'myValidator2'],
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 'test',
-              });
-            expect(throwable).to.throw('My error');
-            expect(called).to.be.eq(2);
-          });
-
-          it('should allow the given value if validators returns true', function () {
-            let called = 0;
-            const dbs = new DatabaseSchema();
-            const reg = dbs.getService(PropertyValidatorRegistry);
-            reg.addValidator('myValidator1', function () {
-              called++;
-              return true;
-            });
-            reg.addValidator('myValidator2', function () {
-              called++;
-              return true;
-            });
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  validate: ['myValidator1', 'myValidator2'],
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: 'test',
-            });
-            expect(called).to.be.eq(2);
-          });
-
-          it('should throw the error if the first validator returns a promise', function () {
-            let called = 0;
-            const dbs = new DatabaseSchema();
-            const reg = dbs.getService(PropertyValidatorRegistry);
-            reg.addValidator('myValidator1', function () {
-              called++;
-              return Promise.resolve(true);
-            });
-            reg.addValidator('myValidator2', function () {
-              called++;
-              return true;
-            });
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  validate: ['myValidator1', 'myValidator2'],
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 'test',
-              });
-            expect(throwable).to.throw(
-              'Asynchronous property validators are not supported, ' +
-                'but the property "foo" of the model "model" has the property ' +
-                'validator "myValidator1" that returns a Promise.',
-            );
-            expect(called).to.be.eq(1);
-          });
-
-          it('should throw the error if the second validator returns a promise', function () {
-            let called = 0;
-            const dbs = new DatabaseSchema();
-            const reg = dbs.getService(PropertyValidatorRegistry);
-            reg.addValidator('myValidator1', function () {
-              called++;
-              return true;
-            });
-            reg.addValidator('myValidator2', function () {
-              called++;
-              return Promise.resolve(true);
-            });
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  validate: ['myValidator1', 'myValidator2'],
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 'test',
-              });
-            expect(throwable).to.throw(
-              'Asynchronous property validators are not supported, ' +
-                'but the property "foo" of the model "model" has the property ' +
-                'validator "myValidator2" that returns a Promise.',
-            );
-            expect(called).to.be.eq(2);
-          });
-
-          it('should throw the error for a non-true result from the first validator', function () {
-            const testFn = v => {
-              let called = 0;
-              const dbs = new DatabaseSchema();
-              const reg = dbs.getService(PropertyValidatorRegistry);
-              reg.addValidator('myValidator1', function () {
-                called++;
-                return v;
-              });
-              reg.addValidator('myValidator2', function () {
-                called++;
-                return true;
-              });
-              dbs.defineModel({
-                name: 'model',
-                properties: {
-                  foo: {
-                    type: DataType.ANY,
-                    validate: ['myValidator1', 'myValidator2'],
-                  },
-                },
-              });
-              const throwable = () =>
-                dbs.getService(ModelDataValidator).validate('model', {
-                  foo: 'test',
-                });
-              expect(throwable).to.throw(
-                'The property "foo" of the model "model" has the invalid value "test" ' +
-                  'that caught by the property validator "myValidator1".',
-              );
-              expect(called).to.be.eq(1);
-            };
-            testFn('str');
-            testFn('');
-            testFn(10);
-            testFn(0);
-            testFn(false);
-            testFn(undefined);
-            testFn(null);
-            testFn({});
-            testFn([]);
-            testFn(() => undefined);
-          });
-
-          it('should throw the error for a non-true result from the second validator', function () {
-            const testFn = v => {
-              let called = 0;
-              const dbs = new DatabaseSchema();
-              const reg = dbs.getService(PropertyValidatorRegistry);
-              reg.addValidator('myValidator1', function () {
-                called++;
-                return true;
-              });
-              reg.addValidator('myValidator2', function () {
-                called++;
-                return v;
-              });
-              dbs.defineModel({
-                name: 'model',
-                properties: {
-                  foo: {
-                    type: DataType.ANY,
-                    validate: ['myValidator1', 'myValidator2'],
-                  },
-                },
-              });
-              const throwable = () =>
-                dbs.getService(ModelDataValidator).validate('model', {
-                  foo: 'test',
-                });
-              expect(throwable).to.throw(
-                'The property "foo" of the model "model" has the invalid value "test" ' +
-                  'that caught by the property validator "myValidator2".',
-              );
-              expect(called).to.be.eq(2);
-            };
-            testFn('str');
-            testFn('');
-            testFn(10);
-            testFn(0);
-            testFn(false);
-            testFn(undefined);
-            testFn(null);
-            testFn({});
-            testFn([]);
-            testFn(() => undefined);
-          });
-
-          it('should pass arguments to validators', function () {
-            let called = false;
-            const dbs = new DatabaseSchema();
-            const reg = dbs.getService(PropertyValidatorRegistry);
-            reg.addValidator(
-              'myValidator1',
-              function (value, options, context) {
-                expect(value).to.be.eq('test');
-                expect(options).to.be.undefined;
-                expect(context).to.be.eql({
-                  validatorName: 'myValidator1',
-                  modelName: 'model',
-                  propName: 'foo',
-                });
-                called++;
-                return true;
-              },
-            );
-            reg.addValidator(
-              'myValidator2',
-              function (value, options, context) {
-                expect(value).to.be.eq('test');
-                expect(options).to.be.undefined;
-                expect(context).to.be.eql({
-                  validatorName: 'myValidator2',
-                  modelName: 'model',
-                  propName: 'foo',
-                });
-                called++;
-                return true;
-              },
-            );
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  validate: ['myValidator1', 'myValidator2'],
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: 'test',
-            });
-            expect(called).to.be.eq(2);
-          });
-
-          it('should invoke validators in the correct order', function () {
-            const invocation = [];
-            const dbs = new DatabaseSchema();
-            const reg = dbs.getService(PropertyValidatorRegistry);
-            reg.addValidator('myValidator1', function () {
-              invocation.push('myValidator1');
-              return true;
-            });
-            reg.addValidator('myValidator2', function () {
-              invocation.push('myValidator2');
-              return true;
-            });
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  validate: ['myValidator1', 'myValidator2'],
-                },
-              },
-            });
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: 'test',
-            });
-            expect(invocation).to.be.eql(['myValidator1', 'myValidator2']);
-          });
-        });
-
-        describe('when an array element is a Function', function () {
-          describe('named validators', function () {
-            it('should not validate the non-provided property', function () {
-              let calls = 0;
-              const dbs = new DatabaseSchema();
-              const myValidator1 = function () {
-                calls++;
-                throw new Error('Should not to be called.');
-              };
-              const myValidator2 = function () {
-                calls++;
-                throw new Error('Should not to be called.');
-              };
-              dbs.defineModel({
-                name: 'model',
-                properties: {
-                  foo: {
-                    type: DataType.ANY,
-                    validate: [myValidator1, myValidator2],
-                  },
-                },
-              });
-              const validator = dbs.getService(ModelDataValidator);
-              validator.validate('model', {});
-              expect(calls).to.be.eq(0);
-            });
-
-            it('should not validate undefined and null values', function () {
-              let calls = 0;
-              const dbs = new DatabaseSchema();
-              const myValidator1 = function () {
-                calls++;
-                throw new Error('Should not to be called.');
-              };
-              const myValidator2 = function () {
-                calls++;
-                throw new Error('Should not to be called.');
-              };
-              dbs.defineModel({
-                name: 'model',
-                properties: {
-                  foo: {
-                    type: DataType.ANY,
-                    validate: [myValidator1, myValidator2],
-                  },
-                },
-              });
-              const validator = dbs.getService(ModelDataValidator);
-              validator.validate('model', {foo: undefined});
-              validator.validate('model', {foo: null});
-              expect(calls).to.be.eq(0);
-            });
-
-            it('should not validate the empty value', function () {
-              let calls = 0;
-              const dbs = new DatabaseSchema();
-              const myValidator1 = function () {
-                calls++;
-                throw new Error('Should not to be called.');
-              };
-              const myValidator2 = function () {
-                calls++;
-                throw new Error('Should not to be called.');
-              };
-              dbs.defineModel({
-                name: 'model',
-                properties: {
-                  foo: {
-                    type: DataType.STRING,
-                    validate: [myValidator1, myValidator2],
-                  },
-                },
-              });
-              dbs
-                .getService(EmptyValuesService)
-                .setEmptyValuesOf(DataType.STRING, [5]);
-              dbs.getService(ModelDataValidator).validate('model', {foo: 5});
-              expect(calls).to.be.eq(0);
-            });
-
-            it('should throw the error from the first validator', function () {
-              let called = 0;
-              const dbs = new DatabaseSchema();
-              const myValidator1 = function () {
-                called++;
-                throw Error('My error');
-              };
-              const myValidator2 = function () {
-                called++;
-                return false;
-              };
-              dbs.defineModel({
-                name: 'model',
-                properties: {
-                  foo: {
-                    type: DataType.ANY,
-                    validate: [myValidator1, myValidator2],
-                  },
-                },
-              });
-              const throwable = () =>
-                dbs.getService(ModelDataValidator).validate('model', {
-                  foo: 'test',
-                });
-              expect(throwable).to.throw('My error');
-              expect(called).to.be.eq(1);
-            });
-
-            it('should throw the error from the second validator', function () {
-              let called = 0;
-              const dbs = new DatabaseSchema();
-              const myValidator1 = function () {
-                called++;
-                return true;
-              };
-              const myValidator2 = function () {
-                called++;
-                throw Error('My error');
-              };
-              dbs.defineModel({
-                name: 'model',
-                properties: {
-                  foo: {
-                    type: DataType.ANY,
-                    validate: [myValidator1, myValidator2],
-                  },
-                },
-              });
-              const throwable = () =>
-                dbs.getService(ModelDataValidator).validate('model', {
-                  foo: 'test',
-                });
-              expect(throwable).to.throw('My error');
-              expect(called).to.be.eq(2);
-            });
-
-            it('should allow the given value if validators returns true', function () {
-              let called = 0;
-              const dbs = new DatabaseSchema();
-              const myValidator1 = function () {
-                called++;
-                return true;
-              };
-              const myValidator2 = function () {
-                called++;
-                return true;
-              };
-              dbs.defineModel({
-                name: 'model',
-                properties: {
-                  foo: {
-                    type: DataType.ANY,
-                    validate: [myValidator1, myValidator2],
-                  },
-                },
-              });
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 'test',
-              });
-              expect(called).to.be.eq(2);
-            });
-
-            it('should throw the error if the first validator returns a promise', function () {
-              let called = 0;
-              const dbs = new DatabaseSchema();
-              const myValidator1 = function () {
-                called++;
-                return Promise.resolve(true);
-              };
-              const myValidator2 = function () {
-                called++;
-                return true;
-              };
-              dbs.defineModel({
-                name: 'model',
-                properties: {
-                  foo: {
-                    type: DataType.ANY,
-                    validate: [myValidator1, myValidator2],
-                  },
-                },
-              });
-              const throwable = () =>
-                dbs.getService(ModelDataValidator).validate('model', {
-                  foo: 'test',
-                });
-              expect(throwable).to.throw(
-                'Asynchronous property validators are not supported, ' +
-                  'but the property "foo" of the model "model" has the property ' +
-                  'validator "myValidator1" that returns a Promise.',
-              );
-              expect(called).to.be.eq(1);
-            });
-
-            it('should throw the error if the second validator returns a promise', function () {
-              let called = 0;
-              const dbs = new DatabaseSchema();
-              const myValidator1 = function () {
-                called++;
-                return true;
-              };
-              const myValidator2 = function () {
-                called++;
-                return Promise.resolve(true);
-              };
-              dbs.defineModel({
-                name: 'model',
-                properties: {
-                  foo: {
-                    type: DataType.ANY,
-                    validate: [myValidator1, myValidator2],
-                  },
-                },
-              });
-              const throwable = () =>
-                dbs.getService(ModelDataValidator).validate('model', {
-                  foo: 'test',
-                });
-              expect(throwable).to.throw(
-                'Asynchronous property validators are not supported, ' +
-                  'but the property "foo" of the model "model" has the property ' +
-                  'validator "myValidator2" that returns a Promise.',
-              );
-              expect(called).to.be.eq(2);
-            });
-
-            it('should throw the error for a non-true result from the first validator', function () {
-              const testFn = v => {
-                let called = 0;
-                const dbs = new DatabaseSchema();
-                const myValidator1 = function () {
-                  called++;
-                  return v;
-                };
-                const myValidator2 = function () {
-                  called++;
-                  return true;
-                };
-                dbs.defineModel({
-                  name: 'model',
-                  properties: {
-                    foo: {
-                      type: DataType.ANY,
-                      validate: [myValidator1, myValidator2],
-                    },
-                  },
-                });
-                const throwable = () =>
-                  dbs.getService(ModelDataValidator).validate('model', {
-                    foo: 'test',
-                  });
-                expect(throwable).to.throw(
-                  'The property "foo" of the model "model" has the invalid value "test" ' +
-                    'that caught by the property validator "myValidator1".',
-                );
-                expect(called).to.be.eq(1);
-              };
-              testFn('str');
-              testFn('');
-              testFn(10);
-              testFn(0);
-              testFn(false);
-              testFn(undefined);
-              testFn(null);
-              testFn({});
-              testFn([]);
-              testFn(() => undefined);
-            });
-
-            it('should throw the error for a non-true result from the second validator', function () {
-              const testFn = v => {
-                let called = 0;
-                const dbs = new DatabaseSchema();
-                const myValidator1 = function () {
-                  called++;
-                  return true;
-                };
-                const myValidator2 = function () {
-                  called++;
-                  return v;
-                };
-                dbs.defineModel({
-                  name: 'model',
-                  properties: {
-                    foo: {
-                      type: DataType.ANY,
-                      validate: [myValidator1, myValidator2],
-                    },
-                  },
-                });
-                const throwable = () =>
-                  dbs.getService(ModelDataValidator).validate('model', {
-                    foo: 'test',
-                  });
-                expect(throwable).to.throw(
-                  'The property "foo" of the model "model" has the invalid value "test" ' +
-                    'that caught by the property validator "myValidator2".',
-                );
-                expect(called).to.be.eq(2);
-              };
-              testFn('str');
-              testFn('');
-              testFn(10);
-              testFn(0);
-              testFn(false);
-              testFn(undefined);
-              testFn(null);
-              testFn({});
-              testFn([]);
-              testFn(() => undefined);
-            });
-
-            it('should pass arguments to validators', function () {
-              let called = false;
-              const dbs = new DatabaseSchema();
-              const myValidator1 = function (value, options, context) {
-                expect(value).to.be.eq('test');
-                expect(options).to.be.undefined;
-                expect(context).to.be.eql({
-                  validatorName: 'myValidator1',
-                  modelName: 'model',
-                  propName: 'foo',
-                });
-                called++;
-                return true;
-              };
-              const myValidator2 = function (value, options, context) {
-                expect(value).to.be.eq('test');
-                expect(options).to.be.undefined;
-                expect(context).to.be.eql({
-                  validatorName: 'myValidator2',
-                  modelName: 'model',
-                  propName: 'foo',
-                });
-                called++;
-                return true;
-              };
-              dbs.defineModel({
-                name: 'model',
-                properties: {
-                  foo: {
-                    type: DataType.ANY,
-                    validate: [myValidator1, myValidator2],
-                  },
-                },
-              });
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 'test',
-              });
-              expect(called).to.be.eq(2);
-            });
-
-            it('should invoke validators in the correct order', function () {
-              const invocation = [];
-              const myValidator1 = function () {
-                invocation.push('myValidator1');
-                return true;
-              };
-              const myValidator2 = function () {
-                invocation.push('myValidator2');
-                return true;
-              };
-              const dbs = new DatabaseSchema();
-              dbs.defineModel({
-                name: 'model',
-                properties: {
-                  foo: {
-                    type: DataType.ANY,
-                    validate: [myValidator1, myValidator2],
-                  },
-                },
-              });
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 'test',
-              });
-              expect(invocation).to.be.eql(['myValidator1', 'myValidator2']);
-            });
-          });
-
-          describe('anonymous validators', function () {
-            it('should not validate the non-provided property', function () {
-              let calls = 0;
-              const dbs = new DatabaseSchema();
-              dbs.defineModel({
-                name: 'model',
-                properties: {
-                  foo: {
-                    type: DataType.ANY,
-                    validate: [
-                      () => {
-                        calls++;
-                        throw new Error('Should not to be called.');
-                      },
-                      () => {
-                        calls++;
-                        throw new Error('Should not to be called.');
-                      },
-                    ],
-                  },
-                },
-              });
-              const validator = dbs.getService(ModelDataValidator);
-              validator.validate('model', {});
-              expect(calls).to.be.eq(0);
-            });
-
-            it('should not validate undefined and null values', function () {
-              let calls = 0;
-              const dbs = new DatabaseSchema();
-              dbs.defineModel({
-                name: 'model',
-                properties: {
-                  foo: {
-                    type: DataType.ANY,
-                    validate: [
-                      () => {
-                        calls++;
-                        throw new Error('Should not to be called.');
-                      },
-                      () => {
-                        calls++;
-                        throw new Error('Should not to be called.');
-                      },
-                    ],
-                  },
-                },
-              });
-              const validator = dbs.getService(ModelDataValidator);
-              validator.validate('model', {foo: undefined});
-              validator.validate('model', {foo: null});
-              expect(calls).to.be.eq(0);
-            });
-
-            it('should not validate the empty value', function () {
-              let calls = 0;
-              const dbs = new DatabaseSchema();
-              dbs.defineModel({
-                name: 'model',
-                properties: {
-                  foo: {
-                    type: DataType.STRING,
-                    validate: [
-                      () => {
-                        calls++;
-                        throw new Error('Should not to be called.');
-                      },
-                      () => {
-                        calls++;
-                        throw new Error('Should not to be called.');
-                      },
-                    ],
-                  },
-                },
-              });
-              dbs
-                .getService(EmptyValuesService)
-                .setEmptyValuesOf(DataType.STRING, [5]);
-              dbs.getService(ModelDataValidator).validate('model', {foo: 5});
-              expect(calls).to.be.eq(0);
-            });
-
-            it('should throw the error from the first validator', function () {
-              let called = 0;
-              const dbs = new DatabaseSchema();
-              dbs.defineModel({
-                name: 'model',
-                properties: {
-                  foo: {
-                    type: DataType.ANY,
-                    validate: [
-                      () => {
-                        called++;
-                        throw Error('My error');
-                      },
-                      () => {
-                        called++;
-                        return false;
-                      },
-                    ],
-                  },
-                },
-              });
-              const throwable = () =>
-                dbs.getService(ModelDataValidator).validate('model', {
-                  foo: 'test',
-                });
-              expect(throwable).to.throw('My error');
-              expect(called).to.be.eq(1);
-            });
-
-            it('should throw the error from the second validator', function () {
-              let called = 0;
-              const dbs = new DatabaseSchema();
-              dbs.defineModel({
-                name: 'model',
-                properties: {
-                  foo: {
-                    type: DataType.ANY,
-                    validate: [
-                      () => {
-                        called++;
-                        return true;
-                      },
-                      () => {
-                        called++;
-                        throw Error('My error');
-                      },
-                    ],
-                  },
-                },
-              });
-              const throwable = () =>
-                dbs.getService(ModelDataValidator).validate('model', {
-                  foo: 'test',
-                });
-              expect(throwable).to.throw('My error');
-              expect(called).to.be.eq(2);
-            });
-
-            it('should allow the given value if validators returns true', function () {
-              let called = 0;
-              const dbs = new DatabaseSchema();
-              dbs.defineModel({
-                name: 'model',
-                properties: {
-                  foo: {
-                    type: DataType.ANY,
-                    validate: [
-                      () => {
-                        called++;
-                        return true;
-                      },
-                      () => {
-                        called++;
-                        return true;
-                      },
-                    ],
-                  },
-                },
-              });
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 'test',
-              });
-              expect(called).to.be.eq(2);
-            });
-
-            it('should throw the error if the first validator returns a promise', function () {
-              let called = 0;
-              const dbs = new DatabaseSchema();
-              dbs.defineModel({
-                name: 'model',
-                properties: {
-                  foo: {
-                    type: DataType.ANY,
-                    validate: [
-                      () => {
-                        called++;
-                        return Promise.resolve(true);
-                      },
-                      () => {
-                        called++;
-                        return true;
-                      },
-                    ],
-                  },
-                },
-              });
-              const throwable = () =>
-                dbs.getService(ModelDataValidator).validate('model', {
-                  foo: 'test',
-                });
-              expect(throwable).to.throw(
-                'Asynchronous property validators are not supported, ' +
-                  'but the property "foo" of the model "model" has a property ' +
-                  'validator that returns a Promise.',
-              );
-              expect(called).to.be.eq(1);
-            });
-
-            it('should throw the error if the second validator returns a promise', function () {
-              let called = 0;
-              const dbs = new DatabaseSchema();
-              dbs.defineModel({
-                name: 'model',
-                properties: {
-                  foo: {
-                    type: DataType.ANY,
-                    validate: [
-                      () => {
-                        called++;
-                        return true;
-                      },
-                      () => {
-                        called++;
-                        return Promise.resolve(true);
-                      },
-                    ],
-                  },
-                },
-              });
-              const throwable = () =>
-                dbs.getService(ModelDataValidator).validate('model', {
-                  foo: 'test',
-                });
-              expect(throwable).to.throw(
-                'Asynchronous property validators are not supported, ' +
-                  'but the property "foo" of the model "model" has a property ' +
-                  'validator that returns a Promise.',
-              );
-              expect(called).to.be.eq(2);
-            });
-
-            it('should throw the error for a non-true result from the first validator', function () {
-              const testFn = v => {
-                let called = 0;
-                const dbs = new DatabaseSchema();
-                dbs.defineModel({
-                  name: 'model',
-                  properties: {
-                    foo: {
-                      type: DataType.ANY,
-                      validate: [
-                        () => {
-                          called++;
-                          return v;
-                        },
-                        () => {
-                          called++;
-                          return true;
-                        },
-                      ],
-                    },
-                  },
-                });
-                const throwable = () =>
-                  dbs.getService(ModelDataValidator).validate('model', {
-                    foo: 'test',
-                  });
-                expect(throwable).to.throw(
-                  'The property "foo" of the model "model" has the invalid value "test" ' +
-                    'that caught by a property validator.',
-                );
-                expect(called).to.be.eq(1);
-              };
-              testFn('str');
-              testFn('');
-              testFn(10);
-              testFn(0);
-              testFn(false);
-              testFn(undefined);
-              testFn(null);
-              testFn({});
-              testFn([]);
-              testFn(() => undefined);
-            });
-
-            it('should throw the error for a non-true result from the second validator', function () {
-              const testFn = v => {
-                let called = 0;
-                const dbs = new DatabaseSchema();
-                dbs.defineModel({
-                  name: 'model',
-                  properties: {
-                    foo: {
-                      type: DataType.ANY,
-                      validate: [
-                        () => {
-                          called++;
-                          return true;
-                        },
-                        () => {
-                          called++;
-                          return v;
-                        },
-                      ],
-                    },
-                  },
-                });
-                const throwable = () =>
-                  dbs.getService(ModelDataValidator).validate('model', {
-                    foo: 'test',
-                  });
-                expect(throwable).to.throw(
-                  'The property "foo" of the model "model" has the invalid value "test" ' +
-                    'that caught by a property validator.',
-                );
-                expect(called).to.be.eq(2);
-              };
-              testFn('str');
-              testFn('');
-              testFn(10);
-              testFn(0);
-              testFn(false);
-              testFn(undefined);
-              testFn(null);
-              testFn({});
-              testFn([]);
-              testFn(() => undefined);
-            });
-
-            it('should pass arguments to validators', function () {
-              let called = false;
-              const dbs = new DatabaseSchema();
-              dbs.defineModel({
-                name: 'model',
-                properties: {
-                  foo: {
-                    type: DataType.ANY,
-                    validate: [
-                      (value, options, context) => {
-                        expect(value).to.be.eq('test');
-                        expect(options).to.be.undefined;
-                        expect(context).to.be.eql({
-                          validatorName: undefined,
-                          modelName: 'model',
-                          propName: 'foo',
-                        });
-                        called++;
-                        return true;
-                      },
-                      (value, options, context) => {
-                        expect(value).to.be.eq('test');
-                        expect(options).to.be.undefined;
-                        expect(context).to.be.eql({
-                          validatorName: undefined,
-                          modelName: 'model',
-                          propName: 'foo',
-                        });
-                        called++;
-                        return true;
-                      },
-                    ],
-                  },
-                },
-              });
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 'test',
-              });
-              expect(called).to.be.eq(2);
-            });
-
-            it('should invoke validators in the correct order', function () {
-              const invocation = [];
-              const dbs = new DatabaseSchema();
-              dbs.defineModel({
-                name: 'model',
-                properties: {
-                  foo: {
-                    type: DataType.ANY,
-                    validate: [
-                      () => {
-                        invocation.push('myValidator1');
-                        return true;
-                      },
-                      () => {
-                        invocation.push('myValidator2');
-                        return true;
-                      },
-                    ],
-                  },
-                },
-              });
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 'test',
-              });
-              expect(invocation).to.be.eql(['myValidator1', 'myValidator2']);
-            });
-          });
-        });
-      });
-
-      describe('when the option "validate" is an Object', function () {
-        it('should not validate the non-provided property', function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          const reg = dbs.getService(PropertyValidatorRegistry);
-          reg.addValidator('myValidator1', function () {
-            calls++;
-            throw new Error('Should not to be called.');
-          });
-          reg.addValidator('myValidator2', function () {
-            calls++;
-            throw new Error('Should not to be called.');
-          });
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                validate: {
-                  myValidator1: true,
-                  myValidator2: true,
-                },
-              },
-            },
-          });
-          const validator = dbs.getService(ModelDataValidator);
-          validator.validate('model', {});
-          expect(calls).to.be.eq(0);
-        });
-
-        it('should not validate undefined and null values', function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          const reg = dbs.getService(PropertyValidatorRegistry);
-          reg.addValidator('myValidator1', function () {
-            calls++;
-            throw new Error('Should not to be called.');
-          });
-          reg.addValidator('myValidator2', function () {
-            calls++;
-            throw new Error('Should not to be called.');
-          });
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                validate: {
-                  myValidator1: true,
-                  myValidator2: true,
-                },
-              },
-            },
-          });
-          const validator = dbs.getService(ModelDataValidator);
-          validator.validate('model', {foo: undefined});
-          validator.validate('model', {foo: null});
-          expect(calls).to.be.eq(0);
-        });
-
-        it('should not validate the empty value', function () {
-          let calls = 0;
-          const dbs = new DatabaseSchema();
-          const reg = dbs.getService(PropertyValidatorRegistry);
-          reg.addValidator('myValidator1', function () {
-            calls++;
-            throw new Error('Should not to be called.');
-          });
-          reg.addValidator('myValidator2', function () {
-            calls++;
-            throw new Error('Should not to be called.');
-          });
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.STRING,
-                validate: {
-                  myValidator1: true,
-                  myValidator2: true,
-                },
-              },
-            },
-          });
-          dbs
-            .getService(EmptyValuesService)
-            .setEmptyValuesOf(DataType.STRING, [5]);
-          dbs.getService(ModelDataValidator).validate('model', {foo: 5});
-          expect(calls).to.be.eq(0);
-        });
-
-        it('should throw the error for the non-existent validator name', function () {
-          let called = 0;
-          const dbs = new DatabaseSchema();
-          const reg = dbs.getService(PropertyValidatorRegistry);
-          reg.addValidator('myValidator1', function () {
-            called++;
-            return true;
-          });
-          const modelDef = {
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                validate: {
-                  myValidator1: true,
-                },
-              },
-            },
-          };
-          dbs.defineModel(modelDef);
-          modelDef.properties.foo.validate['myValidator2'] = true;
-          const throwable = () =>
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: 'test',
-            });
-          expect(throwable).to.throw(
-            'The property validator "myValidator2" is not defined.',
-          );
-          expect(called).to.be.eq(1);
-        });
-
-        it('should throw the error from the first validator', function () {
-          let called = 0;
-          const dbs = new DatabaseSchema();
-          const reg = dbs.getService(PropertyValidatorRegistry);
-          reg.addValidator('myValidator1', function () {
-            called++;
-            throw Error('My error');
-          });
-          reg.addValidator('myValidator2', function () {
-            called++;
-            return false;
-          });
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                validate: {
-                  myValidator1: true,
-                  myValidator2: true,
-                },
-              },
-            },
-          });
-          const throwable = () =>
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: 'test',
-            });
-          expect(throwable).to.throw('My error');
-          expect(called).to.be.eq(1);
-        });
-
-        it('should throw the error from the second validator', function () {
-          let called = 0;
-          const dbs = new DatabaseSchema();
-          const reg = dbs.getService(PropertyValidatorRegistry);
-          reg.addValidator('myValidator1', function () {
-            called++;
-            return true;
-          });
-          reg.addValidator('myValidator2', function () {
-            called++;
-            throw Error('My error');
-          });
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                validate: {
-                  myValidator1: true,
-                  myValidator2: true,
-                },
-              },
-            },
-          });
-          const throwable = () =>
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: 'test',
-            });
-          expect(throwable).to.throw('My error');
-          expect(called).to.be.eq(2);
-        });
-
-        it('should allow the given value if validators returns true', function () {
-          let called = 0;
-          const dbs = new DatabaseSchema();
-          const reg = dbs.getService(PropertyValidatorRegistry);
-          reg.addValidator('myValidator1', function () {
-            called++;
-            return true;
-          });
-          reg.addValidator('myValidator2', function () {
-            called++;
-            return true;
-          });
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                validate: {
-                  myValidator1: true,
-                  myValidator2: true,
-                },
-              },
-            },
-          });
-          dbs.getService(ModelDataValidator).validate('model', {
-            foo: 'test',
-          });
-          expect(called).to.be.eq(2);
-        });
-
-        it('should throw the error if the first validator returns a promise', function () {
-          let called = 0;
-          const dbs = new DatabaseSchema();
-          const reg = dbs.getService(PropertyValidatorRegistry);
-          reg.addValidator('myValidator1', function () {
-            called++;
-            return Promise.resolve(true);
-          });
-          reg.addValidator('myValidator2', function () {
-            called++;
-            return true;
-          });
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                validate: {
-                  myValidator1: true,
-                  myValidator2: true,
-                },
-              },
-            },
-          });
-          const throwable = () =>
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: 'test',
-            });
-          expect(throwable).to.throw(
-            'Asynchronous property validators are not supported, ' +
-              'but the property "foo" of the model "model" has the property ' +
-              'validator "myValidator1" that returns a Promise.',
-          );
-          expect(called).to.be.eq(1);
-        });
-
-        it('should throw the error if the second validator returns a promise', function () {
-          let called = 0;
-          const dbs = new DatabaseSchema();
-          const reg = dbs.getService(PropertyValidatorRegistry);
-          reg.addValidator('myValidator1', function () {
-            called++;
-            return true;
-          });
-          reg.addValidator('myValidator2', function () {
-            called++;
-            return Promise.resolve(true);
-          });
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                validate: {
-                  myValidator1: true,
-                  myValidator2: true,
-                },
-              },
-            },
-          });
-          const throwable = () =>
-            dbs.getService(ModelDataValidator).validate('model', {
-              foo: 'test',
-            });
-          expect(throwable).to.throw(
-            'Asynchronous property validators are not supported, ' +
-              'but the property "foo" of the model "model" has the property ' +
-              'validator "myValidator2" that returns a Promise.',
-          );
-          expect(called).to.be.eq(2);
-        });
-
-        it('should throw the error for a non-true result from the first validator', function () {
-          const testFn = v => {
-            let called = 0;
-            const dbs = new DatabaseSchema();
-            const reg = dbs.getService(PropertyValidatorRegistry);
-            reg.addValidator('myValidator1', function () {
-              called++;
-              return v;
-            });
-            reg.addValidator('myValidator2', function () {
-              called++;
-              return true;
-            });
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  validate: {
-                    myValidator1: true,
-                    myValidator2: true,
-                  },
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 'test',
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" has the invalid value "test" ' +
-                'that caught by the property validator "myValidator1".',
-            );
-            expect(called).to.be.eq(1);
-          };
-          testFn('str');
-          testFn('');
-          testFn(10);
-          testFn(0);
-          testFn(false);
-          testFn(undefined);
-          testFn(null);
-          testFn({});
-          testFn([]);
-          testFn(() => undefined);
-        });
-
-        it('should throw the error for a non-true result from the second validator', function () {
-          const testFn = v => {
-            let called = 0;
-            const dbs = new DatabaseSchema();
-            const reg = dbs.getService(PropertyValidatorRegistry);
-            reg.addValidator('myValidator1', function () {
-              called++;
-              return true;
-            });
-            reg.addValidator('myValidator2', function () {
-              called++;
-              return v;
-            });
-            dbs.defineModel({
-              name: 'model',
-              properties: {
-                foo: {
-                  type: DataType.ANY,
-                  validate: {
-                    myValidator1: true,
-                    myValidator2: true,
-                  },
-                },
-              },
-            });
-            const throwable = () =>
-              dbs.getService(ModelDataValidator).validate('model', {
-                foo: 'test',
-              });
-            expect(throwable).to.throw(
-              'The property "foo" of the model "model" has the invalid value "test" ' +
-                'that caught by the property validator "myValidator2".',
-            );
-            expect(called).to.be.eq(2);
-          };
-          testFn('str');
-          testFn('');
-          testFn(10);
-          testFn(0);
-          testFn(false);
-          testFn(undefined);
-          testFn(null);
-          testFn({});
-          testFn([]);
-          testFn(() => undefined);
-        });
-
-        it('should pass arguments to validators', function () {
-          let called = false;
-          const dbs = new DatabaseSchema();
-          const reg = dbs.getService(PropertyValidatorRegistry);
-          reg.addValidator('myValidator1', function (value, options, context) {
-            expect(value).to.be.eq('test');
-            expect(options).to.be.eq('foo');
-            expect(context).to.be.eql({
-              validatorName: 'myValidator1',
-              modelName: 'model',
-              propName: 'foo',
-            });
-            called++;
-            return true;
-          });
-          reg.addValidator('myValidator2', function (value, options, context) {
-            expect(value).to.be.eq('test');
-            expect(options).to.be.eq('bar');
-            expect(context).to.be.eql({
-              validatorName: 'myValidator2',
-              modelName: 'model',
-              propName: 'foo',
-            });
-            called++;
-            return true;
-          });
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                validate: {
-                  myValidator1: 'foo',
-                  myValidator2: 'bar',
-                },
-              },
-            },
-          });
-          dbs.getService(ModelDataValidator).validate('model', {
-            foo: 'test',
-          });
-          expect(called).to.be.eq(2);
-        });
-
-        it('should invoke validators in the correct order', function () {
-          const invocation = [];
-          const dbs = new DatabaseSchema();
-          const reg = dbs.getService(PropertyValidatorRegistry);
-          reg.addValidator('myValidator1', function () {
-            invocation.push('myValidator1');
-            return true;
-          });
-          reg.addValidator('myValidator2', function () {
-            invocation.push('myValidator2');
-            return true;
-          });
-          dbs.defineModel({
-            name: 'model',
-            properties: {
-              foo: {
-                type: DataType.ANY,
-                validate: {
-                  myValidator1: true,
-                  myValidator2: true,
-                },
-              },
-            },
-          });
-          dbs.getService(ModelDataValidator).validate('model', {
-            foo: 'test',
-          });
-          expect(invocation).to.be.eql(['myValidator1', 'myValidator2']);
-        });
-      });
-    });
-  });
-});

+ 0 - 2
src/definition/model/properties/index.d.ts

@@ -1,8 +1,6 @@
 export * from './data-type.js';
 export * from './property-definition.js';
 export * from './property-uniqueness.js';
-export * from './property-validator/index.js';
-export * from './property-transformer/index.js';
 export * from './property-uniqueness-validator.js';
 export * from './properties-definition-validator.js';
 export * from './primary-keys-definition-validator.js';

+ 0 - 2
src/definition/model/properties/index.js

@@ -1,8 +1,6 @@
 export * from './data-type.js';
 export * from './property-definition.js';
 export * from './property-uniqueness.js';
-export * from './property-validator/index.js';
-export * from './property-transformer/index.js';
 export * from './property-uniqueness-validator.js';
 export * from './properties-definition-validator.js';
 export * from './primary-keys-definition-validator.js';

+ 0 - 169
src/definition/model/properties/properties-definition-validator.js

@@ -3,8 +3,6 @@ import {DataType as Type} from './data-type.js';
 import {capitalize} from '../../../utils/index.js';
 import {PropertyUniqueness} from './property-uniqueness.js';
 import {InvalidArgumentError} from '../../../errors/index.js';
-import {PropertyValidatorRegistry} from './property-validator/index.js';
-import {PropertyTransformerRegistry} from './property-transformer/index.js';
 import {PrimaryKeysDefinitionValidator} from './primary-keys-definition-validator.js';
 
 /**
@@ -228,173 +226,6 @@ export class PropertiesDefinitionValidator extends Service {
         propName,
         modelName,
       );
-    // если определена опция "validate", то проверяется значение
-    // опции, которое может являться строкой, массивом или объектом
-    if (propDef.validate != null) {
-      const propertyValidatorRegistry = this.getService(
-        PropertyValidatorRegistry,
-      );
-      // если опция "validate" содержит строку, то проверяется
-      // наличие зарегистрированного валидатора по названию
-      if (propDef.validate && typeof propDef.validate === 'string') {
-        // если название валидатора не зарегистрировано,
-        // то выбрасывается ошибка
-        if (!propertyValidatorRegistry.hasValidator(propDef.validate))
-          throw new InvalidArgumentError(
-            'The property validator %v is not found.',
-            propDef.validate,
-          );
-      }
-      // если опция "validate" содержит функцию, то данная функция
-      // воспринимается как пользовательский валидатор
-      else if (propDef.validate && typeof propDef.validate === 'function') {
-        // (допустимо)
-      }
-      // если опция "validate" содержит массив, то проверяется
-      // каждый элемент массива
-      else if (Array.isArray(propDef.validate)) {
-        for (const validatorOrName of propDef.validate) {
-          // если элемент массива является строкой, то проверяется
-          // наличие зарегистрированного валидатора по названию
-          if (validatorOrName && typeof validatorOrName === 'string') {
-            if (!propertyValidatorRegistry.hasValidator(validatorOrName))
-              throw new InvalidArgumentError(
-                'The property validator %v is not found.',
-                validatorOrName,
-              );
-          }
-          // если элемент массива является функцией, то данная функция
-          // воспринимается как пользовательский валидатор
-          else if (validatorOrName && typeof validatorOrName === 'function') {
-            // (допустимо)
-          }
-          // если элемент массива не является названием зарегистрированного
-          // валидатора или функцией-валидатором, то выбрасывается ошибка
-          else {
-            throw new InvalidArgumentError(
-              'The provided option "validate" for the property %v in the model %v ' +
-                'has an Array value that should contain validator names or validator ' +
-                'functions, but %v was given.',
-              propName,
-              modelName,
-              validatorOrName,
-            );
-          }
-        }
-      }
-      // если опция "validate" содержит объект, то проверяются ключи данного
-      // объекта, которые должны являться названиями зарегистрированных
-      // валидаторов, а значения их аргументами
-      else if (typeof propDef.validate === 'object') {
-        Object.keys(propDef.validate).forEach(validatorName => {
-          // если ключ объекта не является названием зарегистрированного
-          // валидатора, то выбрасывается ошибка
-          if (!propertyValidatorRegistry.hasValidator(validatorName))
-            throw new InvalidArgumentError(
-              'The property validator %v is not found.',
-              validatorName,
-            );
-        });
-      }
-      // если опция "validate" не является не пустой строкой, функцией,
-      // массивом и объектом, то выбрасывается ошибка
-      else {
-        throw new InvalidArgumentError(
-          'The provided option "validate" for the property %v in the model %v ' +
-            'should be either a validator name, a validator function, an array ' +
-            'of validator names or functions, or an object mapping validator ' +
-            'names to their arguments, but %v was given.',
-          propName,
-          modelName,
-          propDef.validate,
-        );
-      }
-    }
-    // если определена опция "transform", то проверяется значение
-    // опции, которое может являться строкой, массивом или объектом
-    if (propDef.transform != null) {
-      const propertyTransformerRegistry = this.getService(
-        PropertyTransformerRegistry,
-      );
-      // если опция "transform" содержит строку, то проверяется
-      // наличие зарегистрированного трансформера по названию
-      if (propDef.transform && typeof propDef.transform === 'string') {
-        // если название трансформера не зарегистрировано,
-        // то выбрасывается ошибка
-        if (!propertyTransformerRegistry.hasTransformer(propDef.transform))
-          throw new InvalidArgumentError(
-            'The property transformer %v is not found.',
-            propDef.transform,
-          );
-      }
-      // если опция "transform" содержит функцию, то данная функция
-      // воспринимается как пользовательский трансформер
-      else if (propDef.transform && typeof propDef.transform === 'function') {
-        // (допустимо)
-      }
-      // если опция "transform" содержит массив, то проверяется
-      // каждый элемент массива
-      else if (Array.isArray(propDef.transform)) {
-        for (const transformerOrName of propDef.transform) {
-          // если элемент массива является строкой, то проверяется
-          // наличие зарегистрированного трансформера по названию
-          if (transformerOrName && typeof transformerOrName === 'string') {
-            if (!propertyTransformerRegistry.hasTransformer(transformerOrName))
-              throw new InvalidArgumentError(
-                'The property transformer %v is not found.',
-                transformerOrName,
-              );
-          }
-          // если элемент массива является функцией, то данная функция
-          // воспринимается как пользовательский трансформер
-          else if (
-            transformerOrName &&
-            typeof transformerOrName === 'function'
-          ) {
-            // (допустимо)
-          }
-          // если элемент массива не является названием зарегистрированного
-          // трансформера или функцией-трансформером, то выбрасывается ошибка
-          else {
-            throw new InvalidArgumentError(
-              'The provided option "transform" for the property %v in the model %v ' +
-                'has an Array value that should contain transformer names or transformer ' +
-                'functions, but %v was given.',
-              propName,
-              modelName,
-              transformerOrName,
-            );
-          }
-        }
-      }
-      // если опция "transform" содержит объект, то проверяются ключи данного
-      // объекта, которые должны являться названиями зарегистрированных
-      // трансформеров, а значения их аргументами
-      else if (typeof propDef.transform === 'object') {
-        Object.keys(propDef.transform).forEach(transformerName => {
-          // если ключ объекта не является названием зарегистрированного
-          // валидатора, то выбрасывается ошибка
-          if (!propertyTransformerRegistry.hasTransformer(transformerName))
-            throw new InvalidArgumentError(
-              'The property transformer %v is not found.',
-              transformerName,
-            );
-        });
-      }
-      // если опция "transform" не является не пустой строкой, функцией,
-      // массивом и объектом, то выбрасывается ошибка
-      else {
-        throw new InvalidArgumentError(
-          'The provided option "transform" for the property %v in the model %v ' +
-            'should be either a transformer name, a transformer function, an array ' +
-            'of transformer names or functions, or an object mapping transformer ' +
-            'names to their arguments, but %v was given.',
-          propName,
-          modelName,
-          propDef.transform,
-        );
-      }
-    }
     if (propDef.unique) {
       if (
         typeof propDef.unique !== 'boolean' &&

+ 0 - 162
src/definition/model/properties/properties-definition-validator.spec.js

@@ -3,20 +3,12 @@ import {chai} from '../../../chai.js';
 import {DataType} from './data-type.js';
 import {format} from '@e22m4u/js-format';
 import {PropertyUniqueness} from './property-uniqueness.js';
-import {PropertyValidatorRegistry} from './property-validator/index.js';
-import {PropertyTransformerRegistry} from './property-transformer/index.js';
 import {PropertiesDefinitionValidator} from './properties-definition-validator.js';
 import {PrimaryKeysDefinitionValidator} from './primary-keys-definition-validator.js';
 
 const S = new PropertiesDefinitionValidator();
 const sandbox = chai.spy.sandbox();
 
-S.getService(PropertyValidatorRegistry).addValidator('myValidator', () => true);
-S.getService(PropertyTransformerRegistry).addTransformer(
-  'myTransformer',
-  () => true,
-);
-
 describe('PropertiesDefinitionValidator', function () {
   afterEach(function () {
     sandbox.restore();
@@ -426,160 +418,6 @@ describe('PropertiesDefinitionValidator', function () {
       expect(V.validate).to.have.been.called.with.exactly('model', propDefs);
     });
 
-    it('the option "validate" should have a non-empty String, a Function, an Array or an Object', function () {
-      const validate = v => () => {
-        const foo = {
-          type: DataType.ANY,
-          validate: v,
-        };
-        S.validate('model', {foo});
-      };
-      const error = v =>
-        format(
-          'The provided option "validate" for the property "foo" in the model "model" ' +
-            'should be either a validator name, a validator function, an array ' +
-            'of validator names or functions, or an object mapping validator ' +
-            'names to their arguments, but %s was given.',
-          v,
-        );
-      expect(validate('')).to.throw(error('""'));
-      expect(validate(10)).to.throw(error('10'));
-      expect(validate(0)).to.throw(error('0'));
-      expect(validate(true)).to.throw(error('true'));
-      expect(validate(false)).to.throw(error('false'));
-      validate('myValidator')();
-      validate(() => true)();
-      validate(['myValidator'])();
-      validate([() => true])();
-      validate([])();
-      validate({myValidator: true})();
-      validate({})();
-      validate(null)();
-      validate(undefined)();
-    });
-
-    it('the option "validate" with an Array value requires elements to be a non-empty String or a Function', function () {
-      const validate = v => () => {
-        const foo = {
-          type: DataType.ANY,
-          validate: [v],
-        };
-        S.validate('model', {foo});
-      };
-      const error = v =>
-        format(
-          'The provided option "validate" for the property "foo" in the model "model" ' +
-            'has an Array value that should contain validator names or validator functions, ' +
-            'but %s was given.',
-          v,
-        );
-      expect(validate('')).to.throw(error('""'));
-      expect(validate(10)).to.throw(error('10'));
-      expect(validate(0)).to.throw(error('0'));
-      expect(validate(true)).to.throw(error('true'));
-      expect(validate(false)).to.throw(error('false'));
-      expect(validate([1, 2, 3])).to.throw(error('Array'));
-      expect(validate({foo: 'bar'})).to.throw(error('Object'));
-      expect(validate(null)).to.throw(error('null'));
-      expect(validate(undefined)).to.throw(error('undefined'));
-      validate('myValidator')();
-      validate(() => true)();
-    });
-
-    it('the option "validate" requires only existing validator names', function () {
-      const validate = v => () => {
-        const foo = {
-          type: DataType.ANY,
-          validate: v,
-        };
-        S.validate('model', {foo});
-      };
-      const error = v => format('The property validator %s is not found.', v);
-      expect(validate('unknown')).to.throw(error('"unknown"'));
-      expect(validate({unknown: true})).to.throw(error('"unknown"'));
-      expect(validate(['unknown'])).to.throw(error('"unknown"'));
-      validate('myValidator')();
-      validate(['myValidator'])();
-      validate({myValidator: true})();
-    });
-
-    it('the option "transform" should have a non-empty String, a Function, an Array or an Object', function () {
-      const validate = v => () => {
-        const foo = {
-          type: DataType.ANY,
-          transform: v,
-        };
-        S.validate('model', {foo});
-      };
-      const error = v =>
-        format(
-          'The provided option "transform" for the property "foo" in the model "model" ' +
-            'should be either a transformer name, a transformer function, an array ' +
-            'of transformer names or functions, or an object mapping transformer ' +
-            'names to their arguments, but %s was given.',
-          v,
-        );
-      expect(validate('')).to.throw(error('""'));
-      expect(validate(10)).to.throw(error('10'));
-      expect(validate(0)).to.throw(error('0'));
-      expect(validate(true)).to.throw(error('true'));
-      expect(validate(false)).to.throw(error('false'));
-      validate('myTransformer')();
-      validate(v => v)();
-      validate(['myTransformer'])();
-      validate([v => v])();
-      validate([])();
-      validate({myTransformer: true})();
-      validate({})();
-      validate(null)();
-      validate(undefined)();
-    });
-
-    it('the option "transform" with an Array value requires elements to be a non-empty String or a Function', function () {
-      const validate = v => () => {
-        const foo = {
-          type: DataType.ANY,
-          transform: [v],
-        };
-        S.validate('model', {foo});
-      };
-      const error = v =>
-        format(
-          'The provided option "transform" for the property "foo" in the model "model" ' +
-            'has an Array value that should contain transformer names or transformer functions, ' +
-            'but %s was given.',
-          v,
-        );
-      expect(validate('')).to.throw(error('""'));
-      expect(validate(10)).to.throw(error('10'));
-      expect(validate(0)).to.throw(error('0'));
-      expect(validate(true)).to.throw(error('true'));
-      expect(validate(false)).to.throw(error('false'));
-      expect(validate([1, 2, 3])).to.throw(error('Array'));
-      expect(validate({foo: 'bar'})).to.throw(error('Object'));
-      expect(validate(null)).to.throw(error('null'));
-      expect(validate(undefined)).to.throw(error('undefined'));
-      validate('myTransformer')();
-      validate(v => v)();
-    });
-
-    it('the option "transform" requires only existing transformer names', function () {
-      const validate = v => () => {
-        const foo = {
-          type: DataType.ANY,
-          transform: v,
-        };
-        S.validate('model', {foo});
-      };
-      const error = v => format('The property transformer %s is not found.', v);
-      expect(validate('unknown')).to.throw(error('"unknown"'));
-      expect(validate({unknown: true})).to.throw(error('"unknown"'));
-      expect(validate(['unknown'])).to.throw(error('"unknown"'));
-      validate('myTransformer')();
-      validate(['myTransformer'])();
-      validate({myTransformer: true})();
-    });
-
     it('expects the provided option "unique" to be a Boolean or the PropertyUniqueness', function () {
       const validate = v => {
         const foo = {

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

@@ -1,7 +1,5 @@
 import {DataType} from './data-type.js';
 import {PropertyUniqueness} from './property-uniqueness.js';
-import {PropertyValidateOptions} from './property-validator/index.js';
-import {PropertyTransformOptions} from './property-transformer/index.js';
 
 /**
  * Full property definition.
@@ -16,8 +14,6 @@ export declare type FullPropertyDefinition = {
   columnType?: string;
   required?: boolean;
   default?: unknown;
-  validate?: PropertyValidateOptions;
-  transform?: PropertyTransformOptions;
   unique?: boolean | PropertyUniqueness;
 };
 

+ 0 - 3
src/definition/model/properties/property-transformer/builtin/index.d.ts

@@ -1,3 +0,0 @@
-export * from './trim-transformer.js';
-export * from './to-lower-case-transformer.js';
-export * from './to-upper-case-transformer.js';

+ 0 - 3
src/definition/model/properties/property-transformer/builtin/index.js

@@ -1,3 +0,0 @@
-export * from './trim-transformer.js';
-export * from './to-lower-case-transformer.js';
-export * from './to-upper-case-transformer.js';

+ 0 - 6
src/definition/model/properties/property-transformer/builtin/to-lower-case-transformer.d.ts

@@ -1,6 +0,0 @@
-import {PropertyTransformer} from '../property-transformer.js';
-
-/**
- * To lower case transformer.
- */
-export const toLowerCaseTransformer: PropertyTransformer;

+ 0 - 19
src/definition/model/properties/property-transformer/builtin/to-lower-case-transformer.js

@@ -1,19 +0,0 @@
-import {InvalidArgumentError} from '../../../../../errors/index.js';
-
-/**
- * To lower case transformer.
- *
- * @param {*} value
- * @param {undefined} options
- * @param {object} context
- * @returns {string|undefined|null}
- */
-export function toLowerCaseTransformer(value, options, context) {
-  if (value == null) return value;
-  if (typeof value === 'string') return value.toLowerCase();
-  throw new InvalidArgumentError(
-    'The property transformer %v requires a String value, but %v was given.',
-    context.transformerName,
-    value,
-  );
-}

+ 0 - 39
src/definition/model/properties/property-transformer/builtin/to-lower-case-transformer.spec.js

@@ -1,39 +0,0 @@
-import {expect} from 'chai';
-import {format} from '@e22m4u/js-format';
-import {toLowerCaseTransformer} from './to-lower-case-transformer.js';
-
-describe('toLowerCaseTransformer', function () {
-  it('returns undefined and null values as is', function () {
-    const res1 = toLowerCaseTransformer(undefined, undefined, {});
-    const res2 = toLowerCaseTransformer(null, undefined, {});
-    expect(res1).to.be.undefined;
-    expect(res2).to.be.null;
-  });
-
-  it('converts the given string to lower case', function () {
-    const res = toLowerCaseTransformer('TEST', undefined, {});
-    expect(res).to.be.eq('test');
-  });
-
-  it('throws an error if the given value is not a string', function () {
-    const throwable = v => () =>
-      toLowerCaseTransformer(v, undefined, {
-        transformerName: 'toLowerCase',
-      });
-    const error = v =>
-      format(
-        'The property transformer "toLowerCase" requires a String value, but %s was given.',
-        v,
-      );
-    expect(throwable(10)).to.throw(error('10'));
-    expect(throwable(0)).to.throw(error('0'));
-    expect(throwable(true)).to.throw(error('true'));
-    expect(throwable(false)).to.throw(error('false'));
-    expect(throwable({})).to.throw(error('Object'));
-    expect(throwable([])).to.throw(error('Array'));
-    throwable('str')();
-    throwable('')();
-    throwable(undefined)();
-    throwable(null)();
-  });
-});

+ 0 - 6
src/definition/model/properties/property-transformer/builtin/to-upper-case-transformer.d.ts

@@ -1,6 +0,0 @@
-import {PropertyTransformer} from '../property-transformer.js';
-
-/**
- * To upper case transformer.
- */
-export const toUpperCaseTransformer: PropertyTransformer;

+ 0 - 19
src/definition/model/properties/property-transformer/builtin/to-upper-case-transformer.js

@@ -1,19 +0,0 @@
-import {InvalidArgumentError} from '../../../../../errors/index.js';
-
-/**
- * To upper case transformer.
- *
- * @param {*} value
- * @param {undefined} options
- * @param {object} context
- * @returns {string|undefined|null}
- */
-export function toUpperCaseTransformer(value, options, context) {
-  if (value == null) return value;
-  if (typeof value === 'string') return value.toUpperCase();
-  throw new InvalidArgumentError(
-    'The property transformer %v requires a String value, but %v was given.',
-    context.transformerName,
-    value,
-  );
-}

+ 0 - 39
src/definition/model/properties/property-transformer/builtin/to-upper-case-transformer.spec.js

@@ -1,39 +0,0 @@
-import {expect} from 'chai';
-import {format} from '@e22m4u/js-format';
-import {toUpperCaseTransformer} from './to-upper-case-transformer.js';
-
-describe('toUpperCaseTransformer', function () {
-  it('returns undefined and null values as is', function () {
-    const res1 = toUpperCaseTransformer(undefined, undefined, {});
-    const res2 = toUpperCaseTransformer(null, undefined, {});
-    expect(res1).to.be.undefined;
-    expect(res2).to.be.null;
-  });
-
-  it('converts the given string to upper case', function () {
-    const res = toUpperCaseTransformer('test', undefined, {});
-    expect(res).to.be.eq('TEST');
-  });
-
-  it('throws an error if the given value is not a string', function () {
-    const throwable = v => () =>
-      toUpperCaseTransformer(v, undefined, {
-        transformerName: 'toUpperCase',
-      });
-    const error = v =>
-      format(
-        'The property transformer "toUpperCase" requires a String value, but %s was given.',
-        v,
-      );
-    expect(throwable(10)).to.throw(error('10'));
-    expect(throwable(0)).to.throw(error('0'));
-    expect(throwable(true)).to.throw(error('true'));
-    expect(throwable(false)).to.throw(error('false'));
-    expect(throwable({})).to.throw(error('Object'));
-    expect(throwable([])).to.throw(error('Array'));
-    throwable('str')();
-    throwable('')();
-    throwable(undefined)();
-    throwable(null)();
-  });
-});

+ 0 - 6
src/definition/model/properties/property-transformer/builtin/trim-transformer.d.ts

@@ -1,6 +0,0 @@
-import {PropertyTransformer} from '../property-transformer.js';
-
-/**
- * Trim transformer.
- */
-export declare type trimTransformer = PropertyTransformer;

+ 0 - 19
src/definition/model/properties/property-transformer/builtin/trim-transformer.js

@@ -1,19 +0,0 @@
-import {InvalidArgumentError} from '../../../../../errors/index.js';
-
-/**
- * Trim transformer.
- *
- * @param {*} value
- * @param {undefined} options
- * @param {object} context
- * @returns {string|undefined|null}
- */
-export function trimTransformer(value, options, context) {
-  if (value == null) return value;
-  if (typeof value === 'string') return value.trim();
-  throw new InvalidArgumentError(
-    'The property transformer %v requires a String value, but %v was given.',
-    context.transformerName,
-    value,
-  );
-}

+ 0 - 39
src/definition/model/properties/property-transformer/builtin/trim-transformer.spec.js

@@ -1,39 +0,0 @@
-import {expect} from 'chai';
-import {format} from '@e22m4u/js-format';
-import {trimTransformer} from './trim-transformer.js';
-
-describe('trimTransformer', function () {
-  it('returns undefined and null values as is', function () {
-    const res1 = trimTransformer(undefined, undefined, {});
-    const res2 = trimTransformer(null, undefined, {});
-    expect(res1).to.be.undefined;
-    expect(res2).to.be.null;
-  });
-
-  it('trims the given string', function () {
-    const res = trimTransformer(' test ', undefined, {});
-    expect(res).to.be.eq('test');
-  });
-
-  it('throws an error if the given value is not a string', function () {
-    const throwable = v => () =>
-      trimTransformer(v, undefined, {
-        transformerName: 'trim',
-      });
-    const error = v =>
-      format(
-        'The property transformer "trim" requires a String value, but %s was given.',
-        v,
-      );
-    expect(throwable(10)).to.throw(error('10'));
-    expect(throwable(0)).to.throw(error('0'));
-    expect(throwable(true)).to.throw(error('true'));
-    expect(throwable(false)).to.throw(error('false'));
-    expect(throwable({})).to.throw(error('Object'));
-    expect(throwable([])).to.throw(error('Array'));
-    throwable('str')();
-    throwable('')();
-    throwable(undefined)();
-    throwable(null)();
-  });
-});

+ 0 - 2
src/definition/model/properties/property-transformer/index.d.ts

@@ -1,2 +0,0 @@
-export * from './property-transformer.js';
-export * from './property-transformer-registry.js';

+ 0 - 2
src/definition/model/properties/property-transformer/index.js

@@ -1,2 +0,0 @@
-export * from './property-transformer.js';
-export * from './property-transformer-registry.js';

+ 0 - 29
src/definition/model/properties/property-transformer/property-transformer-registry.d.ts

@@ -1,29 +0,0 @@
-import {Service} from '@e22m4u/js-service';
-import {PropertyTransformer} from './property-transformer.js';
-
-/**
- * Property transformer registry.
- */
-export declare class PropertyTransformerRegistry extends Service {
-  /**
-   * Add transformer.
-   *
-   * @param name
-   * @param transformer
-   */
-  addTransformer(name: string, transformer: PropertyTransformer): this;
-
-  /**
-   * Has transformer.
-   *
-   * @param name
-   */
-  hasTransformer(name: string): boolean;
-
-  /**
-   * Get transformer.
-   *
-   * @param name
-   */
-  getTransformer(name: string): PropertyTransformer;
-}

+ 0 - 76
src/definition/model/properties/property-transformer/property-transformer-registry.js

@@ -1,76 +0,0 @@
-import {Service} from '@e22m4u/js-service';
-import {trimTransformer} from './builtin/index.js';
-import {toUpperCaseTransformer} from './builtin/index.js';
-import {toLowerCaseTransformer} from './builtin/index.js';
-import {InvalidArgumentError} from '../../../../errors/index.js';
-
-/**
- * Property transformer registry.
- */
-export class PropertyTransformerRegistry extends Service {
-  /**
-   * Transformers.
-   *
-   * @type {object}
-   */
-  _transformers = {
-    trim: trimTransformer,
-    toUpperCase: toUpperCaseTransformer,
-    toLowerCase: toLowerCaseTransformer,
-  };
-
-  /**
-   * Add transformer.
-   *
-   * @param {string} name
-   * @param {Function} transformer
-   * @returns {PropertyTransformerRegistry}
-   */
-  addTransformer(name, transformer) {
-    if (!name || typeof name !== 'string')
-      throw new InvalidArgumentError(
-        'A name of the property transformer must ' +
-          'be a non-empty String, but %v was given.',
-        name,
-      );
-    if (name in this._transformers)
-      throw new InvalidArgumentError(
-        'The property transformer %v is already defined.',
-        name,
-      );
-    if (typeof transformer !== 'function')
-      throw new InvalidArgumentError(
-        'The property transformer %v must be a Function, but %v was given.',
-        name,
-        transformer,
-      );
-    this._transformers[name] = transformer;
-    return this;
-  }
-
-  /**
-   * Has transformer.
-   *
-   * @param {string} name
-   * @returns {boolean}
-   */
-  hasTransformer(name) {
-    return Boolean(this._transformers[name]);
-  }
-
-  /**
-   * Get transformer.
-   *
-   * @param {string} name
-   * @returns {Function}
-   */
-  getTransformer(name) {
-    const transformer = this._transformers[name];
-    if (!transformer)
-      throw new InvalidArgumentError(
-        'The property transformer %v is not defined.',
-        name,
-      );
-    return transformer;
-  }
-}

+ 0 - 133
src/definition/model/properties/property-transformer/property-transformer-registry.spec.js

@@ -1,133 +0,0 @@
-import {expect} from 'chai';
-import {format} from '@e22m4u/js-format';
-import {trimTransformer} from './builtin/index.js';
-import {toUpperCaseTransformer} from './builtin/index.js';
-import {toLowerCaseTransformer} from './builtin/index.js';
-import {PropertyTransformerRegistry} from './property-transformer-registry.js';
-
-describe('PropertyTransformerRegistry', function () {
-  describe('addTransformer', function () {
-    it('has builtin transformers', function () {
-      const ptr = new PropertyTransformerRegistry();
-      expect(ptr['_transformers']).to.be.eql({
-        trim: trimTransformer,
-        toUpperCase: toUpperCaseTransformer,
-        toLowerCase: toLowerCaseTransformer,
-      });
-    });
-
-    it('adds a given transformer with the name', function () {
-      const ptr = new PropertyTransformerRegistry();
-      const myTransformer = () => undefined;
-      const res = ptr.addTransformer('myTransformer', myTransformer);
-      expect(res).to.be.eq(ptr);
-      expect(ptr['_transformers']['myTransformer']).to.be.eq(myTransformer);
-    });
-
-    it('requires the given name to be a non-empty string', function () {
-      const ptr = new PropertyTransformerRegistry();
-      const throwable = v => () => ptr.addTransformer(v, () => undefined);
-      const error = v =>
-        format(
-          'A name of the property transformer must ' +
-            'be a non-empty String, but %s was given.',
-          v,
-        );
-      expect(throwable('')).to.throw(error('""'));
-      expect(throwable(10)).to.throw(error('10'));
-      expect(throwable(0)).to.throw(error('0'));
-      expect(throwable(false)).to.throw(error('false'));
-      expect(throwable(undefined)).to.throw(error('undefined'));
-      expect(throwable(null)).to.throw(error('null'));
-      expect(throwable({})).to.throw(error('Object'));
-      expect(throwable([])).to.throw(error('Array'));
-      expect(throwable(() => undefined)).to.throw(error('Function'));
-      throwable('str')();
-    });
-
-    it('throws an error if the given name already exists', function () {
-      const ptr = new PropertyTransformerRegistry();
-      ptr.addTransformer('test', () => undefined);
-      const throwable = () => ptr.addTransformer('test', () => undefined);
-      expect(throwable).to.throw(
-        'The property transformer "test" is already defined.',
-      );
-    });
-
-    it('requires the given transformer to be a function', function () {
-      const ptr = new PropertyTransformerRegistry();
-      const throwable = v => () => ptr.addTransformer('test', v);
-      const error = v =>
-        format(
-          'The property transformer "test" must be a Function, but %s was given.',
-          v,
-        );
-      expect(throwable('str')).to.throw(error('"str"'));
-      expect(throwable('')).to.throw(error('""'));
-      expect(throwable(10)).to.throw(error('10'));
-      expect(throwable(0)).to.throw(error('0'));
-      expect(throwable(false)).to.throw(error('false'));
-      expect(throwable(undefined)).to.throw(error('undefined'));
-      expect(throwable(null)).to.throw(error('null'));
-      expect(throwable({})).to.throw(error('Object'));
-      expect(throwable([])).to.throw(error('Array'));
-      throwable(() => undefined)();
-    });
-  });
-
-  describe('hasTransformer', function () {
-    it('returns false for a not existing name', function () {
-      const ptr = new PropertyTransformerRegistry();
-      expect(ptr.hasTransformer('str')).to.be.false;
-      expect(ptr.hasTransformer('')).to.be.false;
-      expect(ptr.hasTransformer(10)).to.be.false;
-      expect(ptr.hasTransformer(0)).to.be.false;
-      expect(ptr.hasTransformer(true)).to.be.false;
-      expect(ptr.hasTransformer(false)).to.be.false;
-      expect(ptr.hasTransformer(null)).to.be.false;
-      expect(ptr.hasTransformer(undefined)).to.be.false;
-      expect(ptr.hasTransformer({})).to.be.false;
-      expect(ptr.hasTransformer([])).to.be.false;
-      expect(ptr.hasTransformer(() => undefined)).to.be.false;
-    });
-
-    it('returns true for an existing name', function () {
-      const ptr = new PropertyTransformerRegistry();
-      expect(ptr.hasTransformer('test')).to.be.false;
-      ptr.addTransformer('test', () => undefined);
-      expect(ptr.hasTransformer('test')).to.be.true;
-    });
-  });
-
-  describe('getTransformer', function () {
-    it('returns transformer by its name', function () {
-      const ptr = new PropertyTransformerRegistry();
-      const myTransformer1 = () => undefined;
-      const myTransformer2 = () => undefined;
-      ptr.addTransformer('foo', myTransformer1);
-      ptr.addTransformer('bar', myTransformer2);
-      const res1 = ptr.getTransformer('foo');
-      const res2 = ptr.getTransformer('bar');
-      expect(res1).to.be.eq(myTransformer1);
-      expect(res2).to.be.eq(myTransformer2);
-    });
-
-    it('throws an error for a not existed name', function () {
-      const ptr = new PropertyTransformerRegistry();
-      const throwable = v => () => ptr.getTransformer(v);
-      const error = v =>
-        format('The property transformer %s is not defined.', v);
-      expect(throwable('str')).to.throw(error('"str"'));
-      expect(throwable('')).to.throw(error('""'));
-      expect(throwable(10)).to.throw(error('10'));
-      expect(throwable(0)).to.throw(error('0'));
-      expect(throwable(true)).to.throw(error('true'));
-      expect(throwable(false)).to.throw(error('false'));
-      expect(throwable(null)).to.throw(error('null'));
-      expect(throwable(undefined)).to.throw(error('undefined'));
-      expect(throwable({})).to.throw(error('Object'));
-      expect(throwable([])).to.throw(error('Array'));
-      expect(throwable(() => undefined)).to.throw(error('Function'));
-    });
-  });
-});

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

@@ -1,27 +0,0 @@
-import {ValueOrPromise} from '../../../../types.js';
-
-/**
- * Property transformer context.
- */
-export declare type PropertyTransformerContext = {
-  transformerName: string,
-  modelName: string,
-  propName: string,
-}
-
-/**
- * Property transformer.
- */
-export declare type PropertyTransformer = (
-  value: unknown,
-  options: unknown,
-  context: PropertyTransformerContext,
-) => ValueOrPromise<unknown>;
-
-/**
- * Property transform options.
- */
-export type PropertyTransformOptions =
-  | (string | PropertyTransformer)
-  | (string | PropertyTransformer)[]
-  | {[key: string]: unknown};

+ 0 - 1
src/definition/model/properties/property-transformer/property-transformer.js

@@ -1 +0,0 @@
-export {};

+ 0 - 3
src/definition/model/properties/property-validator/builtin/index.d.ts

@@ -1,3 +0,0 @@
-export * from './regexp-validator.js';
-export * from './max-length-validator.js';
-export * from './min-length-validator.js';

+ 0 - 3
src/definition/model/properties/property-validator/builtin/index.js

@@ -1,3 +0,0 @@
-export * from './regexp-validator.js';
-export * from './max-length-validator.js';
-export * from './min-length-validator.js';

+ 0 - 6
src/definition/model/properties/property-validator/builtin/max-length-validator.d.ts

@@ -1,6 +0,0 @@
-import {PropertyValidator} from '../property-validator.js';
-
-/**
- * Max length validator.
- */
-export const maxLengthValidator: PropertyValidator;

+ 0 - 28
src/definition/model/properties/property-validator/builtin/max-length-validator.js

@@ -1,28 +0,0 @@
-import {InvalidArgumentError} from '../../../../../errors/index.js';
-
-/**
- * Max length validator.
- *
- * @param {*} value
- * @param {number|boolean} options
- * @param {object} context
- * @returns {boolean}
- */
-export function maxLengthValidator(value, options, context) {
-  if (value == null || options === false) return true;
-  if (typeof options !== 'number')
-    throw new InvalidArgumentError(
-      'The validator %v requires the "options" argument ' +
-        'as a Number, but %v was given.',
-      context.validatorName,
-      options,
-    );
-  if (typeof value === 'string' || Array.isArray(value))
-    return value.length <= options;
-  throw new InvalidArgumentError(
-    'The property validator %v requires a String ' +
-      'or an Array value, but %v was given.',
-    context.validatorName,
-    value,
-  );
-}

+ 0 - 100
src/definition/model/properties/property-validator/builtin/max-length-validator.spec.js

@@ -1,100 +0,0 @@
-import {expect} from 'chai';
-import {format} from '@e22m4u/js-format';
-import {maxLengthValidator} from './max-length-validator.js';
-
-describe('maxLengthValidator', function () {
-  it('returns true if the "options" argument is false', function () {
-    const res = maxLengthValidator('test', false, {});
-    expect(res).to.be.true;
-  });
-
-  it('returns true for undefined and null values', function () {
-    const res1 = maxLengthValidator(undefined, 10, {});
-    const res2 = maxLengthValidator(null, 10, {});
-    expect(res1).to.be.true;
-    expect(res2).to.be.true;
-  });
-
-  it('requires the "value" argument as a String or an Array', function () {
-    const throwable = v => () =>
-      maxLengthValidator(v, 10, {
-        validatorName: 'myValidator',
-      });
-    const error = v =>
-      format(
-        'The property validator "myValidator" requires a String ' +
-          'or an Array value, but %s was given.',
-        v,
-      );
-    expect(throwable(10)).to.throw(error('10'));
-    expect(throwable(0)).to.throw(error('0'));
-    expect(throwable(true)).to.throw(error('true'));
-    expect(throwable(false)).to.throw(error('false'));
-    expect(throwable({})).to.throw(error('Object'));
-    expect(throwable(() => undefined)).to.throw(error('Function'));
-    throwable('str')();
-    throwable('')();
-    throwable([1, 2, 3])();
-    throwable([])();
-    throwable(undefined)();
-    throwable(null)();
-  });
-
-  it('requires the "options" argument to be a number', function () {
-    const throwable = v => () =>
-      maxLengthValidator('test', v, {
-        validatorName: 'myValidator',
-      });
-    const error = v =>
-      format(
-        'The validator "myValidator" requires the "options" argument ' +
-          'as a Number, but %s was given.',
-        v,
-      );
-    expect(throwable('str')).to.throw(error('"str"'));
-    expect(throwable('')).to.throw(error('""'));
-    expect(throwable(true)).to.throw(error('true'));
-    expect(throwable(undefined)).to.throw(error('undefined'));
-    expect(throwable(null)).to.throw(error('null'));
-    expect(throwable({})).to.throw(error('Object'));
-    expect(throwable([])).to.throw(error('Array'));
-    expect(throwable(() => undefined)).to.throw(error('Function'));
-    throwable(10)();
-    throwable(0)();
-    throwable(false)();
-  });
-
-  describe('a string value', function () {
-    it('returns false if the value length is greater than the max length option', function () {
-      const res = maxLengthValidator('1234', 3, {});
-      expect(res).to.be.false;
-    });
-
-    it('returns true if the value length is equal to the max length option', function () {
-      const res = maxLengthValidator('123', 3, {});
-      expect(res).to.be.true;
-    });
-
-    it('returns true if the value length is lower than the max length option', function () {
-      const res = maxLengthValidator('12', 3, {});
-      expect(res).to.be.true;
-    });
-  });
-
-  describe('an array value', function () {
-    it('returns false if the value length is greater than the max length option', function () {
-      const res = maxLengthValidator([1, 2, 3, 4], 3, {});
-      expect(res).to.be.false;
-    });
-
-    it('returns true if the value length is equal to the max length option', function () {
-      const res = maxLengthValidator([1, 2, 3], 3, {});
-      expect(res).to.be.true;
-    });
-
-    it('returns true if the value length is lower than the max length option', function () {
-      const res = maxLengthValidator([1, 2], 3, {});
-      expect(res).to.be.true;
-    });
-  });
-});

+ 0 - 6
src/definition/model/properties/property-validator/builtin/min-length-validator.d.ts

@@ -1,6 +0,0 @@
-import {PropertyValidator} from '../property-validator.js';
-
-/**
- * Min length validator.
- */
-export const minLengthValidator: PropertyValidator;

+ 0 - 28
src/definition/model/properties/property-validator/builtin/min-length-validator.js

@@ -1,28 +0,0 @@
-import {InvalidArgumentError} from '../../../../../errors/index.js';
-
-/**
- * Min length validator.
- *
- * @param {*} value
- * @param {number|boolean} options
- * @param {object} context
- * @returns {boolean}
- */
-export function minLengthValidator(value, options, context) {
-  if (value == null || options === false) return true;
-  if (typeof options !== 'number')
-    throw new InvalidArgumentError(
-      'The validator %v requires the "options" argument ' +
-        'as a Number, but %v was given.',
-      context.validatorName,
-      options,
-    );
-  if (typeof value === 'string' || Array.isArray(value))
-    return value.length >= options;
-  throw new InvalidArgumentError(
-    'The property validator %v requires a String ' +
-      'or an Array value, but %v was given.',
-    context.validatorName,
-    value,
-  );
-}

+ 0 - 100
src/definition/model/properties/property-validator/builtin/min-length-validator.spec.js

@@ -1,100 +0,0 @@
-import {expect} from 'chai';
-import {format} from '@e22m4u/js-format';
-import {minLengthValidator} from './min-length-validator.js';
-
-describe('minLengthValidator', function () {
-  it('returns true if the "options" argument is false', function () {
-    const res = minLengthValidator('test', false, {});
-    expect(res).to.be.true;
-  });
-
-  it('returns true for undefined and null values', function () {
-    const res1 = minLengthValidator(undefined, 10, {});
-    const res2 = minLengthValidator(null, 10, {});
-    expect(res1).to.be.true;
-    expect(res2).to.be.true;
-  });
-
-  it('requires the "value" argument as a String or an Array', function () {
-    const throwable = v => () =>
-      minLengthValidator(v, 0, {
-        validatorName: 'myValidator',
-      });
-    const error = v =>
-      format(
-        'The property validator "myValidator" requires a String ' +
-          'or an Array value, but %s was given.',
-        v,
-      );
-    expect(throwable(10)).to.throw(error('10'));
-    expect(throwable(0)).to.throw(error('0'));
-    expect(throwable(true)).to.throw(error('true'));
-    expect(throwable(false)).to.throw(error('false'));
-    expect(throwable({})).to.throw(error('Object'));
-    expect(throwable(() => undefined)).to.throw(error('Function'));
-    throwable('str')();
-    throwable('')();
-    throwable([1, 2, 3])();
-    throwable([])();
-    throwable(undefined)();
-    throwable(null)();
-  });
-
-  it('requires the "options" argument to be a number', function () {
-    const throwable = v => () =>
-      minLengthValidator('test', v, {
-        validatorName: 'myValidator',
-      });
-    const error = v =>
-      format(
-        'The validator "myValidator" requires the "options" argument ' +
-          'as a Number, but %s was given.',
-        v,
-      );
-    expect(throwable('str')).to.throw(error('"str"'));
-    expect(throwable('')).to.throw(error('""'));
-    expect(throwable(true)).to.throw(error('true'));
-    expect(throwable(undefined)).to.throw(error('undefined'));
-    expect(throwable(null)).to.throw(error('null'));
-    expect(throwable({})).to.throw(error('Object'));
-    expect(throwable([])).to.throw(error('Array'));
-    expect(throwable(() => undefined)).to.throw(error('Function'));
-    throwable(10)();
-    throwable(0)();
-    throwable(false)();
-  });
-
-  describe('a string value', function () {
-    it('returns false if the value length is lower than the min length option', function () {
-      const res = minLengthValidator('12', 3, {});
-      expect(res).to.be.false;
-    });
-
-    it('returns true if the value length is equal to the min length option', function () {
-      const res = minLengthValidator('123', 3, {});
-      expect(res).to.be.true;
-    });
-
-    it('returns true if the value length is greater than the min length option', function () {
-      const res = minLengthValidator('1234', 3, {});
-      expect(res).to.be.true;
-    });
-  });
-
-  describe('an array value', function () {
-    it('returns false if the value length is lower than the min length option', function () {
-      const res = minLengthValidator([1, 2], 3, {});
-      expect(res).to.be.false;
-    });
-
-    it('returns true if the value length is equal to the min length option', function () {
-      const res = minLengthValidator([1, 2, 3], 3, {});
-      expect(res).to.be.true;
-    });
-
-    it('returns true if the value length is greater than the min length option', function () {
-      const res = minLengthValidator([1, 2, 3, 4], 3, {});
-      expect(res).to.be.true;
-    });
-  });
-});

+ 0 - 6
src/definition/model/properties/property-validator/builtin/regexp-validator.d.ts

@@ -1,6 +0,0 @@
-import {PropertyValidator} from '../property-validator.js';
-
-/**
- * Regexp validator.
- */
-export const regexpValidator: PropertyValidator;

+ 0 - 30
src/definition/model/properties/property-validator/builtin/regexp-validator.js

@@ -1,30 +0,0 @@
-import {stringToRegexp} from '../../../../../utils/index.js';
-import {InvalidArgumentError} from '../../../../../errors/index.js';
-
-/**
- * Regexp validator.
- *
- * @param {*} value
- * @param {string|RegExp|boolean} options
- * @param {object} context
- * @returns {boolean}
- */
-export function regexpValidator(value, options, context) {
-  if (value == null || options === false) return true;
-  if (typeof options !== 'string' && !(options instanceof RegExp))
-    throw new InvalidArgumentError(
-      'The validator %v requires the "options" argument ' +
-        'as a String or RegExp, but %v was given.',
-      context.validatorName,
-      options,
-    );
-  if (typeof value === 'string') {
-    const regexp = stringToRegexp(options);
-    return regexp.test(value);
-  }
-  throw new InvalidArgumentError(
-    'The property validator %v requires ' + 'a String value, but %v was given.',
-    context.validatorName,
-    value,
-  );
-}

+ 0 - 102
src/definition/model/properties/property-validator/builtin/regexp-validator.spec.js

@@ -1,102 +0,0 @@
-import {expect} from 'chai';
-import {format} from '@e22m4u/js-format';
-import {regexpValidator} from './regexp-validator.js';
-
-describe('regexpValidator', function () {
-  it('returns true if the "options" argument is false', function () {
-    const res = regexpValidator('test', false, {});
-    expect(res).to.be.true;
-  });
-
-  it('returns true for undefined and null values', function () {
-    const res1 = regexpValidator(undefined, '.*', {});
-    const res2 = regexpValidator(null, '.*', {});
-    expect(res1).to.be.true;
-    expect(res2).to.be.true;
-  });
-
-  it('requires the "value" argument to be a string', function () {
-    const throwable = v => () =>
-      regexpValidator(v, '.*', {
-        validatorName: 'myValidator',
-      });
-    const error = v =>
-      format(
-        'The property validator "myValidator" requires ' +
-          'a String value, but %s was given.',
-        v,
-      );
-    expect(throwable(true)).to.throw(error('true'));
-    expect(throwable(false)).to.throw(error('false'));
-    expect(throwable({})).to.throw(error('Object'));
-    expect(throwable([])).to.throw(error('Array'));
-    expect(throwable(() => undefined)).to.throw(error('Function'));
-    throwable('str')();
-    throwable('')();
-    throwable(undefined)();
-    throwable(null)();
-  });
-
-  it('requires the "options" argument to be a string or RegExp', function () {
-    const throwable = v => () =>
-      regexpValidator('test', v, {
-        validatorName: 'myValidator',
-      });
-    const error = v =>
-      format(
-        'The validator "myValidator" requires the "options" argument ' +
-          'as a String or RegExp, but %s was given.',
-        v,
-      );
-    expect(throwable(true)).to.throw(error('true'));
-    expect(throwable(undefined)).to.throw(error('undefined'));
-    expect(throwable(null)).to.throw(error('null'));
-    expect(throwable({})).to.throw(error('Object'));
-    expect(throwable([])).to.throw(error('Array'));
-    expect(throwable(() => undefined)).to.throw(error('Function'));
-    throwable('str')();
-    throwable('')();
-    throwable(false)();
-    throwable(new RegExp(''))();
-  });
-
-  describe('the given regexp as a String', function () {
-    it('returns false if the given regexp is not matched', function () {
-      const res1 = regexpValidator('foo', 'bar', {});
-      const res2 = regexpValidator('foo', '^\\d+', {});
-      const res3 = regexpValidator('foo', '^baz$', {});
-      expect(res1).to.be.false;
-      expect(res2).to.be.false;
-      expect(res3).to.be.false;
-    });
-
-    it('returns true if the given regexp is matched', function () {
-      const res1 = regexpValidator('foo', '^fo', {});
-      const res2 = regexpValidator('foo', '^foo$', {});
-      const res3 = regexpValidator('foo', '^\\w+$', {});
-      expect(res1).to.be.true;
-      expect(res2).to.be.true;
-      expect(res3).to.be.true;
-    });
-  });
-
-  describe('the given regexp as an instance of RegExp', function () {
-    it('returns false if the given regexp is not matched', function () {
-      const res1 = regexpValidator('foo', /bar/, {});
-      const res2 = regexpValidator('foo', /^\d+/, {});
-      const res3 = regexpValidator('foo', /^bar$/, {});
-      expect(res1).to.be.false;
-      expect(res2).to.be.false;
-      expect(res3).to.be.false;
-    });
-
-    it('returns true if the given regexp is matched', function () {
-      const res1 = regexpValidator('foo', /^fo/, {});
-      const res2 = regexpValidator('foo', /^foo$/, {});
-      const res3 = regexpValidator('foo', /^\w+$/, {});
-      expect(res1).to.be.true;
-      expect(res2).to.be.true;
-      expect(res3).to.be.true;
-    });
-  });
-});

+ 0 - 2
src/definition/model/properties/property-validator/index.d.ts

@@ -1,2 +0,0 @@
-export * from './property-validator.js';
-export * from './property-validator-registry.js';

+ 0 - 2
src/definition/model/properties/property-validator/index.js

@@ -1,2 +0,0 @@
-export * from './property-validator.js';
-export * from './property-validator-registry.js';

+ 0 - 29
src/definition/model/properties/property-validator/property-validator-registry.d.ts

@@ -1,29 +0,0 @@
-import {Service} from '@e22m4u/js-service';
-import {PropertyValidator} from './property-validator.js';
-
-/**
- * Property validator registry.
- */
-export declare class PropertyValidatorRegistry extends Service {
-  /**
-   * Add validator.
-   *
-   * @param name
-   * @param validator
-   */
-  addValidator(name: string, validator: PropertyValidator): this;
-
-  /**
-   * Has validator.
-   *
-   * @param name
-   */
-  hasValidator(name: string): boolean;
-
-  /**
-   * Get validator.
-   *
-   * @param name
-   */
-  getValidator(name: string): PropertyValidator;
-}

+ 0 - 76
src/definition/model/properties/property-validator/property-validator-registry.js

@@ -1,76 +0,0 @@
-import {Service} from '@e22m4u/js-service';
-import {regexpValidator} from './builtin/index.js';
-import {maxLengthValidator} from './builtin/index.js';
-import {minLengthValidator} from './builtin/index.js';
-import {InvalidArgumentError} from '../../../../errors/index.js';
-
-/**
- * Property validator registry.
- */
-export class PropertyValidatorRegistry extends Service {
-  /**
-   * Validators.
-   *
-   * @type {object}
-   */
-  _validators = {
-    maxLength: maxLengthValidator,
-    minLength: minLengthValidator,
-    regexp: regexpValidator,
-  };
-
-  /**
-   * Add validator.
-   *
-   * @param {string} name
-   * @param {Function} validator
-   * @returns {PropertyValidatorRegistry}
-   */
-  addValidator(name, validator) {
-    if (!name || typeof name !== 'string')
-      throw new InvalidArgumentError(
-        'A name of the property validator must ' +
-          'be a non-empty String, but %v was given.',
-        name,
-      );
-    if (name in this._validators)
-      throw new InvalidArgumentError(
-        'The property validator %v is already defined.',
-        name,
-      );
-    if (typeof validator !== 'function')
-      throw new InvalidArgumentError(
-        'The property validator %v must be a Function, but %v was given.',
-        name,
-        validator,
-      );
-    this._validators[name] = validator;
-    return this;
-  }
-
-  /**
-   * Has validator.
-   *
-   * @param {string} name
-   * @returns {boolean}
-   */
-  hasValidator(name) {
-    return Boolean(this._validators[name]);
-  }
-
-  /**
-   * Get validator.
-   *
-   * @param {string} name
-   * @returns {Function}
-   */
-  getValidator(name) {
-    const validator = this._validators[name];
-    if (!validator)
-      throw new InvalidArgumentError(
-        'The property validator %v is not defined.',
-        name,
-      );
-    return validator;
-  }
-}

+ 0 - 132
src/definition/model/properties/property-validator/property-validator-registry.spec.js

@@ -1,132 +0,0 @@
-import {expect} from 'chai';
-import {format} from '@e22m4u/js-format';
-import {regexpValidator} from './builtin/index.js';
-import {maxLengthValidator} from './builtin/index.js';
-import {minLengthValidator} from './builtin/index.js';
-import {PropertyValidatorRegistry} from './property-validator-registry.js';
-
-describe('PropertyValidatorRegistry', function () {
-  it('has builtin validators', function () {
-    const pvr = new PropertyValidatorRegistry();
-    expect(pvr['_validators']).to.be.eql({
-      maxLength: maxLengthValidator,
-      minLength: minLengthValidator,
-      regexp: regexpValidator,
-    });
-  });
-
-  describe('addValidator', function () {
-    it('adds a given validator with the name', function () {
-      const pvr = new PropertyValidatorRegistry();
-      const myValidator = () => undefined;
-      const res = pvr.addValidator('myValidator', myValidator);
-      expect(res).to.be.eq(pvr);
-      expect(pvr['_validators']['myValidator']).to.be.eq(myValidator);
-    });
-
-    it('requires the given name to be a non-empty string', function () {
-      const pvr = new PropertyValidatorRegistry();
-      const throwable = v => () => pvr.addValidator(v, () => undefined);
-      const error = v =>
-        format(
-          'A name of the property validator must ' +
-            'be a non-empty String, but %s was given.',
-          v,
-        );
-      expect(throwable('')).to.throw(error('""'));
-      expect(throwable(10)).to.throw(error('10'));
-      expect(throwable(0)).to.throw(error('0'));
-      expect(throwable(false)).to.throw(error('false'));
-      expect(throwable(undefined)).to.throw(error('undefined'));
-      expect(throwable(null)).to.throw(error('null'));
-      expect(throwable({})).to.throw(error('Object'));
-      expect(throwable([])).to.throw(error('Array'));
-      expect(throwable(() => undefined)).to.throw(error('Function'));
-      throwable('str')();
-    });
-
-    it('throws an error if the given name already exists', function () {
-      const pvr = new PropertyValidatorRegistry();
-      pvr.addValidator('test', () => undefined);
-      const throwable = () => pvr.addValidator('test', () => undefined);
-      expect(throwable).to.throw(
-        'The property validator "test" is already defined.',
-      );
-    });
-
-    it('requires the given validator to be a function', function () {
-      const pvr = new PropertyValidatorRegistry();
-      const throwable = v => () => pvr.addValidator('test', v);
-      const error = v =>
-        format(
-          'The property validator "test" must be a Function, but %s was given.',
-          v,
-        );
-      expect(throwable('str')).to.throw(error('"str"'));
-      expect(throwable('')).to.throw(error('""'));
-      expect(throwable(10)).to.throw(error('10'));
-      expect(throwable(0)).to.throw(error('0'));
-      expect(throwable(false)).to.throw(error('false'));
-      expect(throwable(undefined)).to.throw(error('undefined'));
-      expect(throwable(null)).to.throw(error('null'));
-      expect(throwable({})).to.throw(error('Object'));
-      expect(throwable([])).to.throw(error('Array'));
-      throwable(() => undefined)();
-    });
-  });
-
-  describe('hasValidator', function () {
-    it('returns false for a not existing name', function () {
-      const pvr = new PropertyValidatorRegistry();
-      expect(pvr.hasValidator('str')).to.be.false;
-      expect(pvr.hasValidator('')).to.be.false;
-      expect(pvr.hasValidator(10)).to.be.false;
-      expect(pvr.hasValidator(0)).to.be.false;
-      expect(pvr.hasValidator(true)).to.be.false;
-      expect(pvr.hasValidator(false)).to.be.false;
-      expect(pvr.hasValidator(null)).to.be.false;
-      expect(pvr.hasValidator(undefined)).to.be.false;
-      expect(pvr.hasValidator({})).to.be.false;
-      expect(pvr.hasValidator([])).to.be.false;
-      expect(pvr.hasValidator(() => undefined)).to.be.false;
-    });
-
-    it('returns true for an existing name', function () {
-      const pvr = new PropertyValidatorRegistry();
-      expect(pvr.hasValidator('test')).to.be.false;
-      pvr.addValidator('test', () => undefined);
-      expect(pvr.hasValidator('test')).to.be.true;
-    });
-  });
-
-  describe('getValidator', function () {
-    it('returns validator by its name', function () {
-      const pvr = new PropertyValidatorRegistry();
-      const myValidator1 = () => undefined;
-      const myValidator2 = () => undefined;
-      pvr.addValidator('foo', myValidator1);
-      pvr.addValidator('bar', myValidator2);
-      const res1 = pvr.getValidator('foo');
-      const res2 = pvr.getValidator('bar');
-      expect(res1).to.be.eq(myValidator1);
-      expect(res2).to.be.eq(myValidator2);
-    });
-
-    it('throws an error for a not existed name', function () {
-      const pvr = new PropertyValidatorRegistry();
-      const throwable = v => () => pvr.getValidator(v);
-      const error = v => format('The property validator %s is not defined.', v);
-      expect(throwable('str')).to.throw(error('"str"'));
-      expect(throwable('')).to.throw(error('""'));
-      expect(throwable(10)).to.throw(error('10'));
-      expect(throwable(0)).to.throw(error('0'));
-      expect(throwable(true)).to.throw(error('true'));
-      expect(throwable(false)).to.throw(error('false'));
-      expect(throwable(null)).to.throw(error('null'));
-      expect(throwable(undefined)).to.throw(error('undefined'));
-      expect(throwable({})).to.throw(error('Object'));
-      expect(throwable([])).to.throw(error('Array'));
-      expect(throwable(() => undefined)).to.throw(error('Function'));
-    });
-  });
-});

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

@@ -1,25 +0,0 @@
-/**
- * Property validator context.
- */
-export type PropertyValidatorContext = {
-  validatorName: string,
-  modelName: string,
-  propName: string,
-}
-
-/**
- * Property validator.
- */
-export type PropertyValidator = (
-  value: unknown,
-  options: unknown,
-  context: PropertyValidatorContext,
-) => boolean;
-
-/**
- * Property validate options.
- */
-export type PropertyValidateOptions =
-  | (string | PropertyValidator)
-  | (string | PropertyValidator)[]
-  | {[key: string]: unknown};

+ 0 - 1
src/definition/model/properties/property-validator/property-validator.js

@@ -1 +0,0 @@
-export {};

Некоторые файлы не были показаны из-за большого количества измененных файлов