@sap/cds 9.7.0 → 9.8.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.
Files changed (41) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/_i18n/i18n_en_US_saptrc.properties +1 -56
  3. package/_i18n/messages_en_US_saptrc.properties +1 -92
  4. package/eslint.config.mjs +1 -1
  5. package/lib/compile/for/flows.js +86 -79
  6. package/lib/compile/for/lean_drafts.js +12 -0
  7. package/lib/compile/to/json.js +4 -2
  8. package/lib/env/defaults.js +1 -0
  9. package/lib/env/serviceBindings.js +15 -5
  10. package/lib/index.js +1 -1
  11. package/lib/log/cds-error.js +33 -20
  12. package/lib/req/spawn.js +2 -2
  13. package/lib/srv/bindings.js +6 -13
  14. package/lib/srv/cds.Service.js +8 -36
  15. package/lib/srv/protocols/hcql.js +19 -2
  16. package/lib/srv/protocols/http.js +1 -1
  17. package/lib/utils/cds-utils.js +25 -16
  18. package/lib/utils/tar-win.js +106 -0
  19. package/lib/utils/tar.js +23 -158
  20. package/libx/_runtime/common/generic/crud.js +8 -7
  21. package/libx/_runtime/common/generic/sorting.js +7 -3
  22. package/libx/_runtime/common/utils/resolveView.js +47 -40
  23. package/libx/_runtime/common/utils/rewriteAsterisks.js +1 -0
  24. package/libx/_runtime/fiori/lean-draft.js +11 -2
  25. package/libx/_runtime/messaging/kafka.js +6 -5
  26. package/libx/_runtime/remote/Service.js +14 -2
  27. package/libx/_runtime/remote/utils/client.js +2 -4
  28. package/libx/_runtime/remote/utils/query.js +4 -4
  29. package/libx/odata/middleware/batch.js +316 -339
  30. package/libx/odata/middleware/create.js +0 -5
  31. package/libx/odata/middleware/delete.js +2 -6
  32. package/libx/odata/middleware/operation.js +10 -8
  33. package/libx/odata/middleware/read.js +0 -10
  34. package/libx/odata/middleware/stream.js +1 -0
  35. package/libx/odata/middleware/update.js +0 -6
  36. package/libx/odata/parse/afterburner.js +47 -22
  37. package/libx/odata/parse/cqn2odata.js +6 -1
  38. package/libx/odata/parse/grammar.peggy +14 -2
  39. package/libx/odata/parse/multipartToJson.js +2 -1
  40. package/libx/odata/parse/parser.js +1 -1
  41. package/package.json +2 -2
