@sap/cds 6.1.0 → 6.1.3

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.
Files changed (64) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/apis/log.d.ts +112 -36
  3. package/apis/services.d.ts +13 -2
  4. package/bin/build/provider/buildTaskHandlerFeatureToggles.js +2 -3
  5. package/bin/build/provider/hana/index.js +4 -2
  6. package/bin/build/provider/mtx/resourcesTarBuilder.js +4 -8
  7. package/bin/deploy/to-hana/hana.js +20 -25
  8. package/bin/deploy/to-hana/hdiDeployUtil.js +13 -2
  9. package/lib/dbs/cds-deploy.js +2 -2
  10. package/lib/env/schemas/cds-rc.json +10 -1
  11. package/lib/index.js +1 -1
  12. package/lib/log/format/kibana.js +19 -1
  13. package/lib/ql/Query.js +9 -3
  14. package/lib/ql/SELECT.js +1 -1
  15. package/lib/ql/UPDATE.js +2 -2
  16. package/lib/ql/cds-ql.js +4 -10
  17. package/lib/req/context.js +15 -11
  18. package/lib/srv/srv-api.js +8 -0
  19. package/lib/srv/srv-dispatch.js +11 -7
  20. package/lib/srv/srv-models.js +4 -3
  21. package/lib/srv/srv-tx.js +52 -40
  22. package/lib/utils/cds-utils.js +3 -3
  23. package/lib/utils/resources/index.js +5 -5
  24. package/lib/utils/resources/tar.js +1 -1
  25. package/libx/_runtime/auth/index.js +2 -2
  26. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +2 -1
  27. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/utils/PrimitiveValueDecoder.js +0 -2
  28. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/DeserializerFactory.js +3 -1
  29. package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +0 -2
  30. package/libx/_runtime/cds-services/services/utils/compareJson.js +3 -1
  31. package/libx/_runtime/cds-services/util/assert.js +3 -0
  32. package/libx/_runtime/common/generic/input.js +17 -2
  33. package/libx/_runtime/common/generic/put.js +4 -1
  34. package/libx/_runtime/common/generic/temporal.js +0 -3
  35. package/libx/_runtime/common/utils/binary.js +3 -4
  36. package/libx/_runtime/common/utils/keys.js +14 -6
  37. package/libx/_runtime/common/utils/propagateForeignKeys.js +122 -0
  38. package/libx/_runtime/common/utils/resolveView.js +1 -1
  39. package/libx/_runtime/common/utils/template.js +2 -3
  40. package/libx/_runtime/db/expand/expandCQNToJoin.js +1 -1
  41. package/libx/_runtime/db/expand/rawToExpanded.js +7 -6
  42. package/libx/_runtime/db/generic/input.js +7 -4
  43. package/libx/_runtime/db/sql-builder/InsertBuilder.js +1 -1
  44. package/libx/_runtime/extensibility/add.js +3 -0
  45. package/libx/_runtime/extensibility/handler/transformREAD.js +20 -18
  46. package/libx/_runtime/extensibility/push.js +11 -11
  47. package/libx/_runtime/extensibility/token.js +2 -1
  48. package/libx/_runtime/extensibility/utils.js +8 -6
  49. package/libx/_runtime/fiori/generic/new.js +1 -3
  50. package/libx/_runtime/fiori/generic/patch.js +1 -7
  51. package/libx/_runtime/fiori/utils/where.js +1 -1
  52. package/libx/_runtime/messaging/common-utils/authorizedRequest.js +1 -1
  53. package/libx/_runtime/messaging/enterprise-messaging-utils/EMManagement.js +1 -2
  54. package/libx/_runtime/remote/utils/client.js +29 -10
  55. package/libx/_runtime/sqlite/Service.js +7 -5
  56. package/libx/_runtime/sqlite/execute.js +41 -28
  57. package/libx/odata/cqn2odata.js +6 -2
  58. package/libx/rest/RestAdapter.js +3 -6
  59. package/libx/rest/middleware/input.js +2 -3
  60. package/package.json +1 -1
  61. package/srv/extensibility-service.cds +4 -3
  62. package/srv/model-provider.js +1 -1
  63. package/srv/mtx.js +18 -9
  64. package/libx/_runtime/db/utils/propagateForeignKeys.js +0 -93
