feat: support multi-dimensional arrays
Hello, I am trying to validate the arrays in arrays but I could not find a correct method.
The structure looks like this:
class MyInnerDto {
@IsString()
name: string;
}
class TestDto {
@IsArray({ each: true })
myArray:MyInnerDto[][];
}
Hello,
I've the same kind of issue with Map and Array values.
The test case below show validation error on nestedMap but not on nestedWithArray.
Is there another tips to validate this kind of structure ? or it's a bug ?
With class-validator": "0.11.0"
import { IsString, ValidateNested, Validator } from 'class-validator';
describe('NestedValidation', () => {
class NestedClass {
@IsString()
name: string;
constructor(name: any) {
this.name = name;
}
}
class MasterClass {
@ValidateNested({ each: true })
nestedMap: Map<string, NestedClass>;
@ValidateNested({ each: true })
nestedWithArray: Map<string, NestedClass[]>;
constructor(
nestedMap: Map<string, NestedClass>,
nestedWithArray: Map<string, NestedClass[]>,
) {
this.nestedMap = nestedMap;
this.nestedWithArray = nestedWithArray;
}
}
describe('validation', () => {
let validator: Validator;
beforeAll(() => {
validator = new Validator();
});
it('should validate nested object array', async () => {
const nestedMap = new Map<string, NestedClass>();
nestedMap.set('test', new NestedClass(42));
const nestedMapWithArray = new Map<string, NestedClass[]>();
nestedMapWithArray.set('test', [new NestedClass(42)]);
const masterClass = new MasterClass(nestedMap, nestedMapWithArray);
const errors = await validator.validate(masterClass);
function expectNestedError(property: string) {
const nestedError = errors.find(error => error.property === property);
expect(nestedError).toBeDefined();
expect(nestedError).toMatchObject({ property, target: masterClass, });
}
expectNestedError('nestedMap');
expectNestedError('nestedWithArray');
});
});
});
Thanks
https://github.com/typestack/class-validator/pull/539 fixed multi-dimensional arrays for @ValidatedNested. But we should also support multi-dimensional arrays for cases like:
@IsNumber({}, {
each: true
})
tags: number[][];
Note: I see one edge case here. What if I want to validate only first, second, third, ..., ... level of multi-dimensional array? E.g.:
@IsArray({}, {
each: true
})
@IsNumber({ each: true })
tags: number[][][][][];
Maybe we should add an option maxDepth for this?
whats the status on the situation here? I'm facing a simple 2d numeric array validation issue here and this issue is on hold for over a year now because of a rather rare edge case whilst simple multi-dimensional array checks are already possible but not yet merged. Any way to get into this again?
mark
Any word on this? Can anyone suggest a workaround using custom validators that can do the needful? I need to validate multi dimensional arrays of various types, ie. enums, strings, numbers, objectids (mongodb)
Simple custom decorator example below.
This validates that the property:
- is an array
- each element is also an array
- each sub array has 3 entries
- each sub entry is a string
You can tweak this for your needs
import { registerDecorator } from 'class-validator';
export function PermissionsValidator() {
// eslint-disable-next-line @typescript-eslint/ban-types
return function (object: Object, propertyName: string) {
registerDecorator({
name: 'permissions',
target: object.constructor,
propertyName: propertyName,
validator: {
validate(value: unknown) {
return (
Array.isArray(value) &&
value.length > 0 &&
value.every((row) => {
return (
Array.isArray(row) &&
row.length === 3 &&
row.every((cell) => typeof cell === 'string')
);
})
);
},
},
});
};
}