-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathSingleMetadataFieldValidator.ts
More file actions
160 lines (140 loc) · 6.14 KB
/
Copy pathSingleMetadataFieldValidator.ts
File metadata and controls
160 lines (140 loc) · 6.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
import {
BaseMetadataFieldValidator,
DatasetMetadataFieldAndValueInfo
} from './BaseMetadataFieldValidator'
import { ControlledVocabularyFieldError } from './errors/ControlledVocabularyFieldError'
import { MetadataFieldValidator } from './MetadataFieldValidator'
import { DatasetMetadataChildFieldValueDTO } from '../../dtos/DatasetDTO'
import { MultipleMetadataFieldValidator } from './MultipleMetadataFieldValidator'
import {
MetadataFieldInfo,
MetadataFieldType
} from '../../../../metadataBlocks/domain/models/MetadataBlock'
export class SingleMetadataFieldValidator extends BaseMetadataFieldValidator {
validate(datasetMetadataFieldAndValueInfo: DatasetMetadataFieldAndValueInfo): void {
const metadataFieldValue = datasetMetadataFieldAndValueInfo.metadataFieldValue
const metadataFieldInfo = datasetMetadataFieldAndValueInfo.metadataFieldInfo
if (Array.isArray(metadataFieldValue)) {
throw this.createGeneralValidationError(
datasetMetadataFieldAndValueInfo,
'Expecting a single field, not an array.'
)
}
if (
typeof metadataFieldValue === 'object' &&
metadataFieldInfo.type !== MetadataFieldType.None
) {
throw this.createGeneralValidationError(
datasetMetadataFieldAndValueInfo,
'Expecting a string, not child fields.'
)
}
if (
typeof metadataFieldValue === 'string' &&
metadataFieldInfo.type === MetadataFieldType.None
) {
throw this.createGeneralValidationError(
datasetMetadataFieldAndValueInfo,
'Expecting child fields, not a string.'
)
}
this.validateFieldValue(datasetMetadataFieldAndValueInfo)
}
private validateFieldValue(datasetMetadataFieldAndValueInfo: DatasetMetadataFieldAndValueInfo) {
const metadataFieldInfo = datasetMetadataFieldAndValueInfo.metadataFieldInfo
if (metadataFieldInfo.isControlledVocabulary) {
this.validateControlledVocabularyFieldValue(datasetMetadataFieldAndValueInfo)
}
if (metadataFieldInfo.childMetadataFields != undefined) {
this.validateChildMetadataFieldValues(datasetMetadataFieldAndValueInfo)
}
}
private validateControlledVocabularyFieldValue(
datasetMetadataFieldAndValueInfo: DatasetMetadataFieldAndValueInfo
) {
if (
!datasetMetadataFieldAndValueInfo.metadataFieldInfo.controlledVocabularyValues?.includes(
datasetMetadataFieldAndValueInfo.metadataFieldValue as string
)
) {
throw new ControlledVocabularyFieldError(
datasetMetadataFieldAndValueInfo.metadataFieldKey,
datasetMetadataFieldAndValueInfo.metadataBlockName,
datasetMetadataFieldAndValueInfo.metadataParentFieldKey,
datasetMetadataFieldAndValueInfo.metadataFieldPosition
)
}
}
private validateChildMetadataFieldValues(
datasetMetadataFieldAndValueInfo: DatasetMetadataFieldAndValueInfo
) {
const metadataFieldInfo = datasetMetadataFieldAndValueInfo.metadataFieldInfo
const childMetadataFieldKeys = Object.keys(
metadataFieldInfo.childMetadataFields as Record<string, MetadataFieldInfo>
)
const metadataFieldValidator = new MetadataFieldValidator(
this,
new MultipleMetadataFieldValidator(this)
)
for (const childMetadataFieldKey of childMetadataFieldKeys) {
const childMetadataFieldInfo = (
metadataFieldInfo.childMetadataFields as Record<string, MetadataFieldInfo>
)[childMetadataFieldKey]
const allowEmptyForConditionallyRequiredField: boolean =
this.allowEmptyValueForConditionallyRequiredField(
datasetMetadataFieldAndValueInfo,
childMetadataFieldKey
)
metadataFieldValidator.validate({
metadataFieldInfo: childMetadataFieldInfo,
metadataFieldKey: childMetadataFieldKey,
metadataFieldValue: (
datasetMetadataFieldAndValueInfo.metadataFieldValue as DatasetMetadataChildFieldValueDTO
)[childMetadataFieldKey],
metadataBlockName: datasetMetadataFieldAndValueInfo.metadataBlockName,
metadataParentFieldKey: datasetMetadataFieldAndValueInfo.metadataFieldKey,
metadataFieldPosition: datasetMetadataFieldAndValueInfo.metadataFieldPosition,
allowEmptyForConditionallyRequiredField
})
}
}
/**
* This method allows setting empty values for conditionally required child fields.
* A child field is conditionally required if it is required and its parent field is not required.
* The child field should be required only if any of its sibling fields has a value, otherwise it should be optional.
*/
private allowEmptyValueForConditionallyRequiredField(
datasetMetadataFieldAndValueInfo: DatasetMetadataFieldAndValueInfo,
childMetadataFieldKey: string
): boolean {
let result = false
const metadataFieldInfo = datasetMetadataFieldAndValueInfo.metadataFieldInfo
const childMetadataFieldKeys = Object.keys(
metadataFieldInfo.childMetadataFields as Record<string, MetadataFieldInfo>
)
const conditionallyRequiredChildFields: false | string[] =
!datasetMetadataFieldAndValueInfo.metadataFieldInfo.isRequired &&
childMetadataFieldKeys.filter(
(childMetadataFieldKey) =>
(metadataFieldInfo.childMetadataFields as Record<string, MetadataFieldInfo>)[
childMetadataFieldKey
].isRequired
)
const hasConditionallyRequiredChildFields = Boolean(conditionallyRequiredChildFields)
if (
hasConditionallyRequiredChildFields &&
Object.values(conditionallyRequiredChildFields as string[]).includes(childMetadataFieldKey)
) {
// At this point we know we are standing on a child field that is required and the parent field is not required
// Get the sibling fields and check if any of them has a value
const { [childMetadataFieldKey as keyof Record<string, string>]: _, ...siblingFields } =
datasetMetadataFieldAndValueInfo.metadataFieldValue as Record<string, string>
const siblingsValues = Object.values(siblingFields) as string[]
const isAnySiblingValuePresent = siblingsValues.some(
([, value]) => value !== undefined && value !== ''
)
result = !isAnySiblingValuePresent
}
return result
}
}