@@ -0,0 +1,122 @@
1
+ const cds = require('../../cds')
2
+
3
+ const { prefixForStruct } = require('../../common/utils/csn')
4
+
5
+ const _autoGenerate = e => e && e.isUUID && e.key
6
+
7
+ const _set = (row, value, element, enumerable) => {
8
+ if (!element.parent.elements[element.name]) return // only when in model
9
+ if (!enumerable && element.foreignKeySource) {
10
+ // only for foreign keys
11
+ Object.defineProperty(row, element.name, {
12
+ get() {
13
+ return value
14
+ },
15
+ set(v) {
16
+ // Make sure that it becomes enumerable again if set manually afterwards
17
+ Object.defineProperty(row, element.name, { value: v, configurable: true, enumerable: true })
18
+ },
19
+ enumerable: false,
20
+ configurable: true
21
+ })
22
+ } else {
23
+ row[element.name] = value
24
+ }
25
+ }
26
+
27
+ const _generateParentField = ({ parentElement }, row, enumerable) => {
28
+ if (_autoGenerate(parentElement) && !row[parentElement.name]) {
29
+ _set(row, cds.utils.uuid(), parentElement, enumerable)
30
+ }
31
+ }
32
+
33
+ const _generateChildField = ({ deep, childElement }, childRow, enumerable) => {
34
+ if (deep) {
35
+ _generateChildField(deep.propagation, childRow[deep.targetName], enumerable)
36
+ } else if (_autoGenerate(childElement) && childRow && !childRow[childElement.name]) {
37
+ _set(childRow, cds.utils.uuid(), childElement, enumerable)
38
+ }
39
+ }
40
+
41
+ const _getNestedVal = (row, prefix) => {
42
+ let val = row
43
+ const splitted = prefix.split('_')
44
+ splitted.pop() // remove last `_`
45
+ let k = ''
46
+
47
+ while (splitted.length > 0) {
48
+ k += splitted.shift()
49
+ if (k in val) {
50
+ val = val[k]
51
+ k = ''
52
+ } else {
53
+ k += '_'
54
+ }
55
+ }
56
+
57
+ return val
58
+ }
59
+
60
+ const _propagateToChild = ({ parentElement, childElement, parentFieldValue }, row, childRow, enumerable) => {
61
+ if (!childElement || !childElement.parent.elements[childElement.name]) return
62
+ if (parentElement) {
63
+ const prefix = prefixForStruct(parentElement)
64
+ if (prefix) {
65
+ const nested = _getNestedVal(row, prefix)
66
+ _set(childRow, nested[parentElement.name], childElement, enumerable)
67
+ } else {
68
+ _set(childRow, row[parentElement.name], childElement, enumerable)
69
+ }
70
+ } else if (parentFieldValue !== undefined) {
71
+ _set(childRow, parentFieldValue, childElement, enumerable)
72
+ }
73
+ }
74
+
75
+ const _propagateToParent = ({ parentElement, childElement, deep }, childRow, row, enumerable) => {
76
+ if (deep) {
77
+ _propagateToParent(deep.propagation, childRow[deep.targetName], childRow, enumerable)
78
+ }
79
+ if (parentElement && childElement && childRow && childElement.name in childRow) {
80
+ _set(row, childRow[childElement.name], parentElement, enumerable)
81
+ }
82
+ }
83
+
84
+ module.exports = (
85
+ tKey,
86
+ row,
87
+ foreignKeyPropagations,
88
+ isCompositionEffective,
89
+ { deleteAssocs = false, enumerable = true } = {}
90
+ ) => {
91
+ if (!row || !(tKey in row)) return
92
+ if (row[tKey] === null) {
93
+ for (const foreignKeyPropagation of foreignKeyPropagations) {
94
+ if (!foreignKeyPropagation.fillChild) {
95
+ _set(row, null, foreignKeyPropagation.parentElement, enumerable)
96
+ }
97
+ }
98
+ if (deleteAssocs && !isCompositionEffective) delete row[tKey]
99
+ return
100
+ }
101
+
102
+ const childRows = Array.isArray(row[tKey]) ? row[tKey] : [row[tKey]]
103
+
104
+ for (const childRow of childRows) {
105
+ if (!childRow) return
106
+
107
+ for (const foreignKeyPropagation of foreignKeyPropagations) {
108
+ if (foreignKeyPropagation.fillChild) {
109
+ // propagate or generate in parent
110
+ const pk = foreignKeyPropagation.parentElement && foreignKeyPropagation.parentElement.name
111
+ if (pk && !(pk in row)) _propagateToParent(foreignKeyPropagation, childRow, row, enumerable)
112
+ if (!(pk in row)) _generateParentField(foreignKeyPropagation, row, enumerable)
113
+
114
+ if (isCompositionEffective) _propagateToChild(foreignKeyPropagation, row, childRow, enumerable)
115
+ } else {
116
+ _generateChildField(foreignKeyPropagation, childRow, enumerable)
117
+ _propagateToParent(foreignKeyPropagation, childRow, row, enumerable)
118
+ }
119
+ }
120
+ }
121
+ if (deleteAssocs && !isCompositionEffective) delete row[tKey]
122
+ }
@@ -612,7 +612,7 @@ const _newQuery = (query, event, model, service) => {
612
612
  }[event]
