Skip to content
Open

#93 #33

Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 22 additions & 8 deletions src/infrastructure/decorators/fields/BaseField.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {applyDecorators} from '@nestjs/common';
import {ApiProperty} from '@nestjs/swagger';
import {ColumnType} from '@steroidsjs/typeorm/driver/types/ColumnTypes';
import {IsNotEmpty, isString} from 'class-validator';
import {IsArray, IsDefined, IsOptional, isString, NotEquals, ValidateIf} from 'class-validator';
import {IAllFieldOptions} from './index';
import {ITransformCallback, Transform} from '../Transform';

Expand Down Expand Up @@ -155,6 +155,19 @@ export const getFieldDecorator = (targetClass, fieldName: string): (...args: any
return decorator;
};

const getRequiredNullableValidators = ({required, nullable}: IBaseFieldOptions, isArray: boolean) => [
required && nullable && NotEquals(undefined),
required && !nullable && IsDefined(),
!required && nullable && IsOptional(),
!required && !nullable && NotEquals(null),
...((isArray && [
required && nullable && ValidateIf((object, value) => value !== null),
!required && nullable && ValidateIf((object, value) => value !== null && value !== undefined),
!required && !nullable && ValidateIf((object, value) => value !== undefined),
IsArray(),
]) || []),
].filter(Boolean);

const ColumnMetaDecorator = (options: IBaseFieldOptions, internalOptions: IInternalFieldOptions) => (object, propertyName) => {
//проверить getOwnMetadata
Reflect.defineMetadata(STEROIDS_META_FIELD, options, object, propertyName);
Expand All @@ -166,28 +179,29 @@ const ColumnMetaDecorator = (options: IBaseFieldOptions, internalOptions: IInter
};

export function BaseField(options: IBaseFieldOptions = null, internalOptions: IInternalFieldOptions = {}) {
const isArray = typeof options.isArray === 'boolean'
? options.isArray
: (internalOptions.isArray || null);

return applyDecorators(
...[
ColumnMetaDecorator({
label: null,
hint: null,
...options,
isArray: typeof options.isArray === 'boolean'
? options.isArray
: (internalOptions.isArray || null),
isArray,
appType: internalOptions.appType || null,
}, internalOptions),
ApiProperty({
type: options.jsType || internalOptions.swaggerType || internalOptions.jsType,
description: options.label || undefined,
example: options.example || undefined,
required: options.nullable === false,
required: options.required,
nullable: options.nullable,
isArray: options.isArray || internalOptions.isArray,
}),
options.transform && Transform(options.transform),
options.required && IsNotEmpty({
message: 'Обязательно для заполнения',
}),
...getRequiredNullableValidators(options, isArray),
].filter(Boolean),
);
}
3 changes: 1 addition & 2 deletions src/infrastructure/decorators/fields/BooleanField.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {applyDecorators} from '@nestjs/common';
import {IsBoolean, IsOptional} from 'class-validator';
import {IsBoolean} from 'class-validator';
import {BaseField, IBaseFieldOptions} from './BaseField';
import {Transform} from '../Transform';

Expand All @@ -23,6 +23,5 @@ export function BooleanField(options: IBaseFieldOptions = {}) {
IsBoolean({
message: 'Должен быть булевом',
}),
IsOptional(),
);
}
3 changes: 1 addition & 2 deletions src/infrastructure/decorators/fields/CoordinateField.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {applyDecorators} from '@nestjs/common';
import {IsString, ValidateIf} from 'class-validator';
import {IsString} from 'class-validator';
import {BaseField, IBaseFieldOptions} from './BaseField';

