New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
question: validate objects as if they're maps #1378
Comments
Well, by the looks of this, what I initially proposed won't work. class-validator/src/validation/ValidationExecutor.ts Lines 346 to 355 in 615931e
Because a plain objects are just What about extending the definition of In export interface ValidationOptions {
/**
* Indicates that an object is to be considered a plain record.
*
* For an object-valued property marked as plain, the object the property holds may neither
* be specifically class-typed nor validated, but all of the child values of said object MUST be.
* Effectively, this declares a "plain record", which will be validated the same way any other
* JavaScript collection does (Array, Map, Set, etc).
* The default is `false`; that is, an object-value must be an instance of a class.
*/
plain?: boolean;
} Then, in ValidationExecutor.ts we can introduce a different code path for when a property is plain-typed: export class ValidationExecutor {
// Not changed
// ...
private nestedValidations(value: any, metadatas: ValidationMetadata[], errors: ValidationError[]): void {
// Not changed
// ...
// At line 346
if (value instanceof Array || value instanceof Set || value instanceof Map) {
// Not changed
// ...
} else if (value instanceof Object) {
if (metadata.validationOptions.plain) {
// Here, we do essentially what would be done with a Map-typed property
Object.values(value).forEach((subValue: any, index: any) => {
this.performValidations(value, subValue, index.toString(), [], metadatas, errors);
});
} else {
const targetSchema = typeof metadata.target === 'string' ? metadata.target : metadata.target.name;
this.execute(value, targetSchema, errors);
}
} else {
// Not changed
// ...
}
});
} I suggest this change because it's not easy to map this "map" concept in terms of classes. The idiom |
Hi, here is my solution with constraint import {
ValidatorConstraint,
ValidatorConstraintInterface,
validate,
ValidationArguments,
ValidationError,
} from 'class-validator';
import {
ClassConstructor,
plainToClass,
} from 'class-transformer';
@ValidatorConstraint({ async: true })
export class RecordValidator<T extends Record<string, unknown>> implements ValidatorConstraintInterface {
validationErrors: ValidationError[][] = [];
async validate(record: Record<string, T>, validationArguments: ValidationArguments) {
const ClassTransformer = validationArguments.constraints?.[0] as ClassConstructor<T>;
if (!ClassTransformer) {
return false;
}
const values = Object.values(record);
this.validationErrors = await Promise.all(values.map((value) => {
const transformedValue = plainToClass(ClassTransformer, value);
return validate(transformedValue);
}));
return this.validationErrors.every((validationError) => isEmpty(validationError));
}
defaultMessage() {
return this.validationErrors.map(
(errors) => errors.reduce(
(acc, error) => error.constraints ? [...acc, ...Object.values(error.constraints)] : acc,
[],
).join(', '),
).join(', ');
}
} And usage like this: class ButtonDto {
@IsString()
id: sting;
@IsOptional()
@IsString()
name?: string;
}
export class SomeDto {
@Validate(RecordValidator, [ButtonDto])
buttons: Record<string, ButtonDto>;
} |
I was trying to...
Validate objects as if they're maps.
For the same reasons discussed in #447 (i.e. lack of
Map
in my specific environment).The problem:
Based on one of the examples in the original issue (#447). Would this work?
Also, if anyone knows (and I know this is
class-transformer
stuff), and considering I do useclass-transformer
to instantiate the whole plain object into a class instance: does the@Type
there properly converts all object values to their correspondingB
instances? (As I understand, being an instance of a class is a precondition for validation (including nested validation) to work)Another example (based on the previous, to clarify my use case):
The text was updated successfully, but these errors were encountered: