@sap/cds 9.1.0 → 9.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +43 -0
- package/bin/deploy.js +29 -0
- package/bin/serve.js +1 -5
- package/lib/compile/etc/csv.js +11 -6
- package/lib/compile/load.js +8 -5
- package/lib/compile/to/hdbtabledata.js +1 -1
- package/lib/dbs/cds-deploy.js +0 -31
- package/lib/env/cds-env.js +2 -1
- package/lib/env/cds-requires.js +3 -0
- package/lib/env/schemas/cds-rc.js +4 -0
- package/lib/index.js +38 -38
- package/lib/log/cds-error.js +12 -11
- package/lib/log/format/json.js +1 -1
- package/lib/ql/SELECT.js +31 -0
- package/lib/ql/resolve.js +1 -1
- package/lib/req/context.js +1 -1
- package/lib/req/validate.js +16 -17
- package/lib/srv/cds.Service.js +18 -28
- package/lib/srv/middlewares/auth/ias-auth.js +29 -2
- package/lib/srv/middlewares/auth/jwt-auth.js +11 -1
- package/lib/srv/srv-models.js +1 -1
- package/lib/srv/srv-tx.js +2 -2
- package/lib/utils/cds-utils.js +35 -2
- package/lib/utils/csv-reader.js +1 -1
- package/lib/utils/version.js +18 -0
- package/libx/_runtime/cds.js +1 -1
- package/libx/_runtime/common/aspects/any.js +1 -23
- package/libx/_runtime/common/generic/input.js +111 -50
- package/libx/_runtime/common/generic/sorting.js +1 -1
- package/libx/_runtime/common/utils/draft.js +1 -1
- package/libx/_runtime/common/utils/entityFromCqn.js +1 -1
- package/libx/_runtime/common/utils/propagateForeignKeys.js +1 -1
- package/libx/_runtime/common/utils/resolveView.js +2 -2
- package/libx/_runtime/common/utils/structured.js +2 -2
- package/libx/_runtime/common/utils/templateProcessor.js +0 -5
- package/libx/_runtime/common/utils/vcap.js +1 -1
- package/libx/_runtime/fiori/lean-draft.js +63 -23
- package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +3 -2
- package/libx/_runtime/messaging/service.js +1 -1
- package/libx/_runtime/remote/utils/client.js +1 -1
- package/libx/common/assert/utils.js +2 -12
- package/libx/common/utils/streaming.js +4 -9
- package/libx/http/location.js +1 -0
- package/libx/odata/index.js +1 -1
- package/libx/odata/middleware/batch.js +6 -1
- package/libx/odata/middleware/create.js +1 -1
- package/libx/odata/middleware/error.js +22 -19
- package/libx/odata/middleware/stream.js +1 -1
- package/libx/odata/parse/cqn2odata.js +16 -10
- package/libx/odata/parse/grammar.peggy +4 -2
- package/libx/odata/parse/parser.js +1 -1
- package/libx/odata/utils/index.js +1 -1
- package/libx/queue/index.js +2 -2
- package/libx/rest/RestAdapter.js +1 -2
- package/libx/rest/middleware/create.js +5 -2
- package/package.json +2 -2
- package/server.js +1 -1
- package/bin/deploy/to-hana.js +0 -1
- package/lib/utils/check-version.js +0 -9
- package/lib/utils/unit.js +0 -19
- package/libx/_runtime/cds-services/util/assert.js +0 -181
- package/libx/_runtime/types/api.js +0 -129
- package/libx/common/assert/validation.js +0 -109
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
const cds = require('../../cds')
|
|
2
|
-
const LOG = cds.log('app')
|
|
3
|
-
const templatePathSerializer = require('../../common/utils/templateProcessorPathSerializer')
|
|
4
|
-
|
|
5
|
-
const typeCheckers = require('../../../common/assert/type-strict')
|
|
6
|
-
const { 'cds.Decimal': checkDecimal } = typeCheckers
|
|
7
|
-
const { checkMandatory, checkEnum, checkRange, checkFormat } = require('../../../common/assert/validation')
|
|
8
|
-
|
|
9
|
-
const ASSERT_RANGE = 'ASSERT_RANGE'
|
|
10
|
-
const ASSERT_FORMAT = 'ASSERT_FORMAT'
|
|
11
|
-
const ASSERT_DATA_TYPE = 'ASSERT_DATA_TYPE'
|
|
12
|
-
const ASSERT_ENUM = 'ASSERT_ENUM'
|
|
13
|
-
const ASSERT_NOT_NULL = 'ASSERT_NOT_NULL'
|
|
14
|
-
|
|
15
|
-
const _enumValues = element => {
|
|
16
|
-
return Object.keys(element).map(enumKey => {
|
|
17
|
-
const enum_ = element[enumKey]
|
|
18
|
-
const enumValue = enum_ && enum_.val
|
|
19
|
-
|
|
20
|
-
if (enumValue !== undefined) {
|
|
21
|
-
if (enumValue['=']) return enumValue['=']
|
|
22
|
-
if (enum_ && enum_.literal && enum_.literal === 'number') return Number(enumValue)
|
|
23
|
-
return enumValue
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return enumKey
|
|
27
|
-
})
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// REVISIT: this needs a cleanup!
|
|
31
|
-
const assertError = (code, element, value, key, path) => {
|
|
32
|
-
let args
|
|
33
|
-
|
|
34
|
-
if (typeof code === 'object') {
|
|
35
|
-
args = code.args
|
|
36
|
-
code = code.code
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const { name, type, precision, scale } = element
|
|
40
|
-
const error = new Error()
|
|
41
|
-
const errorEntry = {
|
|
42
|
-
code,
|
|
43
|
-
message: code,
|
|
44
|
-
target: path ?? element.name ?? key,
|
|
45
|
-
args: args ?? [name ?? key]
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const assertError = Object.assign(error, errorEntry)
|
|
49
|
-
Object.assign(assertError, {
|
|
50
|
-
entity: element.parent && element.parent.name,
|
|
51
|
-
element: name, // > REVISIT: when is error.element needed?
|
|
52
|
-
type: element.items ? element.items._type : type,
|
|
53
|
-
status: 400,
|
|
54
|
-
value
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
if (element.enum) assertError.enum = _enumValues(element)
|
|
58
|
-
if (precision) assertError.precision = precision
|
|
59
|
-
if (scale) assertError.scale = scale
|
|
60
|
-
|
|
61
|
-
if (element.target) {
|
|
62
|
-
// REVISIT: when does this case apply?
|
|
63
|
-
assertError.target = element.target
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return assertError
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* @param {import('../../types/api').InputConstraints} constraints
|
|
71
|
-
*/
|
|
72
|
-
const checkInputConstraints = ({ element, value, errors, key, pathSegmentsInfo }) => {
|
|
73
|
-
if (!element) return errors
|
|
74
|
-
|
|
75
|
-
let path
|
|
76
|
-
if (pathSegmentsInfo?.length) path = templatePathSerializer(element.name || key, pathSegmentsInfo)
|
|
77
|
-
|
|
78
|
-
// not nice, but best option for keeping new cds.assert() clean
|
|
79
|
-
if (element._isMandatory) {
|
|
80
|
-
const mandatoryErrors = []
|
|
81
|
-
checkMandatory(value, element, mandatoryErrors, [], key)
|
|
82
|
-
if (mandatoryErrors.length) {
|
|
83
|
-
errors.push(...mandatoryErrors.map(() => assertError({ code: ASSERT_NOT_NULL }, element, value, key, path)))
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (value == null) return errors
|
|
88
|
-
|
|
89
|
-
// not nice, but best option for keeping new cds.assert() clean
|
|
90
|
-
const enumErrors = []
|
|
91
|
-
checkEnum(value, element, enumErrors, [], key)
|
|
92
|
-
if (enumErrors.length) {
|
|
93
|
-
errors.push(...enumErrors.map(e => assertError({ code: ASSERT_ENUM, args: e.args }, element, value, key, path)))
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// not nice, but best option for keeping new cds.assert() clean
|
|
97
|
-
const rangeErrors = []
|
|
98
|
-
checkRange(value, element, rangeErrors, [], key)
|
|
99
|
-
if (rangeErrors.length) {
|
|
100
|
-
errors.push(...rangeErrors.map(e => assertError({ code: ASSERT_RANGE, args: e.args }, element, value, key, path)))
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// not nice, but best option for keeping new cds.assert() clean
|
|
104
|
-
const formatErrors = []
|
|
105
|
-
checkFormat(value, element, formatErrors, [], key)
|
|
106
|
-
if (formatErrors.length) {
|
|
107
|
-
errors.push(...formatErrors.map(e => assertError({ code: ASSERT_FORMAT, args: e.args }, element, value, key, path)))
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
if (element.type === 'cds.Decimal') {
|
|
111
|
-
// not nice, but best option for keeping new cds.assert() clean
|
|
112
|
-
const decimalErrors = []
|
|
113
|
-
checkDecimal(value, element, decimalErrors, [], key)
|
|
114
|
-
if (decimalErrors.length) {
|
|
115
|
-
errors.push(
|
|
116
|
-
...decimalErrors.map(e => assertError({ code: ASSERT_DATA_TYPE, args: e.args }, element, value, key, path))
|
|
117
|
-
)
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return errors
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Check whether the target entity referenced by the association (the reference's target) exists and assert an error if
|
|
126
|
-
* the the reference's target doesn't exist.
|
|
127
|
-
*
|
|
128
|
-
* In other words, use this annotation to check whether a non-null foreign key input in a table has a corresponding
|
|
129
|
-
* primary key (also known as a parent key) in the associated/referenced target table (also known as a parent table).
|
|
130
|
-
*
|
|
131
|
-
* @param {import('../../types/api').assertTargetMap} assertMap
|
|
132
|
-
* @param {array} errors An array to appends the possible errors.
|
|
133
|
-
* @see {@link https://cap.cloud.sap/docs/guides/providing-services#assert-target @assert.target} for
|
|
134
|
-
* further information.
|
|
135
|
-
*/
|
|
136
|
-
const assertTargets = async (assertMap, errors) => {
|
|
137
|
-
const { targets: targetsMap, allTargets } = assertMap
|
|
138
|
-
if (targetsMap.size === 0) return
|
|
139
|
-
|
|
140
|
-
const targets = Array.from(targetsMap.values())
|
|
141
|
-
const transactions = targets.map(({ keys, entity }) => {
|
|
142
|
-
const where = Object.assign({}, ...keys)
|
|
143
|
-
return cds.db.exists(entity, where).forShareLock()
|
|
144
|
-
})
|
|
145
|
-
const targetsExistsResults = await Promise.allSettled(transactions)
|
|
146
|
-
|
|
147
|
-
targetsExistsResults.forEach((txPromise, index) => {
|
|
148
|
-
const isPromiseRejected = txPromise.status === 'rejected'
|
|
149
|
-
const shouldAssertError = (txPromise.status === 'fulfilled' && txPromise.value == null) || isPromiseRejected
|
|
150
|
-
if (!shouldAssertError) return
|
|
151
|
-
|
|
152
|
-
const target = targets[index]
|
|
153
|
-
const { element } = target.assocInfo
|
|
154
|
-
|
|
155
|
-
if (isPromiseRejected) {
|
|
156
|
-
LOG._debug &&
|
|
157
|
-
LOG.debug(
|
|
158
|
-
`The transaction to check the @assert.target constraint for foreign key "${element.name}" failed`,
|
|
159
|
-
txPromise.reason
|
|
160
|
-
)
|
|
161
|
-
|
|
162
|
-
throw new Error(txPromise.reason.message)
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
allTargets
|
|
166
|
-
.filter(t => t.key === target.key)
|
|
167
|
-
.forEach(target => {
|
|
168
|
-
const { row, pathSegmentsInfo } = target.assocInfo
|
|
169
|
-
const key = target.foreignKey.name
|
|
170
|
-
let path
|
|
171
|
-
if (pathSegmentsInfo?.length) path = templatePathSerializer(key, pathSegmentsInfo)
|
|
172
|
-
const error = assertError('ASSERT_TARGET', target.foreignKey, row[key], key, path)
|
|
173
|
-
errors.push(error)
|
|
174
|
-
})
|
|
175
|
-
})
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
module.exports = {
|
|
179
|
-
checkInputConstraints,
|
|
180
|
-
assertTargets
|
|
181
|
-
}
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
// Columns
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @typedef {object} ColumnRef
|
|
5
|
-
* @property {string[]} ref
|
|
6
|
-
* @property {function} func
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* @typedef {Array<ColumnRef>} ColumnRefs
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
// Input constraints
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* @typedef {object} InputConstraints
|
|
17
|
-
* @property {object} element
|
|
18
|
-
* @property {*} value
|
|
19
|
-
* @property {Array} errors
|
|
20
|
-
* @property {string} [key]
|
|
21
|
-
* @property {pathSegmentInfo[]} [pathSegmentsInfo]
|
|
22
|
-
* @property {string} event
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
// ON condition
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* @typedef {object} ONConditionAliases
|
|
29
|
-
* @property {string} select
|
|
30
|
-
* @property {string} join
|
|
31
|
-
*/
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* @typedef {object} ONConditionOptions
|
|
35
|
-
* @property {string | Array} [associationNames]
|
|
36
|
-
* @property {object} [csn]
|
|
37
|
-
* @property {ONConditionAliases} [aliases]
|
|
38
|
-
* @property {boolean} [resolveView=true]
|
|
39
|
-
*/
|
|
40
|
-
|
|
41
|
-
// Template processor
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* @typedef {object} TemplateProcessorInfo
|
|
45
|
-
* @property {entity} target
|
|
46
|
-
* @property {Map} elements
|
|
47
|
-
*/
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* @typedef {object} TemplateProcessorPathOptions
|
|
51
|
-
* @property {object} [draftKeys]
|
|
52
|
-
* @property {function} [rowUUIDGenerator]
|
|
53
|
-
* @property {string[]} [segments=[]] - Path segments to relate the error message.
|
|
54
|
-
* @property {boolean} [includeKeyValues=false] Indicates whether the key values are included in the path segments
|
|
55
|
-
* The path segments are used to build the error target (a relative resource path)
|
|
56
|
-
*/
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* @typedef {object} TemplateProcessor
|
|
60
|
-
* @property {Function} processFn
|
|
61
|
-
* @property {object} data
|
|
62
|
-
* @property {TemplateProcessorInfo} template
|
|
63
|
-
* @property {boolean} [isRoot=true]
|
|
64
|
-
* @property {TemplateProcessorPathOptions} [pathOptions=null]
|
|
65
|
-
*/
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* @typedef {object} pathSegmentInfo
|
|
69
|
-
* @property {string} key
|
|
70
|
-
* @property {string[]} keyNames
|
|
71
|
-
* @property {object} row
|
|
72
|
-
* @property {object} elements
|
|
73
|
-
* @property {string[]} draftKeys
|
|
74
|
-
*/
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* @typedef {object} templateElementInfo
|
|
78
|
-
* @property {object} row
|
|
79
|
-
* @property {string} key
|
|
80
|
-
* @property {object} element
|
|
81
|
-
* @property {boolean} plain
|
|
82
|
-
* @property {entity} target
|
|
83
|
-
* @property {boolean} isRoot
|
|
84
|
-
* @property {string[] | Array<pathSegmentInfo>} [pathSegmentsInfo]
|
|
85
|
-
*/
|
|
86
|
-
|
|
87
|
-
// Search
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* @typedef {object} searchContainsArg
|
|
91
|
-
* @property {ColumnRefs} [list] The columns to
|
|
92
|
-
* be searched
|
|
93
|
-
* @property {string} [val] The search string
|
|
94
|
-
*/
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* @typedef {Array<searchContainsArg>} searchContainsArgs
|
|
98
|
-
*/
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* @typedef {object} searchContainsExp
|
|
102
|
-
* @property {string} func='contains' The function name
|
|
103
|
-
* @property {searchContainsArgs} args
|
|
104
|
-
*/
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* @typedef {object} search2cqnOptions
|
|
108
|
-
* @property {ColumnRefs} [columns] The columns to be searched
|
|
109
|
-
* @property {string} locale The user locale
|
|
110
|
-
*/
|
|
111
|
-
|
|
112
|
-
// Assert targets map
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* @typedef {object} assertTargetMap
|
|
116
|
-
* @property {Map<string, targetMaps>} targets
|
|
117
|
-
* @property {targetMaps[]} allTargets
|
|
118
|
-
*/
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* @typedef {object} targetMaps
|
|
122
|
-
* @property {string} key
|
|
123
|
-
* @property {entity} entity
|
|
124
|
-
* @property {object} keys
|
|
125
|
-
* @property {object} foreignKey
|
|
126
|
-
* @property {templateElementInfo} assocInfo
|
|
127
|
-
*/
|
|
128
|
-
|
|
129
|
-
module.exports = {}
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
const { cds } = global
|
|
2
|
-
|
|
3
|
-
const {
|
|
4
|
-
'cds.Date': checkISODate,
|
|
5
|
-
'cds.Time': checkISOTime,
|
|
6
|
-
'cds.DateTime': checkISODateTime,
|
|
7
|
-
'cds.Timestamp': checkISOTimestamp,
|
|
8
|
-
'cds.String': checkString
|
|
9
|
-
} = require('./type-strict')
|
|
10
|
-
const { getTarget, resolveCDSType } = require('./utils')
|
|
11
|
-
|
|
12
|
-
const _isNavigationColumn = (col, as) => col.ref?.length > 1 && (col.as === as || col.ref[col.ref.length - 1] === as)
|
|
13
|
-
|
|
14
|
-
// REVISIT: mandatory is actually not the same as not null or empty string
|
|
15
|
-
const _isNotFilled = val => val === null || val === undefined || (typeof val === 'string' && val.trim() === '')
|
|
16
|
-
|
|
17
|
-
const _getEnumElement = ele => ((ele['@assert.range'] && ele.enum) ? ele.enum : undefined)
|
|
18
|
-
|
|
19
|
-
const _enumValues = ele => {
|
|
20
|
-
return Object.keys(ele).map(enumKey => {
|
|
21
|
-
const enum_ = ele[enumKey]
|
|
22
|
-
const enumValue = enum_ && enum_.val
|
|
23
|
-
if (enumValue !== undefined) {
|
|
24
|
-
if (enumValue['=']) return enumValue['=']
|
|
25
|
-
if (enum_ && enum_.literal && enum_.literal === 'number') return Number(enumValue)
|
|
26
|
-
return enumValue
|
|
27
|
-
}
|
|
28
|
-
return enumKey
|
|
29
|
-
})
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const _checkDateValue = (val, r1, r2) => {
|
|
33
|
-
const dateVal = new Date(val)
|
|
34
|
-
return (dateVal - new Date(r1)) * (dateVal - new Date(r2)) <= 0
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const _toDate = val => `2000-01-01T${val}Z`
|
|
38
|
-
|
|
39
|
-
const _checkInRange = (val, range, type) => {
|
|
40
|
-
switch (type) {
|
|
41
|
-
case 'cds.Date':
|
|
42
|
-
return checkISODate(val) && _checkDateValue(val, range[0], range[1])
|
|
43
|
-
case 'cds.DateTime':
|
|
44
|
-
return checkISODateTime(val) && _checkDateValue(val, range[0], range[1])
|
|
45
|
-
case 'cds.Timestamp':
|
|
46
|
-
return checkISOTimestamp(val) && _checkDateValue(val, range[0], range[1])
|
|
47
|
-
case 'cds.Time':
|
|
48
|
-
return checkISOTime(val) && _checkDateValue(_toDate(val), _toDate(range[0]), _toDate(range[1]))
|
|
49
|
-
default:
|
|
50
|
-
return (val - range[0]) * (val - range[1]) <= 0
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// process.env.CDS_ASSERT_FORMAT_FLAGS is not official!
|
|
55
|
-
const _checkRegExpFormat = (val, format) =>
|
|
56
|
-
checkString(val) && val.match(new RegExp(format, process.env.CDS_ASSERT_FORMAT_FLAGS || 'u'))
|
|
57
|
-
|
|
58
|
-
const checkMandatory = (v, ele, errs, path, k) => {
|
|
59
|
-
// REVISIT: correct to not complain?
|
|
60
|
-
// do not complain about missing foreign keys in children
|
|
61
|
-
if (path.length && ele['@odata.foreignKey4']) return
|
|
62
|
-
|
|
63
|
-
// TODO: which case is this?
|
|
64
|
-
// do not complain about ???
|
|
65
|
-
if (ele.parent?.query?.SELECT?.columns?.find(col => _isNavigationColumn(col, ele.name))) return
|
|
66
|
-
|
|
67
|
-
if (_isNotFilled(v)) {
|
|
68
|
-
const target = getTarget(path, k)
|
|
69
|
-
errs.push(new cds.error('ASSERT_NOT_NULL', { target, statusCode: 400, code: '400' }))
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const checkEnum = (v, ele, errs, path, k) => {
|
|
74
|
-
const enumElements = _getEnumElement(ele)
|
|
75
|
-
const enumValues = enumElements && _enumValues(enumElements)
|
|
76
|
-
if (enumElements && !enumValues.some(ev => ev == v)) { //> use == for automatic type coercion
|
|
77
|
-
const args =
|
|
78
|
-
typeof v === 'string'
|
|
79
|
-
? ['"' + v + '"', enumValues.map(ele => '"' + ele + '"').join(', ')]
|
|
80
|
-
: [v, enumValues.join(', ')]
|
|
81
|
-
const target = getTarget(path, k)
|
|
82
|
-
errs.push(new cds.error('ASSERT_ENUM', { args, target, statusCode: 400, code: '400' }))
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const checkRange = (v, ele, errs, path, k) => {
|
|
87
|
-
const rangeElements = ele['@assert.range'] && !_getEnumElement(ele) ? ele['@assert.range'] : undefined
|
|
88
|
-
if (rangeElements && !_checkInRange(v, rangeElements, resolveCDSType(ele))) {
|
|
89
|
-
const args = [v, ...ele['@assert.range']]
|
|
90
|
-
const target = getTarget(path, k)
|
|
91
|
-
errs.push(new cds.error('ASSERT_RANGE', { args, target, statusCode: 400, code: '400' }))
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const checkFormat = (v, ele, errs, path, k) => {
|
|
96
|
-
const formatElements = ele['@assert.format']
|
|
97
|
-
if (formatElements && !_checkRegExpFormat(v, formatElements)) {
|
|
98
|
-
const args = [v, formatElements]
|
|
99
|
-
const target = getTarget(path, k)
|
|
100
|
-
errs.push(new cds.error('ASSERT_FORMAT', { args, target, statusCode: 400, code: '400' }))
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
module.exports = {
|
|
105
|
-
checkMandatory,
|
|
106
|
-
checkEnum,
|
|
107
|
-
checkRange,
|
|
108
|
-
checkFormat
|
|
109
|
-
}
|