Как передать универсальный тип в типе? - PullRequest
0 голосов
/ 08 октября 2019

Я пытаюсь создать новое ограничение для валидаторов классов Typestack. Ограничение "IsUnique" будет принимать сущность в качестве типа, а его столбец - в качестве аргумента, чтобы проверить, не существует ли этот столбец в базе данных и является ли он уникальным.

Я пробовал приведенный ниже кодно почему-то я не могу передать тип в "IsUniqueConstraint" через ключ валидатора в registerDecorator. С тех пор я новичок в Typescript, поэтому не очень хорошо понимаю его концепции.

Может кто-нибудь помочь мне узнать, как мы можем это сделать?

уникален. constraint.ts

import { registerDecorator, ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments, ValidationOptions } from 'class-validator';
import { Injectable } from '@nestjs/common';
import { Repository } from 'typeorm';

@ValidatorConstraint({ name: 'isUnique', async: true })
@Injectable()
export class IsUniqueConstraint<T> implements ValidatorConstraintInterface {

    constructor(private readonly repository: Repository<T>) { }

    async validate(value: string, args: ValidationArguments) {
        const [column] = args.constraints;

        const result = await this.repository.findOne({ where: { [column]: value } });

        if (result) {
            return false;
        }

        return true;
    }

    defaultMessage(args: ValidationArguments) {
        return `"${args.value}" already exists for ${args.constraints[0]}`;
    }

}

export function IsUnique<T>(column: string, validationOptions?: ValidationOptions) {
    return (object: object, propertyName: string) => {
        registerDecorator({
            target: object.constructor,
            propertyName,
            options: validationOptions,
            constraints: [column],
            validator: IsUniqueConstraint,
        });
    };
}

user.dto.ts

import { IsNotEmpty } from 'class-validator';
import { IsUnique } from './../shared/constraints/is-unique.constraint';
import { User } from './user.entity';

export class CreateUserDto {
  @IsNotEmpty()
  @IsUnique<User>('username')
  readonly username: string;
}

Ответы [ 2 ]

0 голосов
/ 09 октября 2019

Хорошо, после долгих попыток я решил по-другому. Спасибо @HB за указание пути.

Чтобы сделать то же самое, я передал сущность в валидатор и сгенерировал хранилище в самом классе. Потому что Nest JS Injection работал только для классов.

import { registerDecorator, ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments, ValidationOptions } from 'class-validator';
import { Injectable } from '@nestjs/common';
import { Connection } from 'typeorm';
import { InjectConnection } from '@nestjs/typeorm';

@ValidatorConstraint({ name: 'isUnique', async: true })
@Injectable()
export class IsUniqueConstraint implements ValidatorConstraintInterface {

    constructor(@InjectConnection() private readonly connection: Connection) { }

    async validate(value: string, args: ValidationArguments) {
        const [entity, column] = args.constraints;

        const repository = this.connection.getRepository(entity);
        const result     = await repository.findOne({ where: { [column]: value } });

        if (result) {
            return false;
        }

        return true;
    }

    defaultMessage(args: ValidationArguments) {
        return `"${args.value}" already exists for ${args.constraints[1]}`;
    }

}

export function IsUnique(entity: Function, column: string, validationOptions?: ValidationOptions) {
    return (object: object, propertyName: string) => {
        registerDecorator({
            target: object.constructor,
            propertyName,
            options: validationOptions,
            constraints: [entity, column],
            validator: IsUniqueConstraint,
        });
    };
}
0 голосов
/ 09 октября 2019

Generics - это, как правило, функция только во время компиляции. Если у вас нет какого-либо способа передачи метаданных, включая обобщенные (не уверен, что это легко возможно).

Если вам нужно использовать тип во время выполнения, вы обычно должны передавать его как обычный аргумент, поэтому в этом случае подпись должна измениться, чтобы приспособиться к этому:

@IsUnique(User, 'username')

Возможно, поэтому, когда вы вводите репозитории, вы делаете это через @InjectRepository(User), который также принимает класс сущности в качестве аргумента. Я сомневаюсь, что в IsUniqueConstraint хранилище может быть введено как есть. Вам, вероятно, потребуется разрешить его из контейнера / диспетчера соединений DI на основе типа сущности, передаваемого декоратором.

В соответствии с документацией вы можете напрямую назначить объект validator, а не просто класс /конструктор, так что вы можете создать конкретный экземпляр вашего валидатора, вручную передавая разрешенный репозиторий в конструктор.

Итак, может быть что-то в этом роде:

import { getRepository } from "typeorm";
// ...

export function IsUnique(
    entity: Function,
    column: string,
    validationOptions?: ValidationOptions) {

    // Not sure if this works here. Maybe it needs to be
    // moved into the returned function or a different resolution
    // mechanism is required.
    const repository = getRepository(entity); 

    return (object: object, propertyName: string) => {
        registerDecorator({
            target: object.constructor,
            propertyName,
            options: validationOptions,
            constraints: [column],
            validator: new IsUniqueConstraint(repository),
        });
    };
}
...