@@ -11,19 +11,19 @@ module.exports = cds.service.impl(function () {
11
11
  this.on(['CREATE', 'READ', 'UPDATE', 'UPSERT', 'DELETE'], '*', async function handle_crud_requests(req) {
12
12
 
13
13
  if (!cds.db)
14
- return req.reject ('NO_DATABASE_CONNECTION') // REVISIT: error message
14
+ return req.reject('NO_DATABASE_CONNECTION') // REVISIT: error message
15
15
 
16
16
  if (!req.query)
17
- return req.reject (501, 'The request has no query and cannot be served generically.')
17
+ return req.reject(501, 'The request has no query and cannot be served generically.')
18
18
 
19
19
  if (typeof req.query !== 'string' && req.target?._hasPersistenceSkip)
20
- return req.reject (501, `Entity "${req.target.name}" is annotated with "@cds.persistence.skip" and cannot be served generically.`)
20
+ return req.reject(501, `Entity "${req.target.name}" is annotated with "@cds.persistence.skip" and cannot be served generically.`)
21
21
 
22
22
  // validate that all elements in path exist on db, if necessary
23
23
  // - INSERT has no where clause to do this in one roundtrip
24
24
  // - SELECT returns [] -> really empty collection or invalid path?
25
25
  const subject = req.query.INSERT?.into || req.query.SELECT?.from
26
- const pathExistsQuery = subject?.ref?.length > 1 && SELECT(1).from({ ref: subject.ref.slice(0,-1) })
26
+ const pathExistsQuery = subject?.ref?.length > 1 && SELECT(1).from({ ref: subject.ref.slice(0, -1) })
27
27
 
28
28
  if (req.event === 'CREATE' && pathExistsQuery) {
29
29
  // REVISIT: Why dont't we just run the insert and check affected rows?
@@ -33,10 +33,10 @@ module.exports = cds.service.impl(function () {
33
33
 
34
34
  if (req.event in { DELETE: 1, UPDATE: 1 } && req.target?._isSingleton) {
35
35
  if (req.event === 'DELETE' && !req.target['@odata.singleton.nullable'])
36
- return req.reject (400, 'SINGLETON_NOT_NULLABLE')
36
+ return req.reject(400, 'SINGLETON_NOT_NULLABLE')
37
37
 
38
38
  const selectSingleton = SELECT.one(req.target)
39
- const keyColumns = [...(req.target.keys||[])].filter(e => !e.isAssociation).map(e => e.name)
39
+ const keyColumns = [...(req.target.keys || [])].filter(e => !e.isAssociation).map(e => e.name)
40
40
 
41
41
  // if no keys available, select all columns so we can delete the singleton with same content
42
42
  if (keyColumns.length) selectSingleton.columns(keyColumns)
@@ -54,7 +54,8 @@ module.exports = cds.service.impl(function () {
54
54
 
55
55
  if (req.event === 'READ' && req.query?.SELECT && req.locale) req.query.SELECT.localized ??= true
56
56
 
57
- const result = await cds.run (req.query, req.data)
57
+ // REVISIT for cds^10: can we always use cds.db.dispatch(req)?
58
+ const result = req.iterator && !req.objectMode ? await cds.db.dispatch(req) : await cds.run(req.query, req.data)
58
59
 
59
60
  if (req.event === 'READ') {
60
61
  // do not execute additional select to distinguish between 412 and 404
@@ -50,6 +50,12 @@ const _addDefaultSortOrder = (req, select) => {
50
50
  )
51
51
  }
52
52
 
53
+ const containsAggregation = column => {
54
+ if (column.func) return true
55
+ if (column.xpr) return column.xpr.some(xpr => containsAggregation(xpr))
56
+ return false
57
+ }
58
+
53
59
  /**
54
60
  * 1. query options --> already set in req.query
55
61
  * 2. orders from view
@@ -63,9 +69,7 @@ const handle_sorting = function (req) {
63
69
  let select = req.query.SELECT
64
70
 
65
71
  // do not sort for /$count queries or queries only using aggregations
66
- if (select.columns && select.columns.length && select.columns.every(col => col.func)) {
67
- return
68
- }
72
+ if (select.columns?.length && select.columns.every(col => containsAggregation(col))) return
69
73
 
70
74
  if (select.from && select.from.SELECT) {
71
75
  // add default sort to root query
@@ -53,15 +53,15 @@ const _inverseTransition = transition => {
53
53
  return inverseTransition
54
54
  }
55
55
 
56
- const revertData = (data, transition, service, options) => {
56
+ const revertData = (data, transition, service) => {
57
57
  if (!transition || !transition.mapping.size) return data
58
58
  const inverseTransition = _inverseTransition(transition)
59
59
  return Array.isArray(data)
60
- ? data.map(entry => _newData(entry, inverseTransition, true, service, options))
61
- : _newData(data, inverseTransition, true, service, options)
60
+ ? data.map(entry => _newData(entry, inverseTransition, true, service))
61
+ : _newData(data, inverseTransition, true, service)
62
62
  }
63
63
 
64
- const _newSubData = (val, key, transition, el, inverse, service, options) => {
64
+ const _newSubData = (val, key, transition, el, inverse, service, options = {}) => {
65
65
  if ((!Array.isArray(val) && typeof val === 'object') || (Array.isArray(val) && val.length !== 0)) {
66
66
  let mapped = transition.mapping.get(key)
67
67
  if (!mapped) {
@@ -70,7 +70,7 @@ const _newSubData = (val, key, transition, el, inverse, service, options) => {
70
70
  }
71
71
 
72
72
  if (!mapped.transition) {
73
- const subTransition = getTransition(el._target, service, undefined, options?.event, { abort: options?.abort })
73
+ const subTransition = getTransition(el._target, service, null, options.event)
74
74
  mapped.transition = inverse ? _inverseTransition(subTransition) : subTransition
75
75
  }
76
76
 
@@ -196,7 +196,7 @@ const _newColumns = (columns = [], transition, service, withAlias = false, optio
196
196
 
197
197
  // reuse _newColumns with new transition
198
198
  const expandTarget = def._target
199
- const subtransition = getTransition(expandTarget, service, undefined, options.event, { abort: options.abort })
199
+ const subtransition = getTransition(expandTarget, service, null, options.event)
200
200
  mapped.transition = subtransition
201
201
  newColumn.expand = _newColumns(column.expand, subtransition, service, withAlias, options)
202
202
  }
@@ -523,19 +523,26 @@ const _queryColumns = (target, columns = [], isAborted) => {
523
523
  return queryColumns
524
524
  }
525
525
 
526
- const _mappedValue = (col, alias) => {
526
+ const _mappedValue = (col, alias, target) => {
527
527
  const key = col.as || col.ref[0]
528
528
 
529
529
  if (col.ref) {
530
- const columnRef = col.ref.filter(columnName => columnName !== alias)
530
+ let columnRef = col.ref.filter(columnName => columnName !== alias)
531
+
532
+ if (columnRef.length > 1 && target) {
533
+ const firstElement = target.elements?.[columnRef[0]]
534
+ if (firstElement?.foreignKeys) {
535
+ // It's a managed association - use foreignKeys property to get the FK column name
536
+ if (columnRef[1] in firstElement.foreignKeys) columnRef = [`${firstElement.name}_${columnRef[1]}`]
537
+ }
538
+ }
539
+
531
540
  return [key, { ref: columnRef }]
532
541
  }
533
542
 
534
543
  return [key, { val: col.val }]
535
544
  }
536
545
 
537
- const getDBTable = target => cds.db.resolve.table(target)
538
-
539
546
  const _appendForeignKeys = (newColumns, target, columns, { as, ref = [] }) => {
540
547
  const el = target.elements[as] || target.query._target?.elements[ref.at(-1)]
541
548
 
@@ -578,26 +585,27 @@ const _checkForForbiddenViews = (queryTarget, event) => {
578
585
  }
579
586
  }
580
587
 
581
- const _getTransitionData = (target, columns, service, options) => {
582
- let { abort, skipForbiddenViewCheck, event } = options
583
- // REVISIT revert after cds-dbs pr
584
- if (!abort) abort = service.resolve.abortDB
585
- // REVISIT: Find less param polluting way to skip forbidden view check for reads
586
- if (!skipForbiddenViewCheck) _checkForForbiddenViews(target, event)
587
- const isAborted = abort(target)
588
+ const _getTransitionData = (target, columns, service, event) => {
589
+ _checkForForbiddenViews(target, event)
590
+
591
+ const _dbAbort = target =>
592
+ !!(Object.prototype.hasOwnProperty.call(target, '@cds.persistence.table') || !target.query?._target)
593
+ const _defaultAbort = target => target._service?.name === service.definition?.name
594
+ const _abort = service.isDatabaseService ? _dbAbort : _defaultAbort
595
+
596
+ const isAborted = _abort(target)
588
597
  columns = _queryColumns(target, columns, isAborted)
589
598
 
590
599
  if (isAborted) return { target, transitionColumns: columns }
591
600
 
592
601
  if (!target.query?._target) {
593
602
  // for cross service in x4 and DRAFT.DraftAdministrativeData we cannot abort properly
594
- // therefore return last resolved target
595
603
  if (cds.env.features.restrict_service_scope === false) return { target, transitionColumns: columns }
596
604
  return undefined
597
605
  } else {
598
606
  const newTarget = target.query._target
599
607
  // continue projection resolving for projections
600
- return _getTransitionData(newTarget, columns, service, options)
608
+ return _getTransitionData(newTarget, columns, service, event)
601
609
  }
602
610
  }
603
611
 
@@ -606,24 +614,20 @@ const _getTransitionData = (target, columns, service, options) => {
606
614
  *
607
615
  * @param queryTarget
608
616
  * @param service
609
- * @param skipForbiddenViewCheck
617
+ * @param _dummy - unused positional argument (for db-service < 2.9)
618
+ * @param event
610
619
  */
611
- const getTransition = (queryTarget, service, skipForbiddenViewCheck, event, options) => {
620
+ const getTransition = (queryTarget, service, _dummy, event) => {
612
621
  // Never resolve unknown targets (e.g. for drafts)
613
- if (!queryTarget) {
614
- return { target: queryTarget, queryTarget, mapping: new Map() }
615
- }
622
+ if (!queryTarget) return { target: queryTarget, queryTarget, mapping: new Map() }
616
623
 
617
- const transitionData = _getTransitionData(queryTarget, [], service, {
618
- skipForbiddenViewCheck,
619
- event,
620
- abort: options?.abort
621
- })
624
+ const transitionData = _getTransitionData(queryTarget, [], service, event)
622
625
  if (!transitionData) return undefined
623
626
  const { target: _target, transitionColumns } = transitionData
624
627
  const query = queryTarget.query
625
628
  const alias = query && query.SELECT && query.SELECT.from && query.SELECT.from.as
626
- const mappedColumns = transitionColumns.map(column => _mappedValue(column, alias))
629
+ const mappingTarget = query?._target
630
+ const mappedColumns = transitionColumns.map(column => _mappedValue(column, alias, mappingTarget))
627
631
  const mapping = new Map(mappedColumns)
628
632
  return { target: _target, queryTarget, mapping }
629
633
  }
@@ -632,11 +636,7 @@ const _entityTransitionsForTarget = (from, model, service, options) => {
632
636
  let previousEntity = options.previousEntity
633
637
 
634
638
  if (typeof from === 'string') {
635
- return (
636
- model.definitions[from] && [
637
- getTransition(model.definitions[from], service, undefined, options.event, { abort: options.abort })
638
- ]
639
- )
639
+ return model.definitions[from] && [getTransition(model.definitions[from], service, null, options.event)]
640
640
  }
641
641
 
642
642
  if (typeof from === 'object' && from.SELECT) {
@@ -651,7 +651,7 @@ const _entityTransitionsForTarget = (from, model, service, options) => {
651
651
  const entity = model.definitions[element]
652
652
  if (entity) {
653
653
  previousEntity = entity
654
- return getTransition(entity, service, undefined, options.event, { abort: options.abort })
654
+ return getTransition(entity, service, null, options.event)
655
655
  }
656
656
  }
657
657
 
@@ -660,7 +660,7 @@ const _entityTransitionsForTarget = (from, model, service, options) => {
660
660
  if (entity) {
661
661
  // > assoc
662
662
  previousEntity = entity
663
- return getTransition(entity, service, undefined, options.event, { abort: options.abort })
663
+ return getTransition(entity, service, null, options.event)
664
664
  }
665
665
 
666
666
  // > struct
@@ -674,7 +674,7 @@ const _entityTransitionsForTarget = (from, model, service, options) => {
674
674
  })
675
675
  }
676
676
 
677
- const resolveView = (query, model, service, abort) => {
677
+ const resolveView = (query, model, service) => {
678
678
  // swap logger
679
679
  const _LOG = LOG
680
680
  LOG = cds.log(service.kind) // REVISIT: Avoid obtaining loggers per request!
@@ -699,7 +699,7 @@ const resolveView = (query, model, service, abort) => {
699
699
  DELETE: ['from', _newDelete]
700
700
  }[kind]
701
701
 
702
- const options = { abort, event: kind, service, model }
702
+ const options = { event: kind, service, model }
703
703
  const transitions = _entityTransitionsForTarget(query[kind][_prop], model, service, options)
704
704
  if (!service.isDatabaseService && cds.env.features.restrict_service_scope !== false && transitions.some(t => !t))
705
705
  return
@@ -719,8 +719,15 @@ const resolveView = (query, model, service, abort) => {
719
719
  return newQuery
720
720
  }
721
721
 
722
+ const _resolve_table = target => {
723
+ if (target.query?._target && !Object.prototype.hasOwnProperty.call(target, '@cds.persistence.table'))
724
+ return _resolve_table(target.query._target)
725
+ return target
726
+ }
727
+
722
728
  module.exports = {
723
- getDBTable,
729
+ // REVISIT: remove getDBTable with cds^10
730
+ getDBTable: _resolve_table,
724
731
  resolveView,
725
732
  getTransition,
726
733
  revertData
@@ -95,6 +95,7 @@ const rewriteExpandAsterisk = (columns, target) => {
95
95
 
96
96
  for (const elName in target.elements) {
97
97
  if (!target.elements[elName]._target) continue
98
+ if (target.elements[elName]._target?._service !== target._service) continue
98
99
  if (restrictions.includes(elName)) continue
99
100
  if (elName === 'SiblingEntity') continue
100
101
  if (columns.find(col => col.expand && col.ref && col.ref[0] === elName)) continue
@@ -6,6 +6,7 @@ const { Object_keys } = cds.utils
6
6
  const { Readable, PassThrough } = require('stream')
7
7
 
8
8
  const { getPageSize, commonGenericPaging } = require('../common/generic/paging')
9
+ const { getPreferReturnHeader } = require('../../odata/utils')
9
10
  const { handler: commonGenericSorting } = require('../common/generic/sorting')
10
11
  const { addEtagColumns } = require('../common/utils/etag')
11
12
  const { handleStreamProperties } = require('../common/utils/streamProp')
@@ -710,7 +711,7 @@ const draftHandle = async function (req) {
710
711
  let newDraftAction = rootEntity['@Common.DraftRoot.NewAction']
711
712
  if (typeof newDraftAction != 'string' || !newDraftAction.length) newDraftAction = false
712
713
  else newDraftAction = newDraftAction.split('.').pop()
713
- const shouldHandleNewDraftAction = isNewDraftViaActionEnabled && req.target === rootEntity
714
+ const shouldHandleNewDraftAction = isNewDraftViaActionEnabled && req.target.name === rootEntity.name
714
715
 
715
716
  // Create active instance of draft-enabled entity
716
717
  // REVISIT: New OData adapter only sets `NEW` for drafts... how to distinguish programmatic modifications?
@@ -781,7 +782,13 @@ const draftHandle = async function (req) {
781
782
  req.data = createNewResult
782
783
  req.res.status(201)
783
784
 
784
- return _readAfterDraftAction.call(this, { req, payload: createNewResult, action: 'draftNew' })
785
+ const result = await _readAfterDraftAction.call(this, { req, payload: createNewResult, action: 'draftNew' })
786
+ if (result === null) req.res.status(204)
787
+ req.res.set(
788
+ 'location',
789
+ '../' + location4(req.target.actives, this, result || { ...createNewResult, IsActiveEntity: false })
790
+ )
791
+ return result
785
792
  }
786
793
 
787
794
  // Handle draft-only events, that can only ever target entities in draft state
@@ -2442,6 +2449,8 @@ async function onPrepare(req, next) {
2442
2449
  }
2443
2450
 
2444
2451
  const _readAfterDraftAction = async function ({ req, payload, action }) {
2452
+ if (getPreferReturnHeader(req) === 'minimal') return null
2453
+
2445
2454
  const entity = action === 'draftActivate' ? req.target : req.target.drafts
2446
2455
 
2447
2456
  // read after write with query options
@@ -123,13 +123,14 @@ class KafkaService extends cds.MessagingService {
123
123
  eachMessage: async raw => {
124
124
  try {
125
125
  const msg = _normalizeIncomingMessage(raw.message.value.toString())
126
+
126
127
  msg.headers = {}
127
128
  for (const header in raw.message.headers || {}) {
128
129
  msg.headers[header] = raw.message.headers[header]?.toString()
129
130
  }
130
- msg.event =
131
- raw.message.headers['x-sap-cap-effective-topic']?.toString() ?? raw.message.headers.type?.toString()
132
- msg.tenant = raw.message.headers['x-sap-cap-tenant-id']
131
+
132
+ msg.tenant = msg.headers['x-sap-cap-tenant-id']
133
+ msg.event = msg.headers['x-sap-cap-effective-topic'] ?? msg.headers.type
133
134
  if (!msg.event) return
134
135
 
135
136
  await this.processInboundMsg({ tenant: msg.tenant }, msg)
@@ -210,8 +211,8 @@ async function _getConfig(srv) {
210
211
  const caCerts = await _getCaCerts(srv)
211
212
 
212
213
  const allBrokers =
213
- srv.options.credentials.cluster?.['brokers.client_ssl'] ||
214
- srv.options.credentials['cluster.public']?.['brokers.client_ssl']
214
+ srv.options.credentials['cluster.public']?.['brokers.client_ssl'] ||
215
+ srv.options.credentials.cluster?.['brokers.client_ssl']
215
216
  const brokers = allBrokers.split(',')
216
217
 
217
218
  return {
@@ -45,7 +45,7 @@ const _buildPartialUrlFunctions = (url, data, params, kind = 'odata-v4') => {
45
45
  : `${url}(${funcParams.join(',')})?${queryOptions.join('&')}`
46
46
  }
47
47
 
48
- const _extractParamsFromData = (data, params = {}) => {
48
+ const _extractParamsFromData = (data = {}, params = {}) => {
49
49
  return Object.keys(data).reduce((res, el) => {
50
50
  if (params[el]) Object.assign(res, { [el]: data[el] })
51
51
  return res
@@ -142,7 +142,16 @@ const _addHandlerActionFunction = (srv, def, target) => {
142
142
  srv.on(event, target, async function (req) {
143
143
  const shortEntityName = req.target.name.replace(`${this.definition.name}.`, '')
144
144
  if (this.kind === 'odata-v2') return _handleV2BoundActionFunction(srv, def, req, event, this.kind)
145
- const url = `/${shortEntityName}(${_buildKeys(req, this.kind).join(',')})/${this.definition.name}.${event}`
145
+
146
+ const action = req.target.actions[req.event]
147
+ const onCollection = !!(
148
+ action['@cds.odata.bindingparameter.collection'] ||
149
+ (action?.params && [...action.params].some(p => p?.items?.type === '$self'))
150
+ )
151
+
152
+ const url = onCollection
153
+ ? `/${shortEntityName}/${this.definition.name}.${event}`
154
+ : `/${shortEntityName}(${_buildKeys(req, this.kind).join(',')})/${this.definition.name}.${event}`
146
155
  return _handleBoundActionFunction(srv, def, req, url)
147
156
  })
148
157
  } else {
@@ -240,6 +249,9 @@ class RemoteService extends cds.Service {
240
249
  const requestConfig = extractRequestConfig(req, query, this)
241
250
  requestConfig.headers = _getHeaders(requestConfig.headers, req)
242
251
 
252
+ if (this.kind === 'hcql' && req.iterator && !req.objectMode)
253
+ requestConfig.headers.accept = 'application/octet-stream,application/json'
254
+
243
255
  // REVISIT: we should not have to set the content-type at all for that
244
256
  if (requestConfig.headers.accept?.match(/stream|image|tar/)) requestConfig.responseType = 'stream'
245
257
 
@@ -43,9 +43,6 @@ const _executeHttpRequest = async ({ requestConfig, destination, destinationOpti
43
43
  else if (LOG._warn) LOG.warn('Missing JWT token for forwardAuthToken!')
44
44
  }
45
45
 
46
- // Cloud SDK throws error if useCache is activated and jwt is undefined
47
- if (destination.jwt === undefined) destination.useCache = false
48
-
49
46
  if (LOG._debug) _logRequest(requestConfig, destination)
50
47
 
51
48
  // cloud sdk requires a new mechanism to differentiate the priority of headers
@@ -250,7 +247,8 @@ module.exports.run = async (requestConfig, options) => {
250
247
  }
251
248
 
252
249
  const { kind, resolvedTarget, returnType } = options
253
- if (kind === 'hcql') return response.data.data
250
+ if (kind === 'hcql')
251
+ return response.headers?.['content-type']?.includes('application/octet-stream') ? response.data : response.data.data
254
252
  if (kind === 'odata-v4') return _purgeODataV4(response.data)
255
253
  if (kind === 'odata-v2') return _purgeODataV2(response.data, resolvedTarget, returnType)
256
254
  if (kind === 'odata') {
@@ -26,11 +26,11 @@ const _cqnWithPublicEntries = query => {
26
26
  }
27
27
 
28
28
  const _cqnToHcqlRequestConfig = cqn => {
29
- if (cqn.SELECT && cqn.SELECT.from) return { method: 'GET', data: { SELECT: _cqnWithPublicEntries(cqn.SELECT) } }
29
+ if (cqn.SELECT && cqn.SELECT.from) return { method: 'POST', data: { SELECT: _cqnWithPublicEntries(cqn.SELECT) } }
30
30
  if (cqn.INSERT && cqn.INSERT.into) return { method: 'POST', data: { INSERT: _cqnWithPublicEntries(cqn.INSERT) } }
31
- if (cqn.UPDATE && cqn.UPDATE.entity) return { method: 'PATCH', data: { UPDATE: _cqnWithPublicEntries(cqn.UPDATE) } }
32
- if (cqn.UPSERT && cqn.UPSERT.into) return { method: 'PUT', data: { UPSERT: _cqnWithPublicEntries(cqn.UPSERT) } }
33
- if (cqn.DELETE && cqn.DELETE.from) return { method: 'DELETE', data: { DELETE: _cqnWithPublicEntries(cqn.DELETE) } }
31
+ if (cqn.UPDATE && cqn.UPDATE.entity) return { method: 'POST', data: { UPDATE: _cqnWithPublicEntries(cqn.UPDATE) } }
32
+ if (cqn.UPSERT && cqn.UPSERT.into) return { method: 'POST', data: { UPSERT: _cqnWithPublicEntries(cqn.UPSERT) } }
33
+ if (cqn.DELETE && cqn.DELETE.from) return { method: 'POST', data: { DELETE: _cqnWithPublicEntries(cqn.DELETE) } }
34
34
 
35
35
  cds.error(400, 'Invalid CQN object can not be processed.', JSON.stringify(cqn), _cqnToHcqlRequestConfig)
36
36
  }