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

How to validate 2d arrays?

Open aliu-bsm opened this issue 6 years ago • 4 comments

Hello,

I have something like this

@Type is from class-transformer. I tried to search for the issues but I could not find anything.

export class Child {
  @IsDefined()
  @IsString()
  @IsNotEmpty()
  name: string;
}

export class Parent {
  @IsArray()
  @IsNotEmpty()
  @Type((type) => Child)
  @ValidateNested()
  children: Child[][];
}

const parent = new Parent();
let res;
// I need `as any` because I'm using strictNullChecks
parent.children= 123 as any; 
res = validateSync(parent); // this fails

parent.children= [] as any; 
res = validateSync(parent); // this passes

parent.children= [[]] as any; 
res = validateSync(parent); // this passes

parent.children= [[ { name: null } ]] as any;
res = validateSync(parent);  // this passes

Even if the type Child is changed to JS native types like number or string. How can I validate something like this?

aliu-bsm avatar Oct 04 '19 23:10 aliu-bsm

Currently we do not have support for multidimensional arrays. You have to create your own custom validator.

vlapo avatar Oct 15 '19 09:10 vlapo

Currently we do not have support for multidimensional arrays. You have to create your own custom validator.

Not really sure how that would work, can you point us in the right direction here?

MarkMurphy avatar Jan 19 '21 19:01 MarkMurphy

Here's my take on this, @MarkMurphy and @drewwiens

import { IsString, Validate, validate } from 'class-validator';

export class Student {
  @IsString()
  name: string;
}

/** Validates an array of students */
async function validateStudentArray(input: Student[]): Promise<boolean> {
  const validityArray = await Promise.all(
    input.map(async student => {
      const errors = await validate(student); // you could also use validate('Student', student);

      if (errors.length === 0) {
        return true;
      } else {
        return false;
      }
    }),
  );

  const result = validityArray.reduce<boolean>(
    (isValid, currentValue) => isValid && currentValue,
    true,
  );

  return result;
}

export class School {
  @Validate(validateStudentArray, { each: true })
  nestedStudents: Student[][];
}

I'm sure some generalization could be done here

braaar avatar Aug 30 '22 08:08 braaar

By following the doc, the correct custom validation class should implement ValidatorConstraintInterface. Here is an example, I had to validate a 2D GPS coordinates.

import {
  ValidatorConstraint,
  ValidatorConstraintInterface,
} from 'class-validator';

function between(value: number, min: number, max: number) {
  return min <= value && value <= max;
}

@ValidatorConstraint({ name: 'IsLatitudeLongitude', async: false })
export class IsLatitudeLongitude implements ValidatorConstraintInterface {
  errors: string[] = [];
  async validate(values: number[]) {
    this.errors = [];
    const long = values[0];
    const lat = values[1];

    if (values.length !== 2)
      this.errors.push(
        `coordinates ${values} should contain a longitude and a latitude`,
      );
    if (typeof long !== 'number')
      this.errors.push(`longitude ${long} should be a number`);
    if (typeof lat !== 'number')
      this.errors.push(`latitude ${lat} should be a number`);
    if (!between(long, -180, 180))
      this.errors.push(`longitude ${long} is out of range`);
    if (!between(lat, -90, 90))
      this.errors.push(`latitude ${lat} is out of range`);

    return this.errors.length === 0;
  }

  defaultMessage() {
    return this.errors.join('; ');
  }
}

Then you can use it to validate a single Point @Validate(IsLatitudeLongitude) or an array @Validate(IsLatitudeLongitude, { each: true })

Gxmadix avatar Sep 03 '22 16:09 Gxmadix

As mentioned by others, you can use a custom validator for this.

NoNameProvided avatar Dec 09 '22 20:12 NoNameProvided

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

github-actions[bot] avatar Jan 09 '23 00:01 github-actions[bot]