613
613
  const newQuery = Object.create(query)
614
614
  const transitions = _entityTransitionsForTarget(query[event][_prop], model, service)
615
- newQuery[event] = (transitions[0] && _func(newQuery, transitions, service)) || { ...query[event] }
615
+ newQuery[event] = (transitions?.[0] && _func(newQuery, transitions, service)) || { ...query[event] }
616
616
  return newQuery
617
617
  }
618
618
 
@@ -67,7 +67,7 @@ const _getNextTarget = (model, element, currentPath = []) => {
67
67
  * @param {object} targetEntity The target entity which needs to be traversed
68
68
  * @param {object} callbacks
69
69
  * @param {function} callbacks.pick Callback function to pick elements. If it returns a truthy value, the element will be picked. The returned value is part of the template.
70
- * @param {function} callbacks.ignore Callback function to ignore elements. If it returns a truthy value, the element will be ignored.
70
+ * @param {function} callbacks.ignore Callback function to ignore the target of an element. If it returns a truthy value, the element's target will be ignored.
71
71
  * @param {object} [parent=null] The parent entity
72
72
  * @param {Map} [_entityMap] This parameter is an implementation side-effect — don't use it
73
73
  * @param {array} [targetPath=[]]
@@ -92,8 +92,6 @@ function _getTemplate(model, cache, targetEntity, callbacks, parent = null, _ent
92
92
 
93
93
  for (const elementName in elements) {
94
94
  const element = elements[elementName]
95
- if (ignore && ignore(element, targetEntity, parent)) continue
96
-
97
95
  _pick(pick, element, targetEntity, parent, templateElements, elementName)
98
96
 
99
97
  if (element.items) {
@@ -101,6 +99,7 @@ function _getTemplate(model, cache, targetEntity, callbacks, parent = null, _ent
101
99
  }
102
100
 
103
101
  const { nextTargetName, nextTarget } = _getNextTarget(model, element, currentPath)
102
+ if (ignore && ignore(element)) continue
104
103
  const nextTargetCached = _entityMap.get(nextTargetName)
105
104
 
106
105
  if (nextTargetCached) {
@@ -696,7 +696,7 @@ class JoinCQNFromExpanded {
696
696
 
697
697
  const assoc = entity.associations[column.ref[0]]
698
698
  if (assoc.is2one && assoc.on) {
699
- const onCond = expandedEntity._relations[assoc.name].join('target', 'source')
699
+ const onCond = entity._relations[assoc.name].join('target', 'source')
700
700
  const xpr = onCond[0].xpr
701
701
  const fks = (xpr && xpr.filter(e => e.ref && e.ref[0] === 'target').map(e => e.ref[1])) || []
702
702
  for (const k of fks) {
@@ -30,9 +30,13 @@ class RawToExpanded {
30
30
  if (each._conversionMapper) for (const [k, v] of [...each._conversionMapper]) conversionMapper.set(k, v)
31
31
  }
32
32
 
33
- for (let i = 0, length = this._queries.length; i < length; i++) {
33
+ const queryResults = await Promise.all(this._queries)
34
+ // NOTE: this doesn't work:
35
+ // for (let each of this._queries) await each
36
+
37
+ for (let i = 0, length = queryResults.length; i < length; i++) {
34
38
  const { _toManyTree: toManyTree = [] } = queries[i]
35
- const result = await this._queries[i]
39
+ const result = queryResults[i]
36
40
  if (toManyTree.length === 0) {
37
41
  this._parseMainResult(result, mappings, conversionMapper, toManyTree)
38
42
  } else {
@@ -249,10 +253,7 @@ class RawToExpanded {
249
253
  * @returns {Promise<Array>} The complete expanded result set.
250
254
  */
251
255
  const rawToExpanded = (configs, queries, one, rootEntity) => {
252
- return new RawToExpanded(configs, queries, one, rootEntity).toExpanded().catch(err => {
253
- Promise.all(queries).catch(() => {})
254
- throw err
255
- })
256
+ return new RawToExpanded(configs, queries, one, rootEntity).toExpanded()
256
257
  }
257
258
 
258
259
  module.exports = rawToExpanded
@@ -14,7 +14,7 @@ const cds = require('../../cds')
14
14
  const normalizeTimeData = require('../utils/normalizeTimeData')
15
15
 
16
16
  const { enrichDataWithKeysFromWhere } = require('../../common/utils/keys')
17
- const propagateForeignKeys = require('../utils/propagateForeignKeys')
17
+ const propagateForeignKeys = require('../../common/utils/propagateForeignKeys')
18
18
  const getTemplate = require('../../common/utils/template')
19
19
  const templateProcessor = require('../../common/utils/templateProcessor')
20
20
 
@@ -32,8 +32,8 @@ const _processComplexCategory = ({ row, key, val, category, req, element }) => {
32
32
  category = category.category
33
33
 
34
34
  // propagate keys
35
- if (category === 'propagateForeignKeys' && key in row) {
36
- propagateForeignKeys(key, row, element._foreignKeys, element.isComposition)
35
+ if (category === 'propagateForeignKeys') {
36
+ propagateForeignKeys(key, row, element._foreignKeys, element.isComposition, { deleteAssocs: true })
37
37
  return
38
38
  }
39
39
 
@@ -176,7 +176,10 @@ const _pickDraft = element => {
176
176
  // collect actions to apply
177
177
  const categories = []
178
178
 
179
- if (element.virtual) categories.push('virtual')
179
+ if (_isVirtualOrCalculated(element)) {
180
+ categories.push('virtual')
181
+ return { categories } // > no need to continue
182
+ }
180
183
 
181
184
  if (element.default && !DRAFT_COLUMNS_MAP[element.name]) {
182
185
  categories.push({ category: 'default', args: element })
@@ -306,7 +306,7 @@ class InsertBuilder extends BaseBuilder {
306
306
  const purelyManagedColumnValues = this._getAnnotatedInsertColumnValues(annotatedColumns, purelyManagedColumns)
307
307
 
308
308
  this._addUuidToColumns(columns, flattenColumnMap)
309
- columns.push(...flattenColumnMap.keys())
309
+ columns.push(...Array.from(flattenColumnMap.keys()).filter(k => !columns.includes(k)))
310
310
 
311
311
  this._addEntries(valuesArray, { columns, flattenColumnMap, purelyManagedColumnValues, insertAnnotatedColumns })
312
312
 
@@ -1,4 +1,5 @@
1
1
  const cds = require('../cds')
2
+ const LOG = cds.log('mtx')
2
3
 
3
4
  const { validateExtension } = require('./validation')
4
5
  const handleDefaults = require('./defaults')
@@ -16,6 +17,7 @@ const add = async function (req) {
16
17
  const extCsn = _isCSN(extension) ? JSON.parse(extension) : cds.parse.cdl(extension)
17
18
  if (extCsn.requires) delete extCsn.requires
18
19
 
20
+ LOG.info(`validating extension '${tag}' ...`)
19
21
  const { 'cds.xt.ModelProviderService': mps } = cds.services
20
22
  const csn = await mps.getCsn(tenant, ['*'])
21
23
  validateExtension(extCsn, csn, req)
@@ -26,6 +28,7 @@ const add = async function (req) {
26
28
  INSERT.into('cds.xt.Extensions').entries([{ ID, tag, csn: JSON.stringify(extCsn), activated: activate }])
27
29
  )
28
30
  const njCsn = cds.compile.for.nodejs(csn)
31
+ LOG.info(`activating extension to '${activate}' ...`)
29
32
  if (activate === 'propertyBag' && extCsn.extensions)
30
33
  extCsn.extensions.forEach(async ext => await handleDefaults(ext, njCsn))
31
34
  if (activate === 'database') await activateExt(ID, tag, tenant, njCsn)
@@ -42,23 +42,25 @@ const _removeExtendedFields = (columns, extFields, alias) => {
42
42
 
43
43
  const _transformUnion = (req, model) => {
44
44
  // second element is active entity
45
- const name = req.target.name.SET ? req.target.name.SET.args[1]._target.name : req.target.name
46
- const extFields = getExtendedFields(name, model)
47
- _addBackPack(req.query.SELECT.columns, extFields)
48
- _removeExtendedFields(req.query.SELECT.columns, extFields)
49
-
50
- _addBackPack(
51
- req.query.SELECT.from.SET.args[0].SELECT.columns,
52
- extFields,
53
- req.query.SELECT.from.SET.args[0].SELECT.from.args[0].as
54
- )
55
- _addBackPack(req.query.SELECT.from.SET.args[1].SELECT.columns, extFields)
56
- _removeExtendedFields(
57
- req.query.SELECT.from.SET.args[0].SELECT.columns,
58
- extFields,
59
- req.query.SELECT.from.SET.args[0].SELECT.from.args[0].as
60
- )
61
- _removeExtendedFields(req.query.SELECT.from.SET.args[1].SELECT.columns, extFields)
45
+ if (req.target) {
46
+ const name = req.target.name.SET ? req.target.name.SET.args[1]._target.name : req.target.name
47
+ const extFields = getExtendedFields(name, model)
48
+ _addBackPack(req.query.SELECT.columns, extFields)
49
+ _removeExtendedFields(req.query.SELECT.columns, extFields)
50
+
51
+ _addBackPack(
52
+ req.query.SELECT.from.SET.args[0].SELECT.columns,
53
+ extFields,
54
+ req.query.SELECT.from.SET.args[0].SELECT.from.args[0].as
55
+ )
56
+ _addBackPack(req.query.SELECT.from.SET.args[1].SELECT.columns, extFields)
57
+ _removeExtendedFields(
58
+ req.query.SELECT.from.SET.args[0].SELECT.columns,
59
+ extFields,
60
+ req.query.SELECT.from.SET.args[0].SELECT.from.args[0].as
61
+ )
62
+ _removeExtendedFields(req.query.SELECT.from.SET.args[1].SELECT.columns, extFields)
63
+ }
62
64
  }
63
65
 
64
66
  const _getAliasedEntitiesForJoin = (args, model) => {
@@ -111,7 +113,7 @@ function transformExtendedFieldsREAD(req) {
111
113
  _transformColumns(req.query.SELECT.columns, target.name, this.model)
112
114
 
113
115
  if (req.query.SELECT.from.SET) return _transformUnion(req, this.model) // union
114
- if (req.query.SELECT.from.join) return _transformJoin(req, this.model) // join
116
+ if (req.query.SELECT.from.join && req.query.SELECT.from.args) return _transformJoin(req, this.model) // join
115
117
  }
116
118
 
117
119
  module.exports = {
@@ -22,7 +22,7 @@ const _compileProject = async function (extension, req) {
22
22
  if (err.messages) req.reject(400, getCompilerError(err.messages))
23
23
  else throw err
24
24
  } finally {
25
- ;(fs.promises.rm || fs.promises.rmdir)(root, { recursive: true, force: true }).catch(() => {})
25
+ fs.promises.rm(root, { recursive: true, force: true }).catch(() => {})
26
26
  }
27
27
 
28
28
  return { csn, files }
@@ -68,7 +68,7 @@ const pull = async function (req) {
68
68
  // for (const file of i18nFiles) await _copyFile(file, temp)
69
69
  tgz = await packTarArchive(temp)
70
70
  } finally {
71
- ;(fs.promises.rm || fs.promises.rmdir)(temp, { recursive: true, force: true }).catch(() => {})
71
+ fs.promises.rm(temp, { recursive: true, force: true }).catch(() => {})
72
72
  }
73
73
 
74
74
  return tgz
@@ -85,31 +85,31 @@ const push = async function (req) {
85
85
  if (tenant) cds.context = { tenant }
86
86
 
87
87
  // remove current extension with tag
88
- let currentExt
89
88
  if (tag) {
90
- currentExt = await cds.db.run(SELECT.from('cds.xt.Extensions').where({ tag }))
91
- if (currentExt.length) await cds.db.run(DELETE.from('cds.xt.Extensions').where({ tag }))
89
+ await DELETE.from('cds.xt.Extensions').where({ tag })
92
90
  }
93
91
 
94
92
  LOG.info(`validating extension '${tag}' ...`)
95
93
  // validation
96
94
  const { 'cds.xt.ModelProviderService': mps } = cds.services
95
+ // REVISIT: Isn't that also done during activate?
97
96
  const csn = await mps.getCsn(tenant, Object.keys(cds.context.features || {}))
98
97
  try {
99
98
  cds.extend(csn).with(extCsn)
100
99
  } catch (err) {
101
- if (currentExt && currentExt.length) {
102
- await cds.db.run(INSERT.into('cds.xt.Extensions').entries(currentExt)) // REVISIT: why did we eagerly delete that at all above?
103
- }
104
100
  return req.reject(400, getCompilerError(err.messages))
105
101
  }
106
102
  await linter(extCsn, csn, files, req)
107
103
 
108
104
  // insert and activate extension
109
105
  const ID = cds.utils.uuid()
110
- await cds.db.run(
111
- INSERT.into('cds.xt.Extensions').entries([{ ID, csn: JSON.stringify(extCsn), sources, activated: 'database', tag }])
112
- )
106
+ await INSERT.into('cds.xt.Extensions').entries({
107
+ ID,
108
+ csn: JSON.stringify(extCsn),
109
+ sources,
110
+ activated: 'database',
111
+ tag
112
+ })
113
113
 
114
114
  LOG.info(`activating extension '${tag}' ...`)
115
115
  await activate(ID, null, tenant)
@@ -43,7 +43,8 @@ module.exports = {
43
43
  )
44
44
  response.send(data)
45
45
  } catch (error) {
46
- error.message = `Authentication failed with root cause '${error.message}'. Passcode URL: https://${parsedUrl.hostname}/passcode`
46
+ const rootCause = error.response?.data ? JSON.stringify(error.response?.data) : error.message
47
+ error.message = `Authentication failed with root cause '${rootCause}'. Passcode URL: https://${parsedUrl.hostname}/passcode`
47
48
  const {
48
49
  constructor: { name },
49
50
  message
@@ -8,7 +8,7 @@ const EXT_BACK_PACK = 'extensions__'
8
8
 
9
9
  const getTargetRead = req => {
10
10
  let name = ''
11
- if (req.query.SELECT.from.join) {
11
+ if (req.query.SELECT.from.join && req.query.SELECT.from.args) {
12
12
  // join
13
13
  name = req.query.SELECT.from.args.find(arg => arg.ref && arg.ref[0] !== 'DRAFT.DraftAdministativeData').ref[0]
14
14
  } else if (req.target.name.SET) {
@@ -63,15 +63,17 @@ const hasExtendedEntity = (req, model) => {
63
63
  return true
64
64
  }
65
65
 
66
- if (req.query.SELECT.from.join) {
66
+ if (req.query.SELECT.from.join && req.query.SELECT.from.args) {
67
67
  return _hasExtendedEntityArgs(req.query.SELECT.from.args, model)
68
68
  }
69
69
 
70
- if (req.target.name.SET) {
71
- return isExtendedEntity(req.target.name.SET.args[0]._target.name, model)
72
- }
70
+ if (req.target) {
71
+ if (req.target.name.SET) {
72
+ return isExtendedEntity(req.target.name.SET.args[0]._target.name, model)
73
+ }
73
74
 
74
- return isExtendedEntity(req.target.name, model)
75
+ return isExtendedEntity(req.target.name, model)
76
+ }
75
77
  }
76
78
 
77
79
  const getExtendedFields = (entityName, model) => {
@@ -1,11 +1,9 @@
1
1
  const cds = require('../../cds')
2
- const { INSERT, SELECT, UPDATE } = cds.ql
2
+ const { INSERT, UPDATE } = cds.ql
3
3
 
4
4
  const onDraftActivate = require('./activate')._handler
5
5
  const { isNavigationToMany } = require('../utils/req')
6
- const { getKeysCondition } = require('../utils/where')
7
6
  const { ensureDraftsSuffix } = require('../utils/handler')
8
- const { DRAFT_COLUMNS_MAP } = require('../../common/constants/draft')
9
7
 
10
8
  const _getUpdateDraftAdminCQN = ({ user, timestamp }, draftUUID) => {
11
9
  return UPDATE('DRAFT.DraftAdministrativeData')
@@ -1,13 +1,7 @@
1
1
  const cds = require('../../cds')
2
2
  const { UPDATE, SELECT } = cds.ql
3
3
 
4
- const {
5
- getUpdateDraftAdminCQN,
6
- removeDraftUUIDIfNecessary,
7
- ensureDraftsSuffix,
8
- ensureNoDraftsSuffix,
9
- addColumnAlias
10
- } = require('../utils/handler')
4
+ const { getUpdateDraftAdminCQN, ensureDraftsSuffix, ensureNoDraftsSuffix, addColumnAlias } = require('../utils/handler')
11
5
  const { getKeysCondition } = require('../utils/where')
12
6
  const { getColumns } = require('../../cds-services/services/utils/columns')
13
7
  const { DRAFT_COLUMNS_CQN } = require('../../common/constants/draft')
@@ -160,7 +160,7 @@ const isActiveEntityRequested = where => {
160
160
 
161
161
  while (where[i]) {
162
162
  if (where[i].xpr) {
163
- const isRequested = isActiveEntityRequested(where.xpr)
163
+ const isRequested = isActiveEntityRequested(where[i].xpr)
164
164
  if (isRequested) return true
165
165
  }
166
166
  if (
@@ -19,7 +19,7 @@ const authorizedRequest = ({ method, uri, path, oa2, tenant, dataObj, headers, t
19
19
  if (dataObj) {
20
20
  data = JSON.stringify(dataObj)
21
21
  httpOptions.headers['Content-Type'] = 'application/json'
22
- httpOptions.headers['Content-Length'] = data.length
22
+ httpOptions.headers['Content-Length'] = Buffer.byteLength(data)
23
23
  }
24
24
 
25
25
  if (headers) {
@@ -34,7 +34,6 @@ class EMManagement {
34
34
  this.namespace = namespace
35
35
  this.LOG = LOG
36
36
  }
37
-
38
37
  async getQueue(queueName = this.queueName) {
39
38
  this.LOG._info &&
40
39
  this.LOG.info(
@@ -303,7 +302,7 @@ class EMManagement {
303
302
  grantType: 'client_credentials',
304
303
  clientId: this.optionsMessagingREST.oa2.client,
305
304
  clientSecret: this.optionsMessagingREST.oa2.secret,
306
- tokenUrl: this.optionsMessagingREST.oa2.endpoint
305
+ tokenUrl: this.optionsMessagingREST.oa2.endpoint // this is the changed tokenUrl
307
306
  }
308
307
  }
309
308
 
@@ -24,8 +24,8 @@ const _sanitizeHeaders = headers => {
24
24
 
25
25
  const _executeHttpRequest = async ({ requestConfig, destination, destinationOptions, jwt }) => {
26
26
  const { executeHttpRequestWithOrigin } = cloudSdk()
27
-
28
27
  const destinationName = typeof destination === 'string' && destination
28
+
29
29
  if (destinationName) {
30
30
  destination = { destinationName, ...(resolveDestinationOptions(destinationOptions, jwt) || {}) }
31
31
  } else if (destination.forwardAuthToken) {
@@ -59,7 +59,13 @@ const _executeHttpRequest = async ({ requestConfig, destination, destinationOpti
59
59
 
60
60
  // cloud sdk requires a new mechanism to differentiate the priority of headers
61
61
  // "custom" keeps the highest priority as before
62
- requestConfig = { ...requestConfig, headers: { custom: { ...requestConfig.headers } } }
62
+ requestConfig = {
63
+ ...(cds.env?.remote?.max_body_length && { maxBodyLength: cds.env.remote.max_body_length }),
64
+ ...requestConfig,
65
+ headers: {
66
+ custom: { ...requestConfig.headers }
67
+ }
68
+ }
63
69
 
64
70
  return executeHttpRequestWithOrigin(destination, requestConfig, requestOptions)
65
71
  }
@@ -145,10 +151,12 @@ function _defineProperty(obj, property, value) {
145
151
  const map = (..._) => _defineProperty(_map.call(obj, ..._), property, value)
146
152
  props.map = { value: map, enumerable: false, configurable: true, writable: true }
147
153
  }
154
+
148
155
  props[property] = { value: value, enumerable: false, configurable: true, writable: true }
149
156
  for (const prop in props) {
150
157
  Object.defineProperty(obj, prop, props[prop])
151
158
  }
159
+
152
160
  return obj
153
161
  }
154
162
 
@@ -156,14 +164,17 @@ function _normalizeMetadata(prefix, data, results) {
156
164
  const target = results !== undefined ? results : data
157
165
  if (typeof target !== 'object' || target === null) return target
158
166
  const metadataKeys = Object.keys(data).filter(k => prefix.test(k))
167
+
159
168
  for (const k of metadataKeys) {
160
169
  const $ = k.replace(prefix, '$')
161
170
  _defineProperty(target, $, data[k])
162
171
  delete target[k]
163
172
  }
173
+
164
174
  if (Array.isArray(target)) {
165
175
  return target.map(row => _normalizeMetadata(prefix, row))
166
176
  }
177
+
167
178
  // check properties for all and prop.results for odata v2
168
179
  for (const [key, value] of Object.entries(target)) {
169
180
  if (value && typeof value === 'object') {
@@ -171,6 +182,7 @@ function _normalizeMetadata(prefix, data, results) {
171
182
  target[key] = _normalizeMetadata(prefix, value, nestedResults)
172
183
  }
173
184
  }
185
+
174
186
  return target
175
187
  }
176
188
  const _getPurgedRespActionFunc = (data, returnType) => {
@@ -181,6 +193,7 @@ const _getPurgedRespActionFunc = (data, returnType) => {
181
193
  return data[key]
182
194
  }
183
195
  }
196
+
184
197
  return data
185
198
  }
186
199
 
@@ -198,6 +211,7 @@ const _purgeODataV2 = (data, target, returnType, reqHeaders) => {
198
211
  ieee754Compatible,
199
212
  exponentialDecimals
200
213
  )
214
+
201
215
  return _normalizeMetadata(/^__/, data, convertedResponse)
202
216
  }
203
217
 
@@ -217,6 +231,7 @@ const _getSanitizedError = (e, reqOptions, options = { suppressRemoteResponseBod
217
231
  url: e.config ? e.config.baseURL + e.config.url : reqOptions.url,
218
232
  headers: e.config ? e.config.headers : reqOptions.headers
219
233
  }
234
+
220
235
  if (options.batchRequest) {
221
236
  e.request.body = reqOptions.data
222
237
  }
@@ -227,9 +242,11 @@ const _getSanitizedError = (e, reqOptions, options = { suppressRemoteResponseBod
227
242
  statusText: e.response.statusText,
228
243
  headers: e.response.headers
229
244
  }
245
+
230
246
  if (e.response.data && !options.suppressRemoteResponseBody) {
231
247
  response.body = e.response.data
232
248
  }
249
+
233
250
  e.response = response
234
251
  }
235
252
 
@@ -270,12 +287,7 @@ const run = async (
270
287
  response = await _executeHttpRequest({ requestConfig, destination, destinationOptions, jwt })
271
288
  } catch (e) {
272
289
  // > axios received status >= 400 -> gateway error
273
- const msg =
274
- (e.response &&
275
- e.response.data &&
276
- e.response.data.error &&
277
- ((e.response.data.error.message && e.response.data.error.message.value) || e.response.data.error.message)) ||
278
- e.message
290
+ const msg = e?.response?.data?.error?.message?.value ?? e?.response?.data?.error?.message ?? e.message
279
291
  e.message = msg ? 'Error during request to remote service: \n' + msg : 'Request to remote service failed.'
280
292
 
281
293
  const sanitizedError = _getSanitizedError(e, requestConfig, {
@@ -284,7 +296,6 @@ const run = async (
284
296
 
285
297
  const err = Object.assign(new Error(e.message), { statusCode: 502, reason: sanitizedError })
286
298
  LOG._warn && LOG.warn(err)
287
-
288
299
  throw err
289
300
  }
290
301
 
@@ -312,7 +323,6 @@ const run = async (
312
323
  })
313
324
 
314
325
  LOG._warn && LOG.warn(err)
315
-
316
326
  throw err
317
327
  }
318
328
 
@@ -331,6 +341,7 @@ const run = async (
331
341
  if (responseDataSplitted[1].startsWith('HTTP/1.1 2')) {
332
342
  response.data = contentJSON
333
343
  }
344
+
334
345
  if (responseDataSplitted[1].startsWith('HTTP/1.1 4') || responseDataSplitted[1].startsWith('HTTP/1.1 5')) {
335
346
  const innerError = contentJSON.error || contentJSON
336
347
  innerError.status = Number(responseDataSplitted[1].match(/HTTP.*(\d{3})/m)[1])
@@ -357,6 +368,7 @@ const run = async (
357
368
  }
358
369
  return _purgeODataV4(response.data)
359
370
  }
371
+
360
372
  return response.data
361
373
  }
362
374
 
@@ -368,6 +380,7 @@ const getJwt = req => {
368
380
  return token[1]
369
381
  }
370
382
  }
383
+
371
384
  return null
372
385
  }
373
386
 
@@ -382,9 +395,11 @@ const _cqnToReqOptions = (query, service, req) => {
382
395
  .replace(/\( /g, '(')
383
396
  .replace(/ \)/g, ')')
384
397
  }
398
+
385
399
  if (queryObject.method !== 'GET' && queryObject.method !== 'HEAD') {
386
400
  reqOptions.data = kind === 'odata-v2' ? convertV2PayloadData(queryObject.body, req.target) : queryObject.body
387
401
  }
402
+
388
403
  return reqOptions
389
404
  }
390
405
 
@@ -395,9 +410,11 @@ const _stringToReqOptions = (query, data, target) => {
395
410
  method: cleanQuery.substring(0, blankIndex).toUpperCase(),
396
411
  url: encodeURI(formatPath(cleanQuery.substring(blankIndex, cleanQuery.length).trim()))
397
412
  }
413
+
398
414
  if (data && reqOptions.method !== 'GET' && reqOptions.method !== 'HEAD') {
399
415
  reqOptions.data = this.kind === 'odata-v2' ? Object.assign({}, convertV2PayloadData(data, target)) : data
400
416
  }
417
+
401
418
  return reqOptions
402
419
  }
403
420
 
@@ -412,10 +429,12 @@ const _pathToReqOptions = (method, path, data, target) => {
412
429
  // normalize in case parts[2] already starts with /
413
430
  url = url.replace(/^\/\//, '/')
414
431
  }
432
+
415
433
  const reqOptions = { method, url }
416
434
  if (data && reqOptions.method !== 'GET' && reqOptions.method !== 'HEAD') {
417
435
  reqOptions.data = this.kind === 'odata-v2' ? Object.assign({}, convertV2PayloadData(data, target)) : data
418
436
  }
437
+
419
438
  return reqOptions
420
439
  }
421
440