@e22m4u/js-repository 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +479 -61
- package/dist/cjs/index.cjs +319 -270
- package/package.json +1 -1
- package/src/adapter/adapter-loader.js +1 -1
- package/src/adapter/adapter-loader.spec.js +1 -1
- package/src/adapter/decorator/data-sanitizing-decorator.js +1 -1
- package/src/adapter/decorator/data-transformation-decorator.js +1 -1
- package/src/adapter/decorator/data-validation-decorator.js +1 -1
- package/src/adapter/decorator/default-values-decorator.js +1 -1
- package/src/adapter/decorator/fields-filtering-decorator.js +1 -1
- package/src/adapter/decorator/inclusion-decorator.js +1 -1
- package/src/adapter/decorator/property-uniqueness-decorator.js +1 -1
- package/src/definition/datasource/datasource-definition-validator.js +3 -3
- package/src/definition/datasource/datasource-definition-validator.spec.js +3 -3
- package/src/definition/model/model-data-sanitizer.js +2 -2
- package/src/definition/model/model-data-transformer.js +71 -13
- package/src/definition/model/model-data-transformer.spec.js +2073 -407
- package/src/definition/model/model-data-validator.js +125 -37
- package/src/definition/model/model-data-validator.spec.js +2138 -440
- package/src/definition/model/model-definition-utils.js +5 -5
- package/src/definition/model/model-definition-utils.spec.js +7 -7
- package/src/definition/model/model-definition-validator.js +7 -7
- package/src/definition/model/model-definition-validator.spec.js +10 -7
- package/src/definition/model/properties/properties-definition-validator.js +129 -54
- package/src/definition/model/properties/properties-definition-validator.spec.js +85 -25
- package/src/definition/model/properties/property-transformer/builtin/index.d.ts +0 -1
- package/src/definition/model/properties/property-transformer/builtin/index.js +0 -1
- package/src/definition/model/properties/property-transformer/builtin/to-lower-case-transformer.d.ts +1 -1
- package/src/definition/model/properties/property-transformer/builtin/to-lower-case-transformer.js +1 -1
- package/src/definition/model/properties/property-transformer/builtin/to-lower-case-transformer.spec.js +1 -1
- package/src/definition/model/properties/property-transformer/builtin/to-upper-case-transformer.d.ts +1 -1
- package/src/definition/model/properties/property-transformer/builtin/to-upper-case-transformer.js +1 -1
- package/src/definition/model/properties/property-transformer/builtin/to-upper-case-transformer.spec.js +1 -1
- package/src/definition/model/properties/property-transformer/builtin/trim-transformer.js +1 -1
- package/src/definition/model/properties/property-transformer/builtin/trim-transformer.spec.js +1 -1
- package/src/definition/model/properties/property-transformer/property-transformer-registry.js +2 -4
- package/src/definition/model/properties/property-transformer/property-transformer-registry.spec.js +2 -4
- package/src/definition/model/properties/property-transformer/property-transformer.d.ts +2 -2
- package/src/definition/model/properties/property-uniqueness-validator.js +4 -4
- package/src/definition/model/properties/property-uniqueness-validator.spec.js +4 -4
- package/src/definition/model/properties/property-validator/builtin/max-length-validator.d.ts +1 -1
- package/src/definition/model/properties/property-validator/builtin/max-length-validator.js +2 -2
- package/src/definition/model/properties/property-validator/builtin/max-length-validator.spec.js +2 -2
- package/src/definition/model/properties/property-validator/builtin/min-length-validator.d.ts +1 -1
- package/src/definition/model/properties/property-validator/builtin/min-length-validator.js +2 -2
- package/src/definition/model/properties/property-validator/builtin/min-length-validator.spec.js +2 -2
- package/src/definition/model/properties/property-validator/builtin/regexp-validator.d.ts +1 -1
- package/src/definition/model/properties/property-validator/builtin/regexp-validator.js +2 -2
- package/src/definition/model/properties/property-validator/builtin/regexp-validator.spec.js +2 -2
- package/src/definition/model/properties/property-validator/property-validator-registry.js +2 -2
- package/src/definition/model/properties/property-validator/property-validator-registry.spec.js +2 -2
- package/src/definition/model/properties/property-validator/property-validator.d.ts +2 -2
- package/src/definition/model/relations/relations-definition-validator.js +23 -23
- package/src/definition/model/relations/relations-definition-validator.spec.js +24 -24
- package/src/errors/invalid-operator-value-error.js +1 -1
- package/src/errors/invalid-operator-value-error.spec.js +1 -1
- package/src/filter/fields-clause-tool.js +5 -5
- package/src/filter/fields-clause-tool.spec.js +16 -16
- package/src/filter/include-clause-tool.js +6 -6
- package/src/filter/include-clause-tool.spec.js +2 -2
- package/src/filter/operator-clause-tool.js +13 -13
- package/src/filter/operator-clause-tool.spec.js +13 -13
- package/src/filter/order-clause-tool.js +3 -3
- package/src/filter/order-clause-tool.spec.js +4 -4
- package/src/filter/slice-clause-tool.js +5 -5
- package/src/filter/slice-clause-tool.spec.js +5 -5
- package/src/filter/where-clause-tool.js +4 -4
- package/src/filter/where-clause-tool.spec.js +3 -3
- package/src/relations/belongs-to-resolver.js +14 -14
- package/src/relations/belongs-to-resolver.spec.js +14 -14
- package/src/relations/has-many-resolver.js +22 -22
- package/src/relations/has-many-resolver.spec.js +23 -23
- package/src/relations/has-one-resolver.js +22 -22
- package/src/relations/has-one-resolver.spec.js +23 -23
- package/src/relations/references-many-resolver.js +7 -7
- package/src/relations/references-many-resolver.spec.js +7 -7
- package/src/repository/repository-registry.js +1 -1
- package/src/utils/exclude-object-keys.js +1 -1
- package/src/utils/exclude-object-keys.spec.js +1 -1
- package/src/utils/model-name-to-model-key.js +1 -1
- package/src/utils/model-name-to-model-key.spec.js +7 -7
- package/src/utils/select-object-keys.js +3 -3
- package/src/utils/select-object-keys.spec.js +3 -3
- package/src/definition/model/properties/property-transformer/builtin/to-title-case-transformer.d.ts +0 -6
- package/src/definition/model/properties/property-transformer/builtin/to-title-case-transformer.js +0 -22
- package/src/definition/model/properties/property-transformer/builtin/to-title-case-transformer.spec.js +0 -41
package/README.md
CHANGED
|
@@ -6,12 +6,18 @@
|
|
|
6
6
|
- [Импорт](#импорт)
|
|
7
7
|
- [Описание](#описание)
|
|
8
8
|
- [Пример](#пример)
|
|
9
|
-
- [Схема
|
|
9
|
+
- [Схема](#схема)
|
|
10
10
|
- [Источник данных](#источник-данных)
|
|
11
11
|
- [Модель](#модель)
|
|
12
12
|
- [Свойства](#свойства)
|
|
13
13
|
- [Валидаторы](#валидаторы)
|
|
14
|
+
- [Глобальные валидаторы](#глобальные-валидаторы)
|
|
15
|
+
- [Регистрация глобальных валидаторов](#регистрация-глобальных-валидаторов)
|
|
16
|
+
- [Локальные валидаторы](#локальные-валидаторы)
|
|
14
17
|
- [Трансформеры](#трансформеры)
|
|
18
|
+
- [Глобальные трансформеры](#глобальные-трансформеры)
|
|
19
|
+
- [Регистрация глобальных трансформеров](#регистрация-глобальных-трансформеров)
|
|
20
|
+
- [Локальные трансформеры](#локальные-трансформеры)
|
|
15
21
|
- [Пустые значения](#пустые-значения)
|
|
16
22
|
- [Репозиторий](#репозиторий)
|
|
17
23
|
- [Фильтрация](#фильтрация)
|
|
@@ -129,10 +135,10 @@ dbs.defineModel({
|
|
|
129
135
|
},
|
|
130
136
|
})
|
|
131
137
|
|
|
132
|
-
// получение репозитория модели
|
|
138
|
+
// получение репозитория модели
|
|
133
139
|
const countryRep = dbs.getRepository('country');
|
|
134
140
|
|
|
135
|
-
// добавление нового документа в коллекцию
|
|
141
|
+
// добавление нового документа в коллекцию
|
|
136
142
|
const country = await countryRep.create({
|
|
137
143
|
name: 'Russia',
|
|
138
144
|
population: 143400000,
|
|
@@ -141,16 +147,15 @@ const country = await countryRep.create({
|
|
|
141
147
|
// вывод нового документа
|
|
142
148
|
console.log(country);
|
|
143
149
|
// {
|
|
144
|
-
//
|
|
145
|
-
//
|
|
146
|
-
//
|
|
150
|
+
// id: 1,
|
|
151
|
+
// name: 'Russia',
|
|
152
|
+
// population: 143400000,
|
|
147
153
|
// }
|
|
148
154
|
```
|
|
149
155
|
|
|
150
|
-
## Схема
|
|
156
|
+
## Схема
|
|
151
157
|
|
|
152
|
-
Экземпляр класса `DatabaseSchema` хранит определения источников и
|
|
153
|
-
данных.
|
|
158
|
+
Экземпляр класса `DatabaseSchema` хранит определения источников данных и моделей.
|
|
154
159
|
|
|
155
160
|
**Методы**
|
|
156
161
|
|
|
@@ -285,7 +290,7 @@ dbs.defineModel({
|
|
|
285
290
|
- `columnType: string` тип колонки (определяется адаптером)
|
|
286
291
|
- `required: boolean` объявить свойство обязательным
|
|
287
292
|
- `default: any` значение по умолчанию
|
|
288
|
-
- `validate: string | array | object` см. [Валидаторы](#Валидаторы)
|
|
293
|
+
- `validate: string | Function | array | object` см. [Валидаторы](#Валидаторы)
|
|
289
294
|
- `unique: boolean | string` проверять значение на уникальность
|
|
290
295
|
|
|
291
296
|
**Параметр `unique`**
|
|
@@ -341,7 +346,7 @@ dbs.defineModel({
|
|
|
341
346
|
},
|
|
342
347
|
code: {
|
|
343
348
|
type: DataType.NUMBER, // тип свойства "number" (обязательно)
|
|
344
|
-
unique: PropertyUniqueness.
|
|
349
|
+
unique: PropertyUniqueness.STRICT, // проверять уникальность
|
|
345
350
|
},
|
|
346
351
|
},
|
|
347
352
|
});
|
|
@@ -369,19 +374,64 @@ dbs.defineModel({
|
|
|
369
374
|
|
|
370
375
|
## Валидаторы
|
|
371
376
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
377
|
+
Валидаторы используются для проверки значения свойства перед записью в базу.
|
|
378
|
+
Проверка значения валидатором выполняется сразу после проверки типа, указанного
|
|
379
|
+
в определении свойства модели. [Пустые значения](#пустые-значения) пропускают
|
|
380
|
+
проверку валидаторами, так как не имеют полезной нагрузки.
|
|
381
|
+
|
|
382
|
+
### Глобальные валидаторы
|
|
383
|
+
|
|
384
|
+
Модуль поставляется с набором глобальных валидаторов:
|
|
385
|
+
|
|
386
|
+
- `regexp` проверка по регулярному выражению,
|
|
387
|
+
*параметр: `string | RegExp` - регулярное выражение;*
|
|
388
|
+
|
|
389
|
+
- `maxLength` максимальная длина строки или массива,
|
|
390
|
+
*параметр: `number` - максимальная длина;*
|
|
391
|
+
|
|
392
|
+
- `minLength` минимальная длина строки или массива,
|
|
393
|
+
*параметр: `number` - минимальная длина;*
|
|
394
|
+
|
|
395
|
+
Валидаторы указанные ниже находятся в разработке:
|
|
396
|
+
|
|
397
|
+
- `isLowerCase` проверка регистра (только прописные буквы);
|
|
398
|
+
- `isUpperCase` проверка регистра (только строчные буквы);
|
|
399
|
+
- `isEmail` проверка формата электронного адреса;
|
|
400
|
+
|
|
401
|
+
**Примеры**
|
|
402
|
+
|
|
403
|
+
Использование глобального валидатора.
|
|
404
|
+
|
|
405
|
+
```js
|
|
406
|
+
dbs.defineModel({
|
|
407
|
+
name: 'user',
|
|
408
|
+
properties: {
|
|
409
|
+
email: {
|
|
410
|
+
type: DataType.STRING,
|
|
411
|
+
validate: 'isEmail',
|
|
412
|
+
},
|
|
413
|
+
},
|
|
414
|
+
});
|
|
415
|
+
```
|
|
376
416
|
|
|
377
|
-
|
|
378
|
-
- `maxLength: number` максимальная длинна строки или массива
|
|
379
|
-
- `regexp: string | RegExp` проверка по регулярному выражению
|
|
417
|
+
Использование глобальных валидаторов в виде массива.
|
|
380
418
|
|
|
381
|
-
|
|
419
|
+
```js
|
|
420
|
+
dbs.defineModel({
|
|
421
|
+
name: 'user',
|
|
422
|
+
properties: {
|
|
423
|
+
email: {
|
|
424
|
+
type: DataType.STRING,
|
|
425
|
+
validate: [
|
|
426
|
+
'isEmail',
|
|
427
|
+
'isLowerCase',
|
|
428
|
+
],
|
|
429
|
+
},
|
|
430
|
+
},
|
|
431
|
+
});
|
|
432
|
+
```
|
|
382
433
|
|
|
383
|
-
|
|
384
|
-
`validate`, который принимает объект с их названиями и настройками.
|
|
434
|
+
Использование глобальных валидаторов с передачей аргументов.
|
|
385
435
|
|
|
386
436
|
```js
|
|
387
437
|
dbs.defineModel({
|
|
@@ -389,46 +439,209 @@ dbs.defineModel({
|
|
|
389
439
|
properties: {
|
|
390
440
|
name: {
|
|
391
441
|
type: DataType.STRING,
|
|
392
|
-
validate: {
|
|
393
|
-
minLength: 2,
|
|
394
|
-
maxLength: 24,
|
|
442
|
+
validate: {
|
|
443
|
+
minLength: 2,
|
|
444
|
+
maxLength: 24,
|
|
445
|
+
regexp: /^[a-zA-Z-']+$/,
|
|
446
|
+
},
|
|
447
|
+
},
|
|
448
|
+
},
|
|
449
|
+
});
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
Глобальные валидаторы без параметров могут принимать любые аргументы.
|
|
453
|
+
|
|
454
|
+
```js
|
|
455
|
+
dbs.defineModel({
|
|
456
|
+
name: 'user',
|
|
457
|
+
properties: {
|
|
458
|
+
email: {
|
|
459
|
+
type: DataType.STRING,
|
|
460
|
+
validate: {
|
|
461
|
+
maxLength: 100,
|
|
462
|
+
// так как валидатор "isEmail" не имеет параметров,
|
|
463
|
+
// его определение допускает передачу любого значения
|
|
464
|
+
// в качестве аргумента
|
|
465
|
+
isEmail: true,
|
|
395
466
|
},
|
|
396
467
|
},
|
|
397
468
|
},
|
|
398
469
|
});
|
|
399
470
|
```
|
|
400
471
|
|
|
401
|
-
###
|
|
472
|
+
### Регистрация глобальных валидаторов
|
|
402
473
|
|
|
403
474
|
Валидатором является функция, в которую передается значение соответствующего
|
|
404
475
|
поля перед записью в базу. Если во время проверки функция возвращает `false`,
|
|
405
476
|
то выбрасывается стандартная ошибка. Подмена стандартной ошибки возможна
|
|
406
|
-
с помощью выброса пользовательской ошибки непосредственно внутри
|
|
477
|
+
с помощью выброса пользовательской ошибки непосредственно внутри проверяющей
|
|
478
|
+
функции.
|
|
407
479
|
|
|
408
|
-
Регистрация
|
|
409
|
-
|
|
410
|
-
|
|
480
|
+
Регистрация глобального валидатора выполняется методом `addValidator` сервиса
|
|
481
|
+
`PropertyValidatorRegistry`, который принимает название валидатора и функцию
|
|
482
|
+
для проверки значения.
|
|
411
483
|
|
|
412
|
-
|
|
484
|
+
**Примеры**
|
|
485
|
+
|
|
486
|
+
Регистрация глобального валидатора для проверки формата UUID.
|
|
413
487
|
|
|
414
488
|
```js
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
489
|
+
import {createError} from 'http-errors';
|
|
490
|
+
import {format} from '@e22m4u/js-format';
|
|
491
|
+
import {Errorf} from '@e22m4u/js-format';
|
|
492
|
+
import {PropertyValidatorRegistry} from '@e22m4u/js-repository';
|
|
493
|
+
|
|
494
|
+
// получение экземпляра сервиса
|
|
495
|
+
const pvr = dbs.get(PropertyValidatorRegistry);
|
|
496
|
+
|
|
497
|
+
// регулярные выражения для разных версий UUID
|
|
498
|
+
const uuidRegex = {
|
|
499
|
+
any: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,
|
|
500
|
+
v4: /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,
|
|
501
|
+
};
|
|
502
|
+
|
|
503
|
+
// регистрация глобального валидатора "isUuid",
|
|
504
|
+
// принимающего объект настроек со свойством "version"
|
|
505
|
+
pvr.addValidator('isUuid', (value, options, context) => {
|
|
506
|
+
// value - проверяемое значение;
|
|
507
|
+
// options - параметры валидатора;
|
|
508
|
+
// context - информация о проверяемом свойстве;
|
|
509
|
+
console.log(options);
|
|
510
|
+
// {
|
|
511
|
+
// version: 'v4'
|
|
512
|
+
// }
|
|
513
|
+
console.log(context);
|
|
514
|
+
// {
|
|
515
|
+
// validatorName: 'isUuid',
|
|
516
|
+
// modelName: 'device',
|
|
517
|
+
// propName: 'deviceId'
|
|
518
|
+
// }
|
|
519
|
+
|
|
520
|
+
// пустые значения не передаются в валидаторы
|
|
521
|
+
// (условие ниже никогда не сработает)
|
|
522
|
+
if (typeof value !== 'string') return false;
|
|
523
|
+
// поиск регулярного выражения для указанной
|
|
524
|
+
// версии UUID (из параметров валидатора)
|
|
525
|
+
const version = options?.version || 'any';
|
|
526
|
+
const regex = uuidRegex[version];
|
|
527
|
+
// если регулярное выражение не найдено,
|
|
528
|
+
// то выбрасывается внутренняя ошибка
|
|
529
|
+
if (!regex)
|
|
530
|
+
throw new Errorf(
|
|
531
|
+
'Invalid UUID version %v specified for validator.',
|
|
532
|
+
version,
|
|
533
|
+
);
|
|
534
|
+
// при неудачной проверке выбрасывается
|
|
535
|
+
// ошибка 400 BadRequest
|
|
536
|
+
if (!regex.test(value)) {
|
|
537
|
+
const versionString = version !== 'any' ? ` (version ${version})` : '';
|
|
538
|
+
throw createError(400, format(
|
|
539
|
+
'The property %v of the model %v must be a valid UUID%s.',
|
|
540
|
+
context.propName,
|
|
541
|
+
context.modelName,
|
|
542
|
+
versionString,
|
|
543
|
+
));
|
|
544
|
+
}
|
|
545
|
+
// при успешной проверке возвращается true,
|
|
546
|
+
// в противном случае выбрасывается стандартная
|
|
547
|
+
// ошибка проверки
|
|
548
|
+
return true;
|
|
549
|
+
});
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
Использование глобального валидатора в определении свойства.
|
|
553
|
+
|
|
554
|
+
```js
|
|
555
|
+
// определение модели "device"
|
|
556
|
+
dbs.defineModel({
|
|
557
|
+
name: 'device',
|
|
558
|
+
properties: {
|
|
559
|
+
deviceId: {
|
|
560
|
+
type: DataType.STRING,
|
|
561
|
+
required: true,
|
|
562
|
+
validate: {
|
|
563
|
+
// значение {version: 'v4'} будет передаваться
|
|
564
|
+
// вторым аргументом в функцию-валидатор
|
|
565
|
+
isUuid: {version: 'v4'},
|
|
566
|
+
},
|
|
567
|
+
},
|
|
568
|
+
},
|
|
569
|
+
});
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
### Локальные валидаторы
|
|
573
|
+
|
|
574
|
+
Функция-валидатор может быть передана непосредственно в определении свойства
|
|
575
|
+
без предварительной регистрации. Для этого достаточно передать функцию
|
|
576
|
+
в параметр `validate` в качестве значения или элемента массива наряду
|
|
577
|
+
с другими валидаторами.
|
|
578
|
+
|
|
579
|
+
**Примеры**
|
|
580
|
+
|
|
581
|
+
Использование локального валидатора для проверки сложности пароля.
|
|
582
|
+
|
|
583
|
+
```js
|
|
584
|
+
// валидатор `passwordStrength` проверяет сложность пароля
|
|
585
|
+
function passwordStrength(value, options, context) {
|
|
586
|
+
// value - проверяемое значение;
|
|
587
|
+
// options - не используется;
|
|
588
|
+
// context - информация о свойстве;
|
|
589
|
+
console.log(context);
|
|
590
|
+
// {
|
|
591
|
+
// validatorName: 'passwordStrength',
|
|
592
|
+
// modelName: 'user',
|
|
593
|
+
// propName: 'password'
|
|
594
|
+
// }
|
|
595
|
+
const errors = [];
|
|
596
|
+
if (value.length < 8)
|
|
597
|
+
errors.push('must be at least 8 characters long');
|
|
598
|
+
if (!/\d/.test(value))
|
|
599
|
+
errors.push('must contain at least one number');
|
|
600
|
+
if (!/[a-zA-Z]/.test(value))
|
|
601
|
+
errors.push('must contain at least one letter');
|
|
602
|
+
// если одно из условий сработало,
|
|
603
|
+
// то выбрасывается ошибка
|
|
604
|
+
if (errors.length > 0)
|
|
605
|
+
throw createError(400, format(
|
|
606
|
+
'Value of the property %v of the model %v %s.',
|
|
607
|
+
context.propName,
|
|
608
|
+
context.modelName,
|
|
609
|
+
errors.join(', '),
|
|
610
|
+
));
|
|
611
|
+
// при успешной проверке возвращается true,
|
|
612
|
+
// в противном случае выбрасывается стандартная
|
|
613
|
+
// ошибка проверки
|
|
614
|
+
return true;
|
|
419
615
|
}
|
|
420
616
|
|
|
421
|
-
//
|
|
422
|
-
dbs.
|
|
617
|
+
// определение модели "user"
|
|
618
|
+
dbs.defineModel({
|
|
619
|
+
name: 'user',
|
|
620
|
+
properties: {
|
|
621
|
+
password: {
|
|
622
|
+
type: DataType.STRING,
|
|
623
|
+
required: true,
|
|
624
|
+
validate: passwordStrength, // <=
|
|
625
|
+
// или
|
|
626
|
+
// validate: [passwordStrength, ...]
|
|
627
|
+
},
|
|
628
|
+
},
|
|
629
|
+
});
|
|
630
|
+
```
|
|
423
631
|
|
|
424
|
-
|
|
425
|
-
|
|
632
|
+
Использование анонимной функции-валидатора для проверки слага.
|
|
633
|
+
|
|
634
|
+
```js
|
|
635
|
+
// определение модели "article"
|
|
426
636
|
dbs.defineModel({
|
|
427
|
-
name: '
|
|
637
|
+
name: 'article',
|
|
428
638
|
properties: {
|
|
429
|
-
|
|
639
|
+
slug: {
|
|
430
640
|
type: DataType.STRING,
|
|
431
|
-
validate:
|
|
641
|
+
validate: (value) => {
|
|
642
|
+
const re = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
643
|
+
return re.test(value);
|
|
644
|
+
},
|
|
432
645
|
},
|
|
433
646
|
},
|
|
434
647
|
});
|
|
@@ -436,39 +649,244 @@ dbs.defineModel({
|
|
|
436
649
|
|
|
437
650
|
## Трансформеры
|
|
438
651
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
652
|
+
Трансформеры используются для модификации значения свойства перед проверкой
|
|
653
|
+
типа и передачей данных в базу. Трансформеры позволяют автоматически очищать
|
|
654
|
+
или приводить данные к нужному формату.
|
|
655
|
+
|
|
656
|
+
### Глобальные трансформеры
|
|
657
|
+
|
|
658
|
+
Модуль поставляется с набором глобальных трансформеров:
|
|
659
|
+
|
|
660
|
+
- `trim` удаление пробельных символов с начала и конца строки;
|
|
661
|
+
- `toUpperCase` перевод строки в верхний регистр;
|
|
662
|
+
- `toLowerCase` перевод строки в нижний регистр;
|
|
663
|
+
|
|
664
|
+
Трансформеры указанные ниже находятся в разработке:
|
|
443
665
|
|
|
444
|
-
- `
|
|
445
|
-
|
|
446
|
-
- `toLowerCase` перевод строки в нижний регистр
|
|
447
|
-
- `toTitleCase` перевод строки в регистр заголовка
|
|
666
|
+
- `cut` усечение строки или массива до указанной длины,
|
|
667
|
+
*параметр: `number` - максимальная длина;*
|
|
448
668
|
|
|
449
|
-
|
|
669
|
+
- `truncate` усечение строки с добавлением троеточия,
|
|
670
|
+
*параметр: `number` - максимальная длина;*
|
|
450
671
|
|
|
451
|
-
|
|
452
|
-
`
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
672
|
+
- `capitalize` перевод первой буквы каждого слова в верхний регистр,
|
|
673
|
+
*параметр: `{firstWordOnly?: boolean}`;*
|
|
674
|
+
|
|
675
|
+
**Примеры**
|
|
676
|
+
|
|
677
|
+
Использование глобального трансформера.
|
|
456
678
|
|
|
457
679
|
```js
|
|
458
680
|
dbs.defineModel({
|
|
459
681
|
name: 'user',
|
|
460
682
|
properties: {
|
|
461
|
-
|
|
683
|
+
username: {
|
|
462
684
|
type: DataType.STRING,
|
|
463
|
-
transform:
|
|
464
|
-
|
|
465
|
-
|
|
685
|
+
transform: 'toLowerCase',
|
|
686
|
+
},
|
|
687
|
+
},
|
|
688
|
+
});
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
Использование глобальных трансформеров в виде массива.
|
|
692
|
+
|
|
693
|
+
```js
|
|
694
|
+
dbs.defineModel({
|
|
695
|
+
name: 'user',
|
|
696
|
+
properties: {
|
|
697
|
+
firstName: {
|
|
698
|
+
type: DataType.STRING,
|
|
699
|
+
transform: [
|
|
700
|
+
'trim',
|
|
701
|
+
'capitalize',
|
|
466
702
|
],
|
|
467
703
|
},
|
|
468
704
|
},
|
|
469
705
|
});
|
|
470
706
|
```
|
|
471
707
|
|
|
708
|
+
Использование глобальных трансформеров с передачей аргументов.
|
|
709
|
+
|
|
710
|
+
```js
|
|
711
|
+
dbs.defineModel({
|
|
712
|
+
name: 'article',
|
|
713
|
+
properties: {
|
|
714
|
+
annotation: {
|
|
715
|
+
type: DataType.STRING,
|
|
716
|
+
transform: {
|
|
717
|
+
truncate: 200,
|
|
718
|
+
capitalize: {firstWordOnly: true},
|
|
719
|
+
},
|
|
720
|
+
},
|
|
721
|
+
},
|
|
722
|
+
});
|
|
723
|
+
```
|
|
724
|
+
|
|
725
|
+
Глобальные трансформеры без параметров могут принимать любые аргументы.
|
|
726
|
+
|
|
727
|
+
```js
|
|
728
|
+
dbs.defineModel({
|
|
729
|
+
name: 'user',
|
|
730
|
+
properties: {
|
|
731
|
+
firstName: {
|
|
732
|
+
type: DataType.STRING,
|
|
733
|
+
transform: {
|
|
734
|
+
cut: 60,
|
|
735
|
+
// так как трансформер "trim" не имеет параметров,
|
|
736
|
+
// его определение допускает передачу любого значения
|
|
737
|
+
// в качестве аргумента
|
|
738
|
+
trim: true,
|
|
739
|
+
},
|
|
740
|
+
},
|
|
741
|
+
},
|
|
742
|
+
});
|
|
743
|
+
```
|
|
744
|
+
|
|
745
|
+
### Регистрация глобальных трансформеров
|
|
746
|
+
|
|
747
|
+
Трансформером является функция, которая принимает значение свойства и возвращает
|
|
748
|
+
новое значение. Функция может быть как синхронной, так и асинхронной (возвращать
|
|
749
|
+
`Promise`).
|
|
750
|
+
|
|
751
|
+
Регистрация глобального трансформера выполняется методом `addTransformer`
|
|
752
|
+
сервиса `PropertyTransformerRegistry`, который принимает название трансформера
|
|
753
|
+
и саму функцию.
|
|
754
|
+
|
|
755
|
+
**Примеры**
|
|
756
|
+
|
|
757
|
+
Регистрация глобального трансформера для удаления HTML-тегов.
|
|
758
|
+
|
|
759
|
+
```js
|
|
760
|
+
import {PropertyTransformerRegistry} from '@e22m4u/js-repository';
|
|
761
|
+
|
|
762
|
+
// получение экземпляра сервиса
|
|
763
|
+
const ptr = dbs.get(PropertyTransformerRegistry);
|
|
764
|
+
|
|
765
|
+
// регистрация глобального трансформера "stripTags"
|
|
766
|
+
ptr.addTransformer('stripTags', (value, options, context) => {
|
|
767
|
+
// value - трансформируемое значение;
|
|
768
|
+
// options - настройки трансформера (если переданы);
|
|
769
|
+
// context - информация о свойстве;
|
|
770
|
+
console.log(context);
|
|
771
|
+
// {
|
|
772
|
+
// transformerName: 'stripTags',
|
|
773
|
+
// modelName: 'comment',
|
|
774
|
+
// propName: 'text'
|
|
775
|
+
// }
|
|
776
|
+
|
|
777
|
+
if (typeof value !== 'string')
|
|
778
|
+
return value; // возвращаем как есть, если не строка
|
|
779
|
+
|
|
780
|
+
return value.replace(/<[^>]*>?/gm, '');
|
|
781
|
+
});
|
|
782
|
+
```
|
|
783
|
+
|
|
784
|
+
Использование глобального трансформера в определении модели.
|
|
785
|
+
|
|
786
|
+
```js
|
|
787
|
+
dbs.defineModel({
|
|
788
|
+
name: 'comment',
|
|
789
|
+
properties: {
|
|
790
|
+
text: {
|
|
791
|
+
type: DataType.STRING,
|
|
792
|
+
transform: 'stripTags',
|
|
793
|
+
},
|
|
794
|
+
},
|
|
795
|
+
});
|
|
796
|
+
```
|
|
797
|
+
|
|
798
|
+
### Локальные трансформеры
|
|
799
|
+
|
|
800
|
+
Функция-трансформер может быть передана непосредственно в определении свойства без предварительной регистрации. Для этого достаточно передать функцию в параметр `transform` в качестве значения или элемента массива.
|
|
801
|
+
|
|
802
|
+
**Примеры**
|
|
803
|
+
|
|
804
|
+
Использование локального трансформера для нормализации имен.
|
|
805
|
+
|
|
806
|
+
```js
|
|
807
|
+
// функция для нормализации имени
|
|
808
|
+
function normalizeName(value, options, context) {
|
|
809
|
+
// value - трансформируемое значение
|
|
810
|
+
// options - не используется
|
|
811
|
+
// context - информация о свойстве
|
|
812
|
+
if (!value || typeof value !== 'string') return value;
|
|
813
|
+
return value
|
|
814
|
+
.trim() // удаление пробелов в начале и конце
|
|
815
|
+
.toLowerCase() // перевод к нижнему регистру
|
|
816
|
+
.split(' ') // разделение на слова
|
|
817
|
+
// перевод к верхнему регистру первой буквы каждого слова
|
|
818
|
+
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
|
819
|
+
.join(' '); // сборка массива в строку
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
// определение модели "user"
|
|
823
|
+
dbs.defineModel({
|
|
824
|
+
name: 'user',
|
|
825
|
+
properties: {
|
|
826
|
+
firstName: {
|
|
827
|
+
type: DataType.STRING,
|
|
828
|
+
transform: normalizeName, // <=
|
|
829
|
+
},
|
|
830
|
+
lastName: {
|
|
831
|
+
type: DataType.STRING,
|
|
832
|
+
transform: normalizeName, // <=
|
|
833
|
+
},
|
|
834
|
+
},
|
|
835
|
+
});
|
|
836
|
+
```
|
|
837
|
+
|
|
838
|
+
Использование локального асинхронного трансформера для хэширования пароля.
|
|
839
|
+
|
|
840
|
+
```js
|
|
841
|
+
import * as bcrypt from 'bcrypt';
|
|
842
|
+
|
|
843
|
+
// асинхронная функция для хеширования значения
|
|
844
|
+
async function hash(value, options, context) {
|
|
845
|
+
// value - трансформируемое значение
|
|
846
|
+
// options - не используется
|
|
847
|
+
// context - информация о свойстве
|
|
848
|
+
console.log(context);
|
|
849
|
+
// {
|
|
850
|
+
// transformerName: 'hash',
|
|
851
|
+
// modelName: 'user',
|
|
852
|
+
// propName: 'password'
|
|
853
|
+
// }
|
|
854
|
+
const saltRounds = 10;
|
|
855
|
+
return bcrypt.hash(value, saltRounds);
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
// определение модели "user"
|
|
859
|
+
dbs.defineModel({
|
|
860
|
+
name: 'user',
|
|
861
|
+
properties: {
|
|
862
|
+
password: {
|
|
863
|
+
type: DataType.STRING,
|
|
864
|
+
transform: hash, // <=
|
|
865
|
+
// или
|
|
866
|
+
// transform: [hash, ...]
|
|
867
|
+
},
|
|
868
|
+
},
|
|
869
|
+
});
|
|
870
|
+
```
|
|
871
|
+
|
|
872
|
+
Использование анонимной функции-трансформера для коррекции слага.
|
|
873
|
+
|
|
874
|
+
```js
|
|
875
|
+
dbs.defineModel({
|
|
876
|
+
name: 'article',
|
|
877
|
+
properties: {
|
|
878
|
+
slug: {
|
|
879
|
+
type: DataType.STRING,
|
|
880
|
+
transform: (value) => {
|
|
881
|
+
if (typeof value !== 'string') return value;
|
|
882
|
+
return value.toLowerCase().replace(/\s+/g, '-');
|
|
883
|
+
},
|
|
884
|
+
},
|
|
885
|
+
},
|
|
886
|
+
});
|
|
887
|
+
```
|
|
888
|
+
|
|
889
|
+
|
|
472
890
|
## Пустые значения
|
|
473
891
|
|
|
474
892
|
Разные типы свойств имеют свои наборы пустых значений. Эти наборы
|
|
@@ -924,7 +1342,7 @@ dbs.defineModel({
|
|
|
924
1342
|
name: 'city',
|
|
925
1343
|
datasource: 'myDatasource',
|
|
926
1344
|
properties: {
|
|
927
|
-
|
|
1345
|
+
name: DataType.STRING,
|
|
928
1346
|
timeZone: DataType.STRING,
|
|
929
1347
|
},
|
|
930
1348
|
relations: {
|
|
@@ -938,7 +1356,7 @@ dbs.defineModel({
|
|
|
938
1356
|
// определение интерфейса "city"
|
|
939
1357
|
interface City {
|
|
940
1358
|
id: number;
|
|
941
|
-
|
|
1359
|
+
name?: string;
|
|
942
1360
|
timeZone?: string;
|
|
943
1361
|
countryId?: number;
|
|
944
1362
|
country?: Country;
|