|
|
@@ -6,9 +6,9 @@ JavaScript модуль для работы со схемой данных.
|
|
|
|
|
|
- [Установка](#установка)
|
|
|
- [Схема данных](#схема-данных)
|
|
|
-- [Использование](#использование)
|
|
|
- - [Проверка данных](#проверка-данных)
|
|
|
- - [Парсинг данных](#парсинг-данных)
|
|
|
+- [Проверка данных](#проверка-данных)
|
|
|
+- [Парсинг данных](#парсинг-данных)
|
|
|
+- [Именованные схемы](#именованные-схемы)
|
|
|
- [Пустые значения](#пустые-значения)
|
|
|
- [Тесты](#тесты)
|
|
|
- [Лицензия](#лицензия)
|
|
|
@@ -33,7 +33,7 @@ import {DataValidator} from '@e22m4u/js-data-schema';
|
|
|
const {DataValidator} = require('@e22m4u/js-data-schema');
|
|
|
```
|
|
|
|
|
|
-### Схема данных
|
|
|
+## Схема данных
|
|
|
|
|
|
Схема данных позволяет указать допустимый тип значения, схему элементов
|
|
|
массива и схему свойств объекта. Схему можно использовать для проверки
|
|
|
@@ -165,127 +165,96 @@ const {DataValidator} = require('@e22m4u/js-data-schema');
|
|
|
}
|
|
|
```
|
|
|
|
|
|
-## Использование
|
|
|
+## Проверка данных
|
|
|
|
|
|
-Ниже приводятся примеры использования различных схем.
|
|
|
-
|
|
|
-### Проверка данных
|
|
|
-
|
|
|
-Проверка типа данных.
|
|
|
+Модуль экспортирует сервис `DataValidator`, с помощью которого выполняется
|
|
|
+проверка соответствия данных указанной схеме. Пример ниже демонстрирует
|
|
|
+создание экземпляра сервиса и проверку примитивных значений.
|
|
|
|
|
|
```js
|
|
|
import {DataValidator, DataType} from '@e22m4u/js-data-schema';
|
|
|
|
|
|
const validator = new DataValidator();
|
|
|
-
|
|
|
-const schema = {
|
|
|
- type: DataType.STRING, // тип данных
|
|
|
-};
|
|
|
-
|
|
|
-// значение "str" соответствует схеме
|
|
|
-validator.validate('str', schema); // OK
|
|
|
-
|
|
|
-// undefined допускается (параметр "required" не указан)
|
|
|
-validator.validate(undefined, schema); // OK
|
|
|
-
|
|
|
-// 10 не является строкой
|
|
|
-validator.validate(10, schema); // error: DataValidationError
|
|
|
-
|
|
|
-// true не является строкой
|
|
|
-validator.validate(true, schema); // error: DataValidationError
|
|
|
+const numberSchema = {type: DataType.NUMBER};
|
|
|
+
|
|
|
+// OK
|
|
|
+validator.validate(10, numberSchema);
|
|
|
+validator.validate(0, numberSchema);
|
|
|
+validator.validate(undefined, numberSchema);
|
|
|
+validator.validate(null, numberSchema);
|
|
|
+
|
|
|
+// выбросит DataValidationError
|
|
|
+validator.validate('str', numberSchema);
|
|
|
+validator.validate(true, numberSchema);
|
|
|
+validator.validate([1, 2, 3], numberSchema);
|
|
|
+validator.validate({foo: 'bar'}, numberSchema);
|
|
|
```
|
|
|
|
|
|
-Проверка обязательного значения.
|
|
|
+Каждый тип данных имеет собственный набор [пустых значений](#пустые-значения),
|
|
|
+которые являются допустимыми при проверке данных соответствующего типа.
|
|
|
+Чтобы исключить такие значения применяется параметр `required`.
|
|
|
|
|
|
```js
|
|
|
import {DataValidator, DataType} from '@e22m4u/js-data-schema';
|
|
|
|
|
|
const validator = new DataValidator();
|
|
|
|
|
|
-const schema = {
|
|
|
- type: DataType.NUMBER, // тип данных
|
|
|
- required: true, // является обязательным
|
|
|
+const requiredNumberSchema = {
|
|
|
+ type: DataType.NUMBER,
|
|
|
+ required: true // исключает пустые значения
|
|
|
};
|
|
|
|
|
|
-// значение 10 соответствует схеме
|
|
|
-validator.validate(10, schema); // OK
|
|
|
-
|
|
|
-// undefined не допускается (параметр "required")
|
|
|
-validator.validate(undefined, schema); // error: DataValidationError
|
|
|
-
|
|
|
-// 'str' не является числом
|
|
|
-validator.validate('str', schema); // error: DataValidationError
|
|
|
+// OK
|
|
|
+validator.validate(10, requiredNumberSchema);
|
|
|
+validator.validate(-10, requiredNumberSchema);
|
|
|
|
|
|
-// true не является числом
|
|
|
-validator.validate(true, schema); // error: DataValidationError
|
|
|
+// выбросит DataValidationError
|
|
|
+validator.validate(0, requiredNumberSchema);
|
|
|
+validator.validate(undefined, requiredNumberSchema);
|
|
|
+validator.validate(null, requiredNumberSchema);
|
|
|
```
|
|
|
|
|
|
-Проверка элементов массива.
|
|
|
-
|
|
|
-```js
|
|
|
-import {DataValidator, DataType} from '@e22m4u/js-data-schema';
|
|
|
+## Парсинг данных
|
|
|
|
|
|
-const validator = new DataValidator();
|
|
|
+Сервис `DataParser` спроектирован для приведения данных в соответствие
|
|
|
+указанной схеме. Приведение выполняется с учетом возможных ошибок
|
|
|
+пользовательского ввода. К примеру, если схема ожидает число, но входящие
|
|
|
+данные содержат другие символы, то будет выброшена ошибка.
|
|
|
|
|
|
-const schema = {
|
|
|
- type: DataType.ARRAY, // тип данных
|
|
|
- items: {
|
|
|
- type: DataType.NUMBER, // тип элемента
|
|
|
- },
|
|
|
-};
|
|
|
-
|
|
|
-// элементы массива соответствуют схеме
|
|
|
-validator.validate([1, 2, 3], schema); // OK
|
|
|
-
|
|
|
-// пустой массив также допускается
|
|
|
-validator.validate([], schema); // OK
|
|
|
-
|
|
|
-// 'str' не является массивом
|
|
|
-validator.validate('str', schema); // error: DataValidationError
|
|
|
+```js
|
|
|
+import {DataParser, DataType} from '@e22m4u/js-data-schema';
|
|
|
|
|
|
-// элементы массива не соответствуют схеме (параметр "items")
|
|
|
-validator.validate(['a', 'b'], schema); // error: DataValidationError
|
|
|
+const parser = new DataParser();
|
|
|
|
|
|
-// объект не является массивом
|
|
|
-validator.validate({foo: 'bar'}, schema); // error: DataValidationError
|
|
|
+parser.parse('10', {type: DataType.NUMBER}); // 10
|
|
|
+parser.parse('10.5', {type: DataType.NUMBER}); // 10.5
|
|
|
+parser.parse('10abc', {type: DataType.NUMBER}); // DataParsingError
|
|
|
```
|
|
|
|
|
|
-Проверка свойств объекта.
|
|
|
+Массивы и объекты могут быть представлены в виде *JSON*. Метод `parse`
|
|
|
+разбирает такие значения и выполняет их проверку. К примеру, если элементы
|
|
|
+массива не соответствуют определению схемы, то будет выброшена ошибка.
|
|
|
|
|
|
```js
|
|
|
-import {DataValidator, DataType} from '@e22m4u/js-data-schema';
|
|
|
+import {DataParser, DataType} from '@e22m4u/js-data-schema';
|
|
|
|
|
|
-const validator = new DataValidator();
|
|
|
+const parser = new DataParser();
|
|
|
|
|
|
-const schema = {
|
|
|
- type: DataType.OBJECT, // тип данных
|
|
|
- properties: {
|
|
|
- foo: { // схема свойства "foo"
|
|
|
- type: DataType.STRING, // тип свойства
|
|
|
- required: true, // является обязательным
|
|
|
- },
|
|
|
- bar: { // схема свойства "bar"
|
|
|
- type: DataType.NUMBER, // тип свойства
|
|
|
- },
|
|
|
+const numberListSchema = {
|
|
|
+ type: DataType.ARRAY,
|
|
|
+ items: {
|
|
|
+ type: DataType.NUMBER,
|
|
|
+ required: true, // исключает undefined, null и 0
|
|
|
},
|
|
|
};
|
|
|
|
|
|
-// свойства объекта соответствуют схеме
|
|
|
-validator.validate({foo: 'str', bar: 10}, schema); // OK
|
|
|
-
|
|
|
-// обязательное свойство "foo" присутствует
|
|
|
-validator.validate({foo: 'str'}, schema); // OK
|
|
|
-
|
|
|
-// значение свойства "foo" не является строкой
|
|
|
-validator.validate({foo: true}, schema); // error: DataValidationError
|
|
|
-
|
|
|
-// массив не является объектом
|
|
|
-validator.validate([1, 2, 3], schema); // error: DataValidationError
|
|
|
+parser.parse('[1, 2, 3]', numberListSchema); // [1, 2, 3]
|
|
|
+parser.parse('[1, 2, null]', numberListSchema); // DataParsingError
|
|
|
```
|
|
|
|
|
|
-### Парсинг данных
|
|
|
-
|
|
|
-Приведение типа согласно схеме.
|
|
|
+Если при разборе данных значение оказалось [пустым](#пустые-значения),
|
|
|
+то при наличии параметра `default` используется значение по умолчанию.
|
|
|
+Значение данного параметра должно соответствовать схеме.
|
|
|
|
|
|
```js
|
|
|
import {DataParser, DataType} from '@e22m4u/js-data-schema';
|
|
|
@@ -293,76 +262,142 @@ import {DataParser, DataType} from '@e22m4u/js-data-schema';
|
|
|
const parser = new DataParser();
|
|
|
|
|
|
const schema = {
|
|
|
- type: DataType.NUMBER, // тип данных
|
|
|
+ type: DataType.NUMBER,
|
|
|
+ default: 0,
|
|
|
};
|
|
|
|
|
|
-// приведение строки к числу
|
|
|
-const result = parser.parse('10', schema);
|
|
|
-console.log(result); // 10
|
|
|
-
|
|
|
-// строка не является числом
|
|
|
-parser.parse('10abc', schema); // error: DataParsingError
|
|
|
+parser.parse('10', schema); // 10
|
|
|
+parser.parse(undefined, schema); // 0
|
|
|
+parser.parse('N/A', schema); // DataParsingError
|
|
|
```
|
|
|
|
|
|
-Разбор JSON строки согласно схеме массива.
|
|
|
+## Именованные схемы
|
|
|
+
|
|
|
+Модуль экспортирует сервисы для проверки и парсинга данных. Каждый
|
|
|
+сервис позволяет регистрировать схемы данных по уникальному имени
|
|
|
+методом `defineSchema`.
|
|
|
|
|
|
```js
|
|
|
-import {DataParser, DataType} from '@e22m4u/js-data-schema';
|
|
|
+import {DataValidator, DataParser, DataType} from '@e22m4u/js-data-service';
|
|
|
|
|
|
+const validator = new DataValidator();
|
|
|
const parser = new DataParser();
|
|
|
|
|
|
const schema = {
|
|
|
- type: DataType.ARRAY, // тип данных
|
|
|
+ type: DataType.ARRAY,
|
|
|
items: {
|
|
|
- type: DataType.NUMBER, // тип элемента
|
|
|
+ type: DataType.STRING,
|
|
|
+ required: true,
|
|
|
},
|
|
|
};
|
|
|
|
|
|
-// приведение строки к массиву
|
|
|
-const result = parser.parse('[1, 2, 3]', schema);
|
|
|
-console.log(result);
|
|
|
-// [1, 2, 3]
|
|
|
+validator.defineSchema({name: 'mySchema', schema});
|
|
|
+parser.defineSchema({name: 'mySchema', schema});
|
|
|
+```
|
|
|
+
|
|
|
+Регистрация может выполняться централизованно через реестр. Этого можно
|
|
|
+добиться используя сервис-контейнер, который обычно выступает как точка
|
|
|
+входа в приложение.
|
|
|
|
|
|
-// элементы массива не соответствуют схеме
|
|
|
-parser.parse('["str", true]', schema); // error: DataParsingError
|
|
|
+```js
|
|
|
+import {ServiceContainer} from '@e22m4u/js-service';
|
|
|
+
|
|
|
+import {
|
|
|
+ DataType,
|
|
|
+ DataParser,
|
|
|
+ DataValidator,
|
|
|
+ DataSchemaRegistry,
|
|
|
+} from '@e22m4u/js-data-service';
|
|
|
+
|
|
|
+const app = new ServiceContainer();
|
|
|
+const registry = app.get(DataSchemaRegistry);
|
|
|
+
|
|
|
+registry.defineSchema({
|
|
|
+ name: 'mySchema',
|
|
|
+ schema: {
|
|
|
+ type: DataType.ARRAY,
|
|
|
+ items: {
|
|
|
+ type: DataType.STRING,
|
|
|
+ required: true,
|
|
|
+ },
|
|
|
+ },
|
|
|
+});
|
|
|
+
|
|
|
+const validator = app.get(DataValidator);
|
|
|
+const parser = app.get(DataParser);
|
|
|
```
|
|
|
|
|
|
-Разбор JSON строки согласно схеме объекта.
|
|
|
+В примере выше оба сервиса используют общий реестр и знают о зарегистрированной
|
|
|
+схеме `mySchema`, что избавляет от необходимости синхронизации схем между ними.
|
|
|
+
|
|
|
+#### Использование именованных схем
|
|
|
+
|
|
|
+Зарегистрированное имя схемы можно использовать вместо обычной схемы. Пример
|
|
|
+ниже демонстрирует проверку данных с помощью именованной схемы.
|
|
|
|
|
|
```js
|
|
|
-import {DataParser, DataType} from '@e22m4u/js-data-schema';
|
|
|
+validator.defineSchema({
|
|
|
+ name: 'stringList',
|
|
|
+ schema: {
|
|
|
+ type: DataType.STRING,
|
|
|
+ required: true,
|
|
|
+ },
|
|
|
+});
|
|
|
|
|
|
-const parser = new DataParser();
|
|
|
+validator.validate(['a', 'b', 'c'], 'mySchema'); // OK
|
|
|
+validator.validate(['a', 'b', 10], 'mySchema'); // DataValidationError
|
|
|
+```
|
|
|
|
|
|
-const schema = {
|
|
|
- type: DataType.OBJECT, // тип данных
|
|
|
- properties: {
|
|
|
- foo: { // схема свойства "foo"
|
|
|
- type: DataType.STRING, // тип свойства
|
|
|
- required: true, // является обязательным
|
|
|
- },
|
|
|
- bar: { // схема свойства "bar"
|
|
|
- type: DataType.NUMBER, // тип свойства
|
|
|
+Имена схем можно встраивать в обычные схемы. Ниже приводится пример
|
|
|
+использования именованной схемы для определения схемы элементов массива.
|
|
|
+
|
|
|
+```js
|
|
|
+parser.defineSchema({
|
|
|
+ name: 'user', // имя схемы
|
|
|
+ schema: {
|
|
|
+ type: DataType.OBJECT,
|
|
|
+ properties: {
|
|
|
+ name: {
|
|
|
+ type: DataType.STRING,
|
|
|
+ required: true,
|
|
|
+ },
|
|
|
+ age: {
|
|
|
+ type: DataType.NUMBER,
|
|
|
+ default: 0,
|
|
|
+ },
|
|
|
},
|
|
|
},
|
|
|
-};
|
|
|
+});
|
|
|
|
|
|
-// приведение строки к объекту
|
|
|
-const result = parser.parse(
|
|
|
- '{"foo": "str", "bar": 10}',
|
|
|
- schema,
|
|
|
-);
|
|
|
-console.log(result);
|
|
|
-// {
|
|
|
-// "foo": "str",
|
|
|
-// "bar": 10
|
|
|
-// }
|
|
|
+const jsonData = `[{"name": "John","age": 35},{"name": "Tommy"}]`;
|
|
|
|
|
|
-// обязательное свойство "foo" отсутствует
|
|
|
-parser.parse('{"bar": 10}', schema); // error: DataParsingError
|
|
|
+const users = parser.parse(jsonData, {
|
|
|
+ type: DataType.ARRAY,
|
|
|
+ items: 'user', // <= именованная схема
|
|
|
+});
|
|
|
+console.log(users);
|
|
|
+// [
|
|
|
+// {
|
|
|
+// name: 'John',
|
|
|
+// age: 35
|
|
|
+// },
|
|
|
+// {
|
|
|
+// name: 'Tommy',
|
|
|
+// age: 0
|
|
|
+// }
|
|
|
+// ]
|
|
|
+```
|
|
|
+
|
|
|
+Если именованная схема описывает объект, то допускается передача имени схемы
|
|
|
+в параметр `properties`, что позволяет переопределить остальные параметры
|
|
|
+зарегистрированной схемы.
|
|
|
|
|
|
-// значение свойства "foo" не является строкой
|
|
|
-parser.parse('{"foo": 10}', schema); // error: DataParsingError
|
|
|
+```js
|
|
|
+validator.validate(data, {
|
|
|
+ type: DataType.OBJECT,
|
|
|
+ properties: 'user', // имя схема вместо схемы свойств
|
|
|
+ required: true, // переопределение параметра схемы "user"
|
|
|
+});
|
|
|
```
|
|
|
|
|
|
## Пустые значения
|