typeorm - typescript - class validator - validar com base em tipo diferente
Estou trabalhando com TypeORM e gostaria de fornecer diferentes valores para um campo com base no valor de outro campo. Para explicar, aqui está como meu modelo DTO se parece:
import { IsString, IsOptional, IsNumber, IsEnum, IsObject, IsBoolean, ValidateNested } from 'class-validator';
export enum AttributeTypes {
DATE = 'DATE',
TIME = 'TIME',
NUMBERS = 'NUMBERS',
}
export class BaseValidation {
@IsOptional()
@IsBoolean()
required: boolean;
}
export class modelCreate {
@IsOptional()
@IsNumber()
id: number;
@IsOptional()
@IsString()
label: string;
@IsOptional()
@IsEnum(AttributeTypes)
type: AttributeTypes;
@IsOptional()
@IsObject()
@ValidateNested()
validation: BaseValidation;
}
O problema aqui é que eu tenho este campo: validation em modelCreate, & esse campo é um objeto e pode ter várias propriedades & pode se parecer com isto no banco de dados:
validation: {
required: true,
text: 2
}
ou pode parecer assim:
validation: {
required: false,
number: 1,
maxNumber: 10
}
e isso dependeria da propriedade type de modelCreate, porque se o type for 'TIME', eu gostaria de ter validação para isso:
BaseValidation {
@IsBoolean()
required: true,
@IsString()
text: 2
}
e se o tipo for 'NÚMEROS', eu gostaria de ter uma validação assim
BaseValidation {
@IsBoolean()
required: boolean,
@IsNumber()
number: number,
@IsNumber()
maxNumber: number
}
Então a questão é como eu alteraria diferentes classes em um campo de validação com base no valor do campo tipo no class validator, e isso é realmente possível?
Resposta #1
para isso você precisa criar 2 classes, para cada caso, string e números. Então mude o tipo validation: StringBaseValidation | NumberBaseValidation; agora o class-validator pode diferenciar os casos.
Se os dados vêm de uma solicitação, você precisa usar @Type((obj) => obj.writeConditionToDetectString ? StringBaseValidation : NumberBaseValidation) para ajudar a biblioteca a entender de qual tipo são os dados da solicitação.
Resposta #2
Você deve ter um campo discriminativo, para permitir que o class-transformer identifique o tipo a ser convertido e usado na validação. O mesmo pode ser feito com objetos de array aninhados. No seu caso, você pode usar o campo "required".
No exemplo abaixo, se a propriedade required for igual a true, então usamos a classe A; por outro lado, se a propriedade required for igual a false, a classe a ser usada é B.
Na propriedade discriminator você deve definir um campo a ser usado para identificar as diferentes formas polimórficas dos objetos aninhados. O subTypes.[].value é a classe a ser usada na validação e o subTypes.[].name é o valor que o campo discriminator deve ter para assumir a classe adicionada no campo subTypes.[].name.
import { Type } from 'class-transformer';
import { IsBoolean, IsNumber, IsString, ValidateNested } from 'class-validator';
class Discriminator {
@IsBoolean()
required: boolean;
}
class A extends Discriminator {
@IsString()
text: string;
}
class B extends Discriminator {
@IsNumber()
number: number;
@IsNumber()
maxNumber: number
}
export class C {
// Other fields...
@ValidateNested()
@Type(() => Discriminator, {
discriminator: {
property: 'required',
subTypes: [
{ value: A, name: true as unknown as string },
{ value: B, name: false as unknown as string },
],
},
keepDiscriminatorProperty: true,
})
validation: A | B;
}
Agora seu controlador deve se parecer com isto:
@Controller()
export class AppController {
@Post()
public example(
@Body(new ValidationPipe({ transform: true }))
body: C,
) {
return body;
}
}
E você pode fazer seus pedidos:
curl --location 'localhost:3000/' \
--header 'Content-Type: application/json' \
--data '{
"validation": {
"required": true,
"text": "Some text..."
}
}'
Se você alterar o segundo elemento da propriedade required para false, então você verá um erro:
{
- "required": true,
+ "required": false,
"text": "Some text..."
}
{
"statusCode": 400,
"message": [
"validation.number must be a number conforming to the specified constraints",
"validation.maxNumber must be a number conforming to the specified constraints"
],
"error": "Bad Request"
}
Referências: https://github.com/typestack/class-transformer#providing-more-than-one-type-option
