Машинопись, DDD: проверки

#typescript #domain-driven-design

Вопрос:

Я много изучал проверки ввода, и я был немного сбит с толку, многие указывают на то, чтобы оставить проверки размера типа, типа конкретной переменной в домене, чтобы выполнить проверку таким образом, чтобы не привести к утечке знаний о домене, и с этим, поскольку я использую typescript, я подумал о статической функции для создания моего агрегата и использовать статическую функцию с именем canBuild, чтобы проверить, возможно ли создать агрегат

подобный этому:

 export class PersonAggregrate extends Entity<IPersonProps> {
  private constructor(props: IPersonProps, id?: string) {
    super(props, id)
  }

  private static canBuild(props: IPersonJSON): IErrorModel[] {
    let errors = [] as IErrorModel[]
    if (typeof props.firstName !== 'string') errors.push({})
    if (typeof props.lastName !== 'string') errors.push({})
    if (props.firstName.length < 4) errors.push({})
    if (props.lastName.length < 2) errors.push({})
    return errors
  }

  public static build(
    props: IPersonJSON amp; { id?: string },
  ): Either<IErrorModel[], Person> {
    const hasErrs = this.canBuild(props)
    const user = User.build(props.user)
    if (user.isLeft()) {
      hasErrs.push(...user.value)
      return left(hasErrs)
    }
    if (hasErrs.length > 0) return left(hasErrs)
    const person = new Person({ ...props, user: user.value }, props.id)
    return right(person)
  }
}
 

сущность пользователя:

 export class User extends Entity<IUserJSON> {
  private constructor(props: IUserJSON, id?: string) {
    super(props, id)
  }

  private static canBuild(user: IUserJSON) {
    let errors = [] as IErrorModel[]
    if (typeof user.login !== 'string') errors.push({})
    if (typeof user.password !== 'string') errors.push({})
    if (user.refreshToken amp;amp; !validator.isJWT(user.refreshToken)) {
      errors.push({})
    }
    return errors
  }

  public static build(
    props: IUserJSON amp; { id?: string },
  ): Either<IErrorModel[], User> {
    const canBuild = this.canBuild(props)
    if (canBuild.length > 0) left(canBuild)
    const user = new User(props, props.id)
    return right(user)
  }
}
 

моя пользовательская сущность является частью моего объединенного лица

Сделал ли я также следующее в своей команде, чтобы создать объединение:

 export class CreatePersonCommand implements ICommand {
  private readonly id: string
  private readonly login!: string
  private readonly password!: string
  private readonly personId!: string
  private readonly firstName!: string
  private readonly lastName!: string

  constructor(person: Omit<IPersonJSON amp; IUserJSON, 'user' | 'personId'>) {
    this.id = v4()
    this.personId = this.id
    this.login = person.login
    this.password = person.password
    this.firstName = person.firstName
    this.lastName = person.lastName
  }

  public CanExecute(): boolean {
    let errors = [] as IErrorModel[]
    for (let field in this) {
      if (!this[field]){
        errors.push({ code: 215, message: `Required field: ${field}` })
      }
    }
    if (errors.length > 0) throw new BadRequestERROR({ errors })
    return errors.length <= 0
  }
}
 

чтобы не разрешать отправку данных сущности без свойств агрегата

 export class CreatePersonCommand implements ICommand {
  private readonly id: string
  private readonly login!: string
  private readonly password!: string
  private readonly personId!: string
  private readonly firstName!: string
  private readonly lastName!: string

  constructor(person: Omit<IPersonJSON amp; IUserJSON, 'user' | 'personId'>) {
    this.id = v4()
    this.personId = this.id
    this.login = person.login
    this.password = person.password
    this.firstName = person.firstName
    this.lastName = person.lastName
  }

  public CanExecute(): boolean {
    let errors = [] as IErrorModel[]
    for (let field in this) {
      if (!this[field]){
        errors.push({ code: 215, message: `Required field: ${field}` })
      }
    }
    if (errors.length > 0) throw new BadRequestERROR({ errors })
    return errors.length <= 0
  }
}
 

в моей совокупности я не использую ошибки ввода, потому что это просто ошибки входных данных, но я не знаю, следует ли мне рассматривать это (пустые данные как необработанные входные данные, поскольку они не отправляются)
, и на моем посреднике я использую CanExecute перед выполнением команды:

 public publish<T extends ICommand>(command: T): Promise<any> {
    if (!command) throw new InvalidCommandException()
    const handler = this.registry.get(command.constructor.name)
    if (!handler) throw new HandlerNotFoundException(command.constructor.name)
    if(!command.CanExecute()) throw new InvalidCommandException()
    return handler.execute(command)
  }
 

Я хотел бы знать, правильно ли это или есть лучший вариант?

Комментарии:

1. Я думаю, что вы можете найти это сообщение в блоге очень полезным.

2. @plalx эй, братан, спасибо тебе большое, это многое прояснило, я шел по тому же пути, но по ошибке, ты хочешь создать ответ для меня, чтобы я проголосовал положительно?

3. это очень помогает мне в моих вопросах, спасибо вам .

4. Я приглашаю вас ответить на ваш собственный вопрос с помощью полученных вами знаний 😉 Я рад, что это было полезно! Это определенно один из лучших постов, которые я читал о проверке.