Passed
Pull Request — develop (#4)
by Tito
01:46
created

Entity.validateFieldsRequired   A

Complexity

Conditions 3

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 10
dl 0
loc 16
rs 9.9
c 0
b 0
f 0
cc 3
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 UniqueEntityId id If not sent, it generates a UUID
33
   *
34
   * @throws EntityRequiredFieldsNotFoundError|EntityInvalidFieldTypesError
35
   */
36
  constructor(props: T, id?: UniqueEntityId) {
37
    this._id = id ? id : new UniqueEntityId();
38
    this.props = props;
39
40
    this.validate();
41
  }
42
43
  /**
44
   * Validates if the required fields are present.  It will fail if it's not the case
45
   *
46
   * @returns void
47
   */
48
  protected validateFieldsRequired(
49
    requiredValidation: FieldValidator<T>
50
  ): void {
51
    // Fails if required fields are not all present using the field validator
52
    const requiredFieldsValidation = requiredValidation.allFieldsAvailable();
53
54
    if (requiredFieldsValidation !== true)
55
      throw new EntityRequiredFieldsNotFoundError(
56
        (<any>this).constructor.name,
57
        requiredFieldsValidation
58
      );
59
  }
60
61
  /**
62
   * Validates if the required fields are present.  It will fail if it's not the case
63
   *
64
   * @returns void
65
   */
66
  protected validateFieldsMatchingTypes(
67
    requiredValidation: FieldValidator<T>,
68
    optionalValidation: FieldValidator<T>
69
  ) {
70
    const requiredFieldsTypeValidation =
71
      requiredValidation.allFieldsTypeMatch();
72
    const optionalFieldsTypeValidation =
73
      optionalValidation.allFieldsTypeMatch();
74
75
    if (
76
      requiredFieldsTypeValidation !== true ||
77
      optionalFieldsTypeValidation !== true
78
    ) {
79
      // If the validator fails, gets a joint array of the required and optional fields that have failed
80
      const invalidFields = (
81
        requiredFieldsTypeValidation === true
82
          ? []
83
          : requiredFieldsTypeValidation
84
      ).concat(
85
        optionalFieldsTypeValidation === true
86
          ? []
87
          : optionalFieldsTypeValidation
88
      );
89
90
      // Throws an exception with the joint array's names and types
91
      throw new EntityInvalidFieldTypesError(
92
        <any>this.constructor.name,
93
        invalidFields.map((field) => {
94
          return field.name;
95
        }),
96
        invalidFields.map((field) => {
97
          return field.type;
98
        })
99
      );
100
    }
101
  }
102
103
  /**
104
   * Validates the entity
105
   *
106
   * @returns true
107
   * @throws EntityRequiredFieldsNotFoundError|EntityInvalidFieldTypesError
108
   */
109
  protected validate(): true {
110
    // Validator for required fields
111
    const requiredValidation = new FieldValidator(
112
      this.definition.required,
113
      this.props
114
    );
115
116
    // This will fail if fields are not present - leaving error throw
117
    this.validateFieldsRequired(requiredValidation);
118
119
    // Validator for optional fields
120
    const optionalValidation = new FieldValidator(
121
      this.definition.optional,
122
      this.props
123
    );
124
125
    // This will fail if any field is not matching type - leaving error throw
126
    this.validateFieldsMatchingTypes(requiredValidation, optionalValidation);
127
128
    // Everything fine, returns true
129
    return true;
130
  }
131
}
132