export interface ICoordinateFieldOptions extends IBaseFieldOptions {
Expand All @@ -15,7 +15,6 @@ export function CoordinateField(options: ICoordinateFieldOptions = {}) {
appType: 'decimal',
jsType: 'number',
}),
options.nullable && ValidateIf((object, value) => value !== null),
IsString(),
].filter(Boolean)
);
Expand Down
3 changes: 1 addition & 2 deletions src/infrastructure/decorators/fields/DateField.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {applyDecorators} from '@nestjs/common';
import {IsISO8601, ValidateIf, ValidationArguments} from 'class-validator';
import {IsISO8601, ValidationArguments} from 'class-validator';
import {formatISO9075, parseISO} from 'date-fns';
import {BaseField, IBaseFieldOptions} from './BaseField';
import {Transform, TRANSFORM_TYPE_FROM_DB, TRANSFORM_TYPE_TO_DB} from '../Transform';
Expand Down Expand Up @@ -46,7 +46,6 @@ export function DateField(options: IDateFieldOptions = {}) {
}),
Transform(({value}) => normalizeDate(value), TRANSFORM_TYPE_FROM_DB),
Transform(({value}) => normalizeDate(value), TRANSFORM_TYPE_TO_DB),
options.nullable && ValidateIf((object, value) => value),
options.minDate && MinDate(options.minDate, {
each: options.isArray,
message: (args) => `Выбрана дата раньше минимально допустимой (${normalizeFunctionDate(options.minDate, args)})`,
Expand Down
3 changes: 1 addition & 2 deletions src/infrastructure/decorators/fields/DecimalField.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {applyDecorators} from '@nestjs/common';
import {IsDecimal, ValidateBy, ValidateIf, ValidationOptions} from 'class-validator';
import {IsDecimal, ValidateBy, ValidationOptions} from 'class-validator';
import {BaseField, IBaseFieldOptions} from './BaseField';

export interface IDecimalFieldOptions extends IBaseFieldOptions {
Expand Down Expand Up @@ -54,7 +54,6 @@ export function DecimalField(options: IDecimalFieldOptions = {}) {
appType: 'decimal',
jsType: 'number',
}),
options.nullable && ValidateIf((object, value) => value !== null && typeof value !== 'undefined'),
IsDecimal({
decimal_digits: String(options.scale || 2),
}, {
Expand Down
3 changes: 1 addition & 2 deletions src/infrastructure/decorators/fields/DecimalNumberField.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {applyDecorators} from '@nestjs/common';
import {Max, Min, ValidateIf, ValidateBy, ValidationOptions, buildMessage, isDecimal} from 'class-validator';
import {Max, Min, ValidateBy, ValidationOptions, buildMessage, isDecimal} from 'class-validator';

import {IDecimalFieldOptions} from './DecimalField';
import {BaseField} from './BaseField';
Expand Down Expand Up @@ -43,7 +43,6 @@ export function DecimalNumberField(options: IDecimalFieldOptions = {}) {
jsType: 'number',
}),
Transform(({value}) => value ? Number(value) : value, TRANSFORM_TYPE_FROM_DB),
options.nullable && ValidateIf((object, value) => value !== null && typeof value !== 'undefined'),
IsDecimalNumber(options, {
message: options.isDecimalConstraintMessage || 'Должно быть числом',
}),
Expand Down
3 changes: 1 addition & 2 deletions src/infrastructure/decorators/fields/EmailField.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {applyDecorators} from '@nestjs/common';
import {IsEmail, ValidateIf} from 'class-validator';
import {IsEmail} from 'class-validator';
import {BaseField, IBaseFieldOptions} from './BaseField';

export interface IEmailFieldOptions extends IBaseFieldOptions {
Expand All @@ -17,7 +17,6 @@ export function EmailField(options: IEmailFieldOptions = {}) {
appType: 'email',
jsType: 'string',
}),
options.nullable && ValidateIf((object, value) => value !== null && typeof value !== 'undefined'),
IsEmail({
allow_display_name: true,
}, {
Expand Down
3 changes: 1 addition & 2 deletions src/infrastructure/decorators/fields/EnumField.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {applyDecorators} from '@nestjs/common';
import {IsEnum, ValidateIf} from 'class-validator';
import {IsEnum} from 'class-validator';
import {ApiProperty} from '@nestjs/swagger';
import {BaseField, IBaseFieldOptions} from './BaseField';
import BaseEnum from '../../../domain/base/BaseEnum';
Expand Down Expand Up @@ -35,7 +35,6 @@ export function EnumField(options: IEnumFieldOptions = {}) {
ApiProperty({
enum: options.enum,
}),
options.nullable && ValidateIf((object, value) => value !== null && typeof value !== 'undefined'),
IsEnum(options.enum, {
each: options.isArray,
message: options.isEnumConstraintMessage || 'Выберите одно из значений',
Expand Down
3 changes: 1 addition & 2 deletions src/infrastructure/decorators/fields/FileField.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {applyDecorators} from '@nestjs/common';
import {IsArray, IsInt, ValidateIf} from 'class-validator';
import {IsArray, IsInt} from 'class-validator';
import {BaseField, IBaseFieldOptions} from './BaseField';

export interface IFileField extends IBaseFieldOptions {
Expand All @@ -14,7 +14,6 @@ export function getFileFieldDecorators(options: IFileField) {
appType: 'file',
jsType: 'number',
}),
options.nullable && ValidateIf((object, value) => value),
options.multiple
? IsArray({
message: options.isImage ? 'Необходимо загрузить изображения' : 'Необходимо загрузить файлы',
Expand Down
2 changes: 1 addition & 1 deletion src/infrastructure/decorators/fields/IntegerField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export function IntegerField(options: IIntegerFieldOptions = {}) {
appType: 'integer',
jsType: 'number',
}),
options.nullable && ValidateIf((object, value) => options.isArray ? !isArrayEmpty(value) : !isEmpty(value)),
!options.required && ValidateIf((object, value) => options.isArray ? !isArrayEmpty(value) : !isEmpty(value)),
Transform(({value}) => {
if (Array.isArray(value)) {
return value.map(valueItem => !isEmpty(valueItem) ? _toInteger(valueItem) : null);
Expand Down
2 changes: 0 additions & 2 deletions src/infrastructure/decorators/fields/JSONBField.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {applyDecorators} from '@nestjs/common';
import {IsOptional} from 'class-validator';
import {BaseField, IBaseFieldOptions} from './BaseField';

export type IJSONBFieldOptions = IBaseFieldOptions
Expand All @@ -11,6 +10,5 @@ export function JSONBField(options: IJSONBFieldOptions = {}) {
appType: 'object',
jsType: 'jsonb',
}),
!options.required && IsOptional(),
].filter(Boolean));
}
3 changes: 1 addition & 2 deletions src/infrastructure/decorators/fields/PhoneField.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {applyDecorators} from '@nestjs/common';
import {IsPhoneNumber, ValidateIf} from 'class-validator';
import {IsPhoneNumber} from 'class-validator';
import {BaseField, IBaseFieldOptions} from './BaseField';
import {Transform} from '../Transform';

Expand Down Expand Up @@ -28,7 +28,6 @@ export function PhoneField(options: IPhoneFieldOptions = {}) {
appType: 'phone',
jsType: 'string',
}),
options.nullable && ValidateIf((object, value) => value),
Transform(({value}) => normalizePhone(value)),
IsPhoneNumber(null, {
message: options.constraintMessage || 'Некорректный номер телефона',
Expand Down
1 change: 0 additions & 1 deletion src/infrastructure/decorators/fields/RelationField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ export function RelationField(options: IRelationFieldOptions) {
isArray: ['ManyToMany', 'OneToMany'].includes(options.type),
}),
//options.type === 'ManyToOne' && JoinColumn(),
ValidateIf((object, value) => !!value),
ValidateNested({each: true}),
Type(options.relationClass),
Transform(relationTransformFromDb, TRANSFORM_TYPE_FROM_DB),
Expand Down
7 changes: 1 addition & 6 deletions src/infrastructure/decorators/fields/RelationIdField.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {applyDecorators} from '@nestjs/common';
import {ArrayNotEmpty, ValidateIf} from 'class-validator';
import {isEmpty as _isEmpty, isBoolean as _isBoolean} from 'lodash';
import {isBoolean as _isBoolean} from 'lodash';
import {BaseField, getFieldOptions, getMetaPrimaryKey, IBaseFieldOptions} from './BaseField';
import {Transform, TRANSFORM_TYPE_FROM_DB, TRANSFORM_TYPE_TO_DB} from '../Transform';
import {getTableFromModel} from '../../base/ModelTableStorage';
Expand Down Expand Up @@ -54,17 +53,13 @@ export function RelationIdField(options: IRelationIdFieldOptions = {}) {
options.nullable = true;
}

const arrayNotEmptyMessage = options.isFieldValidConstraintMessage || 'Не должно быть пустым';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Я правильно понимаю что этот текст ошибки нигде не будет выводиться?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Да

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

То есть мы теряем часть бизнес-логики при таком изменении? Чем она будет замещаться?

А если эта логика лишняя, то прошу пояснить почему именно.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Выше ответил + я не понимаю, почему свойство options.isFieldValidConstraintMessage отвечает именно за текст ошибки при пустом массиве и находится только в RelationIdField

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

я не понимаю, почему свойство options.isFieldValidConstraintMessage отвечает именно за текст ошибки при пустом массиве и находится только в RelationIdField

Думаю стоит найти ответ на этот вопрос, в чатах или на мите.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

почему свойство options.isFieldValidConstraintMessage отвечает именно за текст ошибки при пустом массиве и находится только в RelationIdField

Получилось найти ответ на этот вопрос?


return applyDecorators(
...[
BaseField(options, {
decoratorName: 'RelationIdField',
appType: 'relationId',
jsType: 'number',
}),
options.nullable && ValidateIf((object, value) => !_isEmpty(value)),
options.isArray && !options.nullable && ArrayNotEmpty({message: arrayNotEmptyMessage}),
Transform(relationTransformFromDb, TRANSFORM_TYPE_FROM_DB),
Transform(relationTransformToDb, TRANSFORM_TYPE_TO_DB),
].filter(Boolean),
Expand Down
3 changes: 1 addition & 2 deletions src/infrastructure/decorators/fields/StringField.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {applyDecorators} from '@nestjs/common';
import {toInteger as _toInteger} from 'lodash';
import {IsOptional, IsString, MaxLength, MinLength} from 'class-validator';
import {IsString, MaxLength, MinLength} from 'class-validator';
import {BaseField, IBaseFieldOptions} from './BaseField';

export interface IStringFieldOptions extends IBaseFieldOptions {
Expand All @@ -23,7 +23,6 @@ export function StringField(options: IStringFieldOptions = {}) {
each: options.isArray,
message: options.isStringConstraintMessage || 'Должна быть строка',
}),
!options.required && IsOptional(), // TODO check nullable and required
typeof options.min === 'number' && MinLength(options.min, {
message: options.minConstraintMessage,
each: options.isArray,
Expand Down
3 changes: 1 addition & 2 deletions src/infrastructure/decorators/fields/TextField.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {applyDecorators} from '@nestjs/common';
import {toInteger as _toInteger} from 'lodash';
import {IsOptional, IsString, MaxLength, MinLength} from 'class-validator';
import {IsString, MaxLength, MinLength} from 'class-validator';
import {BaseField, IBaseFieldOptions} from './BaseField';

export interface ITextFieldOptions extends IBaseFieldOptions {
Expand All @@ -20,7 +20,6 @@ export function TextField(options: ITextFieldOptions = {}) {
each: options.isArray,
message: options.isStringConstraintMessage || 'Должна быть строка',
}),
!options.required && IsOptional(),
typeof options.min === 'number' && MinLength(options.min, {
message: `Длина строка должна быть не менее ${options.min}` || options.minConstraintMessage,
each: options.isArray,
Expand Down
3 changes: 1 addition & 2 deletions src/infrastructure/decorators/fields/TimeField.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {applyDecorators} from '@nestjs/common';
import {IsMilitaryTime, ValidateIf} from 'class-validator';
import {IsMilitaryTime} from 'class-validator';
import {BaseField, IBaseFieldOptions} from './BaseField';

export function TimeField(options: IBaseFieldOptions = {}) {
Expand All @@ -10,7 +10,6 @@ export function TimeField(options: IBaseFieldOptions = {}) {
appType: 'time',
jsType: 'string',
}),
options?.nullable && ValidateIf((object, value) => value !== null),
IsMilitaryTime({
message: 'Время необходимо ввести в формате часы:минуты, например 07:32',
}),
Expand Down
3 changes: 1 addition & 2 deletions src/infrastructure/decorators/fields/UpdateTimeField.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {applyDecorators} from '@nestjs/common';
import {IsOptional, IsString} from 'class-validator';
import {IsString} from 'class-validator';
import {BaseField, IBaseFieldOptions} from './BaseField';
import {normalizeDateTime} from './DateTimeField';
import {Transform, TRANSFORM_TYPE_FROM_DB, TRANSFORM_TYPE_TO_DB} from '../Transform';
Expand All @@ -21,7 +21,6 @@ export function UpdateTimeField(options: IUpdateTimeFieldOptions = {}) {
}),
Transform(({value}) => normalizeDateTime(value, false), TRANSFORM_TYPE_FROM_DB),
Transform(() => normalizeDateTime(new Date(), false), TRANSFORM_TYPE_TO_DB),
IsOptional(),
IsString(),
);
}