Passed
Push — develop ( 81d917...6277d9 )
by Tito
01:04 queued 19s
created

Entity.validate   A

Complexity

Conditions 1

Size

Total Lines 25
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 14
dl 0
loc 25
rs 9.7
c 0
b 0
f 0
cc 1
1
import { EntityInvalidFieldTypesError } from "../Errors/Entities/EntityInvalidFieldTypesError";
2
import { EntityRequiredFieldsNotFoundError } from "../Errors/Entities/EntityRequiredFieldsNotFoundError";
3
import { IEntityDefinition } from "../Types/Entities/IEntityDefinition";
4
import { FieldValidator } from "../Utilities/Fields/FieldValidator";
5
import { UniqueEntityId } from "../Utilities/Ids/UniqueEntityId";
6
7
/**
8
 * Abstract Entity class
9
 */
10
export abstract class Entity<T> {
11
  /**
12
   * Id of the entity
13
   */
14
  protected readonly _id: UniqueEntityId;
15
16
  /**
17
   * Collection of properties
18
   */
19
  protected readonly props: T;
20
21
  /**
22
   * Definition of required and optional fields of the entity, for validation
23
   * Read-only and immutable class property so it has to be defined during inheritance
24
   */
25
  protected readonly definition: IEntityDefinition = {
26
    required: [],
27
    optional: [],
28
  };
29
30
  /**
31
   * @param T props
32
   * @param IEntityDefinition definition Needed for each specific entity overriding this entity.  The child entity should not expose this parameter in its own constructor
33
   * @param UniqueEntityId id If not sent, it generates a UUID
34
   *
35
   * @throws EntityRequiredFieldsNotFoundError|EntityInvalidFieldTypesError
36
   */
37
  constructor(props: T, definition: IEntityDefinition, id?: UniqueEntityId) {
38
    this.props = props;
39
    this.definition = definition;
40
    this._id = id ? id : new UniqueEntityId();
41
42
    this.validate();
43
  }
44
45
  /**
46
   * Validates if the required fields are present.  It will fail if it's not the case
47
   *
48
   * @returns void
49
   */
50
  protected validateFieldsRequired(
51
    requiredValidation: FieldValidator<T>
52
  ): void {
53
    // Fails if required fields are not all present using the field validator
54
    const requiredFieldsValidation = requiredValidation.allFieldsAvailable();
55
56
    if (requiredFieldsValidation !== true)
57
      throw new EntityRequiredFieldsNotFoundError(
58
        (<any>this).constructor.name,
59
        requiredFieldsValidation
60
      );
61
  }
62
63
  /**
64
   * Validates if the required fields are present.  It will fail if it's not the case
65
   *
66
   * @returns void
67
   */
68
  protected validateFieldsMatchingTypes(
69
    requiredValidation: FieldValidator<T>,
70
    optionalValidation: FieldValidator<T>
71
  ) {
72
    const requiredFieldsTypeValidation =
73
      requiredValidation.allFieldsTypeMatch();
74
    const optionalFieldsTypeValidation =
75
      optionalValidation.allFieldsTypeMatch();
76
77
    if (
78
      requiredFieldsTypeValidation !== true ||
79
      optionalFieldsTypeValidation !== true
80
    ) {
81
      // If the validator fails, gets a joint array of the required and optional fields that have failed
82
      const invalidFields = (
83
        requiredFieldsTypeValidation === true
84
          ? []
85
          : requiredFieldsTypeValidation
86
      ).concat(
87
        optionalFieldsTypeValidation === true
88
          ? []
89
          : optionalFieldsTypeValidation
90
      );
91
92
      // Throws an exception with the joint array's names and types
93
      throw new EntityInvalidFieldTypesError(
94
        <any>this.constructor.name,
95
        invalidFields.map((field) => {
96
          return field.name;
97
        }),
98
        invalidFields.map((field) => {
99
          return field.type;
100
        })
101
      );
102
    }
103
  }
104
105
  /**
106
   * Validates the entity
107
   *
108
   * @returns void
109
   * @throws EntityRequiredFieldsNotFoundError|EntityInvalidFieldTypesError
110
   */
111
  protected validate(): void {
112
    // Validator for required fields
113
    const requiredValidation = new FieldValidator(
114
      this.definition.required,
115
      this.props
116
    );
117
118
    // This will fail if fields are not present - leaving error throw
119
    this.validateFieldsRequired(requiredValidation);
120
121
    // Validator for optional fields
122
    const optionalValidation = new FieldValidator(
123
      this.definition.optional,
124
      this.props
125
    );
126
127
    // This will fail if any field is not matching type - leaving error throw
128
    this.validateFieldsMatchingTypes(requiredValidation, optionalValidation);
129
  }
130
}
131