class-validator icon indicating copy to clipboard operation
class-validator copied to clipboard

feat: support multi-dimensional arrays

Open Eldar-X opened this issue 4 years ago • 7 comments

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[][];
}

Eldar-X avatar Mar 01 '20 16:03 Eldar-X

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

jBouyoud avatar Mar 03 '20 06:03 jBouyoud

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[][][][][];

vlapo avatar Mar 28 '20 21:03 vlapo

Maybe we should add an option maxDepth for this?

Eldar-X avatar Mar 28 '20 21:03 Eldar-X

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?

Timtam avatar Jun 16 '21 21:06 Timtam

mark

UNDERCOVERj avatar Dec 16 '21 09:12 UNDERCOVERj

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)

mainakchhari avatar Jan 09 '22 07:01 mainakchhari

Simple custom decorator example below.

This validates that the property:

  1. is an array
  2. each element is also an array
  3. each sub array has 3 entries
  4. 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')
              );
            })
          );
        },
      },
    });
  };
}

jjh-reciprocity avatar Sep 06 '22 17:09 jjh-reciprocity