@sap/cds 5.4.6 → 5.5.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 (228) hide show
  1. package/CHANGELOG.md +208 -2
  2. package/apis/ql.d.ts +17 -15
  3. package/app/index.js +1 -1
  4. package/bin/build/buildTaskEngine.js +26 -42
  5. package/bin/build/buildTaskFactory.js +6 -10
  6. package/bin/build/buildTaskHandler.js +2 -4
  7. package/bin/build/buildTaskProvider.js +3 -1
  8. package/bin/build/buildTaskProviderFactory.js +9 -15
  9. package/bin/build/constants.js +15 -3
  10. package/bin/build/index.js +5 -4
  11. package/bin/build/mtaUtil.js +8 -11
  12. package/bin/build/provider/buildTaskHandlerEdmx.js +63 -6
  13. package/bin/build/provider/buildTaskHandlerInternal.js +2 -34
  14. package/bin/build/provider/buildTaskProviderInternal.js +16 -42
  15. package/bin/build/provider/fiori/index.js +13 -24
  16. package/bin/build/provider/hana/2migration.js +17 -15
  17. package/bin/build/provider/hana/2tabledata.js +52 -48
  18. package/bin/build/provider/hana/index.js +27 -25
  19. package/bin/build/provider/hana/migrationtable.js +91 -67
  20. package/bin/build/provider/java-cf/index.js +14 -24
  21. package/bin/build/provider/mtx/index.js +12 -14
  22. package/bin/build/provider/node-cf/index.js +18 -32
  23. package/bin/cds.js +5 -5
  24. package/bin/serve.js +29 -23
  25. package/bin/version.js +0 -1
  26. package/lib/compile/etc/_localized.js +4 -9
  27. package/lib/compile/for/sql.js +5 -2
  28. package/lib/compile/parse.js +25 -17
  29. package/lib/compile/to/srvinfo.js +2 -1
  30. package/lib/connect/bindings.js +2 -1
  31. package/lib/connect/index.js +48 -49
  32. package/lib/core/classes.js +1 -1
  33. package/lib/core/reflect.js +10 -2
  34. package/lib/deploy.js +26 -23
  35. package/lib/env/defaults.js +13 -6
  36. package/lib/env/index.js +73 -78
  37. package/lib/env/requires.js +38 -19
  38. package/lib/index.js +9 -10
  39. package/lib/lazy.js +2 -2
  40. package/lib/log/index.js +33 -45
  41. package/lib/log/service/index.js +2 -2
  42. package/lib/ql/CREATE.js +14 -9
  43. package/lib/ql/DELETE.js +6 -5
  44. package/lib/ql/DROP.js +12 -9
  45. package/lib/ql/INSERT.js +40 -16
  46. package/lib/ql/Query.js +67 -40
  47. package/lib/ql/SELECT.js +162 -127
  48. package/lib/ql/UPDATE.js +74 -42
  49. package/lib/ql/Whereable.js +77 -87
  50. package/lib/ql/index.js +36 -24
  51. package/lib/ql/parse.js +35 -0
  52. package/lib/req/context.js +44 -8
  53. package/lib/req/locale.js +7 -7
  54. package/lib/serve/Service-api.js +21 -14
  55. package/lib/serve/Service-dispatch.js +28 -12
  56. package/lib/serve/Transaction.js +22 -10
  57. package/lib/serve/index.js +16 -11
  58. package/lib/utils/axios.js +23 -16
  59. package/lib/utils/data.js +35 -0
  60. package/lib/utils/tests.js +27 -18
  61. package/libx/_runtime/audit/generic/personal/access.js +81 -0
  62. package/libx/_runtime/audit/generic/personal/constants.js +4 -0
  63. package/libx/_runtime/audit/generic/personal/index.js +50 -0
  64. package/libx/_runtime/audit/generic/personal/modification.js +138 -0
  65. package/libx/_runtime/audit/generic/personal/utils.js +186 -0
  66. package/libx/_runtime/audit/utils/v2.js +10 -4
  67. package/libx/_runtime/cds-services/adapter/odata-v4/Dispatcher.js +5 -5
  68. package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +6 -7
  69. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/action.js +5 -7
  70. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/create.js +5 -7
  71. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/delete.js +2 -3
  72. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/error.js +4 -0
  73. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +7 -4
  74. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +59 -8
  75. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +11 -1
  76. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +6 -10
  77. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +3 -46
  78. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/applyToCQN.js +2 -5
  79. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/createToCQN.js +2 -2
  80. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/deleteToCQN.js +4 -3
  81. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/expandToCQN.js +1 -2
  82. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/index.js +0 -1
  83. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/selectHelper.js +1 -1
  84. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/updateToCQN.js +2 -2
  85. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/utils.js +16 -18
  86. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/edm/EdmEntityType.js +6 -3
  87. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/format/RepresentationKind.js +4 -1
  88. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/core/OdataRequest.js +1 -0
  89. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/serializer/SerializerFactory.js +15 -2
  90. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/validator/OperationValidator.js +1 -0
  91. package/libx/_runtime/cds-services/adapter/odata-v4/to.js +1 -1
  92. package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +8 -1
  93. package/libx/_runtime/cds-services/adapter/odata-v4/utils/handlerUtils.js +6 -1
  94. package/libx/_runtime/cds-services/adapter/odata-v4/utils/omitValues.js +12 -5
  95. package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +1 -7
  96. package/libx/_runtime/cds-services/adapter/odata-v4/utils/request.js +7 -7
  97. package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +14 -18
  98. package/libx/_runtime/cds-services/adapter/odata-v4/utils/stream.js +13 -13
  99. package/libx/_runtime/cds-services/adapter/rest/handlers/create.js +0 -1
  100. package/libx/_runtime/cds-services/adapter/rest/handlers/operation.js +2 -1
  101. package/libx/_runtime/cds-services/adapter/rest/handlers/read.js +2 -2
  102. package/libx/_runtime/cds-services/adapter/rest/rest-to-cqn/index.js +2 -4
  103. package/libx/_runtime/cds-services/adapter/rest/utils/result.js +4 -2
  104. package/libx/_runtime/cds-services/services/Service.js +40 -5
  105. package/libx/_runtime/cds-services/services/utils/columns.js +13 -7
  106. package/libx/_runtime/cds-services/services/utils/compareJson.js +88 -4
  107. package/libx/_runtime/cds-services/services/utils/differ.js +24 -6
  108. package/libx/_runtime/cds-services/services/utils/handlerUtils.js +2 -2
  109. package/libx/_runtime/common/composition/data.js +44 -55
  110. package/libx/_runtime/common/composition/delete.js +97 -71
  111. package/libx/_runtime/common/composition/index.js +2 -1
  112. package/libx/_runtime/common/composition/insert.js +34 -11
  113. package/libx/_runtime/common/composition/tree.js +119 -92
  114. package/libx/_runtime/common/composition/update.js +4 -1
  115. package/libx/_runtime/common/composition/utils.js +1 -3
  116. package/libx/_runtime/common/constants/draft.js +12 -1
  117. package/libx/_runtime/common/generic/auth.js +6 -22
  118. package/libx/_runtime/common/generic/crud.js +14 -13
  119. package/libx/_runtime/common/generic/input.js +23 -26
  120. package/libx/_runtime/common/generic/put.js +1 -1
  121. package/libx/_runtime/common/generic/sorting.js +16 -16
  122. package/libx/_runtime/common/i18n/index.js +1 -1
  123. package/libx/_runtime/common/i18n/messages.properties +4 -0
  124. package/libx/_runtime/common/utils/backlinks.js +12 -5
  125. package/libx/_runtime/common/utils/cqn.js +6 -1
  126. package/libx/_runtime/common/utils/cqn2cqn4sql.js +102 -101
  127. package/libx/_runtime/common/utils/csn.js +47 -4
  128. package/libx/_runtime/common/utils/data.js +0 -37
  129. package/libx/_runtime/common/utils/enrichWithKeysFromWhere.js +1 -1
  130. package/libx/_runtime/common/utils/entityFromCqn.js +7 -24
  131. package/libx/_runtime/common/utils/foreignKeyPropagations.js +39 -7
  132. package/libx/_runtime/common/utils/generateOnCond.js +11 -12
  133. package/libx/_runtime/common/utils/onlyKeysRemain.js +10 -0
  134. package/libx/_runtime/common/utils/path.js +35 -0
  135. package/libx/_runtime/common/utils/postProcessing.js +86 -0
  136. package/libx/_runtime/common/utils/quotingStyles.js +37 -26
  137. package/libx/_runtime/common/utils/resolveView.js +223 -171
  138. package/libx/_runtime/common/utils/rewriteAsterisk.js +46 -26
  139. package/libx/_runtime/common/utils/structured.js +6 -12
  140. package/libx/_runtime/common/utils/template.js +10 -5
  141. package/libx/_runtime/common/utils/templateDelimiter.js +1 -0
  142. package/libx/_runtime/common/utils/templateProcessor.js +22 -30
  143. package/libx/_runtime/common/utils/union.js +31 -0
  144. package/libx/_runtime/common/utils/unionCqnTemplate.js +184 -0
  145. package/libx/_runtime/db/Service.js +1 -1
  146. package/libx/_runtime/db/data-conversion/timestamp.js +2 -9
  147. package/libx/_runtime/db/expand/expandCQNToJoin.js +204 -297
  148. package/libx/_runtime/db/expand/index.js +3 -3
  149. package/libx/_runtime/db/expand/rawToExpanded.js +36 -7
  150. package/libx/_runtime/db/generic/index.js +1 -1
  151. package/libx/_runtime/db/generic/input.js +5 -7
  152. package/libx/_runtime/db/generic/integrity.js +1 -1
  153. package/libx/_runtime/db/generic/rewrite.js +2 -10
  154. package/libx/_runtime/db/generic/update.js +13 -5
  155. package/libx/_runtime/db/generic/virtual.js +22 -58
  156. package/libx/_runtime/db/query/delete.js +7 -4
  157. package/libx/_runtime/db/query/insert.js +6 -4
  158. package/libx/_runtime/db/query/read.js +13 -20
  159. package/libx/_runtime/db/query/run.js +4 -1
  160. package/libx/_runtime/db/query/update.js +5 -4
  161. package/libx/_runtime/db/sql-builder/ExpressionBuilder.js +35 -2
  162. package/libx/_runtime/db/sql-builder/FunctionBuilder.js +17 -2
  163. package/libx/_runtime/db/sql-builder/InsertBuilder.js +6 -5
  164. package/libx/_runtime/db/sql-builder/ReferenceBuilder.js +10 -0
  165. package/libx/_runtime/db/sql-builder/SelectBuilder.js +35 -24
  166. package/libx/_runtime/db/sql-builder/UpdateBuilder.js +14 -4
  167. package/libx/_runtime/db/sql-builder/arrayed.js +4 -0
  168. package/libx/_runtime/db/utils/deep.js +8 -0
  169. package/libx/_runtime/db/utils/generateAliases.js +2 -1
  170. package/libx/_runtime/fiori/generic/activate.js +19 -15
  171. package/libx/_runtime/fiori/generic/before.js +3 -11
  172. package/libx/_runtime/fiori/generic/cancel.js +1 -1
  173. package/libx/_runtime/fiori/generic/delete.js +3 -1
  174. package/libx/_runtime/fiori/generic/edit.js +12 -2
  175. package/libx/_runtime/fiori/generic/new.js +5 -5
  176. package/libx/_runtime/fiori/generic/patch.js +0 -18
  177. package/libx/_runtime/fiori/generic/read.js +241 -189
  178. package/libx/_runtime/fiori/utils/delete.js +36 -7
  179. package/libx/_runtime/fiori/utils/handler.js +43 -44
  180. package/libx/_runtime/fiori/utils/where.js +30 -15
  181. package/libx/_runtime/hana/customBuilder/CustomSelectBuilder.js +4 -6
  182. package/libx/_runtime/hana/execute.js +2 -2
  183. package/libx/_runtime/hana/localized.js +4 -4
  184. package/libx/_runtime/hana/pool.js +29 -14
  185. package/libx/_runtime/hana/search2cqn4sql.js +2 -1
  186. package/libx/_runtime/hana/searchToContains.js +18 -14
  187. package/libx/_runtime/index.js +0 -5
  188. package/libx/_runtime/messaging/AMQPWebhookMessaging.js +13 -5
  189. package/libx/_runtime/messaging/common-utils/naming-conventions.js +4 -1
  190. package/libx/_runtime/messaging/enterprise-messaging-utils/EMManagement.js +31 -19
  191. package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +1 -2
  192. package/libx/_runtime/messaging/enterprise-messaging.js +6 -4
  193. package/libx/_runtime/messaging/service.js +7 -6
  194. package/libx/_runtime/odata/cqn2odata.js +110 -43
  195. package/libx/_runtime/odata/index.js +26 -48
  196. package/libx/_runtime/odata/odata2cqn.js +1 -6154
  197. package/libx/_runtime/odata/odata2cqn.pegjs +559 -0
  198. package/libx/_runtime/odata/readToCqn.js +94 -64
  199. package/libx/_runtime/remote/Service.js +74 -21
  200. package/libx/_runtime/remote/cqn2odata/index.js +1 -5
  201. package/libx/_runtime/remote/utils/client.js +24 -101
  202. package/libx/_runtime/remote/utils/dataConversion.js +27 -12
  203. package/libx/_runtime/sqlite/Service.js +3 -5
  204. package/libx/_runtime/sqlite/execute.js +23 -24
  205. package/libx/_runtime/sqlite/localized.js +12 -7
  206. package/libx/_runtime/types/api.js +10 -0
  207. package/package.json +1 -1
  208. package/server.js +16 -2
  209. package/lib/ql/grammar.pegjs +0 -208
  210. package/lib/ql/parser.js +0 -1
  211. package/lib/ql/rt/DELETE.js +0 -29
  212. package/lib/ql/rt/INSERT.js +0 -23
  213. package/lib/ql/rt/Query.js +0 -84
  214. package/lib/ql/rt/SELECT.js +0 -174
  215. package/lib/ql/rt/UPDATE.js +0 -119
  216. package/lib/ql/rt/_helpers.js +0 -91
  217. package/lib/ql/rt/index.js +0 -32
  218. package/libx/_runtime/audit/generic/personal.js +0 -260
  219. package/libx/_runtime/cds-services/statements/BaseStatement.js +0 -72
  220. package/libx/_runtime/cds-services/statements/Create.js +0 -57
  221. package/libx/_runtime/cds-services/statements/Delete.js +0 -33
  222. package/libx/_runtime/cds-services/statements/Drop.js +0 -42
  223. package/libx/_runtime/cds-services/statements/Insert.js +0 -201
  224. package/libx/_runtime/cds-services/statements/Select.js +0 -826
  225. package/libx/_runtime/cds-services/statements/Update.js +0 -181
  226. package/libx/_runtime/cds-services/statements/Where.js +0 -726
  227. package/libx/_runtime/cds-services/statements/index.js +0 -25
  228. package/libx/_runtime/common/generic/resolve-mock.js +0 -9
@@ -30,5 +30,16 @@ module.exports = {
30
30
  { ref: ['HasActiveEntity'], cast: { type: 'cds.Boolean' } },
31
31
  { ref: ['HasDraftEntity'], cast: { type: 'cds.Boolean' } },
32
32
  { ref: ['DraftAdministrativeData_DraftUUID'] }
33
- ]
33
+ ],
34
+ SCENARIO: {
35
+ ACTIVE: 'ACTIVE',
36
+ ACTIVE_WITHOUT_DRAFT: 'ACTIVE_WITHOUT_DRAFT',
37
+ ALL_ACTIVE: 'ALL_ACTIVE',
38
+ ALL_INACTIVE: 'ALL_INACTIVE',
39
+ DRAFT_ADMIN: 'DRAFT_ADMIN',
40
+ DRAFT_IN_PROCESS: 'DRAFT_IN_PROCESS',
41
+ DRAFT_WHICH_OWNER: 'DRAFT_WHICH_OWNER',
42
+ SIBLING_ENTITY: 'SIBLING_ENTITY',
43
+ UNION: 'UNION'
44
+ }
34
45
  }
@@ -26,9 +26,6 @@ const RESTRICTIONS = {
26
26
  DELETABLE: 'DeleteRestrictions.Deletable'
27
27
  }
28
28
 
29
- // REVISIT: remove everywhere
30
- const SYMBOL_FROM_ANNOTATION = Symbol.for('sap.cds.FROM_ANNOTATION')
31
-
32
29
  const _reject = req => {
33
30
  // unauthorized or forbidden?
34
31
  if (req.user._is_anonymous) {
@@ -177,19 +174,10 @@ const _evalStatic = (op, vals) => {
177
174
  }
178
175
  }
179
176
 
180
- const _addSymbol = element => {
181
- // NOTE: will not be needed with cds^5.5 as the symbol was removed
182
- if (cds.env.features.skip_restrict_symbol) return element
183
-
184
- element = typeof element === 'string' ? new String(element) : element
185
- element[SYMBOL_FROM_ANNOTATION] = true
186
- return element
187
- }
188
-
189
177
  const _getMergedWhere = restricts => {
190
178
  const xprs = []
191
179
  restricts.forEach(ele => {
192
- xprs.push('(', ...ele._xpr.map(ele => _addSymbol(ele)), ')', 'or')
180
+ xprs.push('(', ...ele._xpr, ')', 'or')
193
181
  })
194
182
  xprs.pop()
195
183
  return xprs
@@ -245,16 +233,9 @@ const _ensureTableAlias = (ref, aliases, targetFrom, model, hasExpand) => {
245
233
  } else {
246
234
  _adaptTableName(ref, nameObj.refIndex, nameObj.name)
247
235
  }
248
-
249
- if (hasExpand && nameObj.aliasIndex === 0) {
250
- _addSymbol(ref)
251
- }
252
236
  }
253
237
 
254
238
  const _enhanceAnnotationSubSelect = (select, model, targetName, targetFrom, hasExpand) => {
255
- if (select.from && select.from.ref) {
256
- _addSymbol(select.from.ref)
257
- }
258
239
  if (select.where) {
259
240
  for (const v of select.where) {
260
241
  if (v.ref && select.from.ref) {
@@ -384,8 +365,10 @@ const _getRestrictionForTarget = (resolvedApplicables, target) => {
384
365
  }
385
366
 
386
367
  const _addRestrictionsToRead = async (req, model, resolvedApplicables) => {
387
- // context.query.where(['(', ...whereClause, ')'])
388
- // REVISIT: better attach where(s) to query as additional filters for later materialization (when?!)
368
+ if (req.target._isDraftEnabled) {
369
+ req.query._draftRestrictions = resolvedApplicables.map(ra => ra._xpr)
370
+ return
371
+ }
389
372
 
390
373
  if (typeof req.query.SELECT.from === 'object')
391
374
  req.query.SELECT.from.ref = _addWheresToRef(req.query.SELECT.from.ref, model, resolvedApplicables)
@@ -393,6 +376,7 @@ const _addRestrictionsToRead = async (req, model, resolvedApplicables) => {
393
376
  const restrictionForTarget = _getRestrictionForTarget(resolvedApplicables, req.target)
394
377
  if (restrictionForTarget) {
395
378
  req.query.where(restrictionForTarget)
379
+ // REVISIT: remove with cds^6
396
380
  _enhanceAnnotationWhere(req.query, restrictionForTarget, model)
397
381
  }
398
382
  }
@@ -5,16 +5,7 @@ const getTemplate = require('../utils/template')
5
5
  const templateProcessor = require('../utils/templateProcessor')
6
6
  const replaceManagedData = require('../utils/dollar')
7
7
 
8
- const _onlyKeysRemain = req => {
9
- // if custom handlers uses only expression like {col: {'+=': 1}},
10
- // req.data will only contain the keys
11
- if (req.query.UPDATE.with && Object.keys(req.query.UPDATE.with).length > 0) {
12
- return false
13
- }
14
-
15
- const keys = Object.keys(req.target.keys)
16
- return !Object.keys(req.data).some(k => !keys.includes(k))
17
- }
8
+ const onlyKeysRemain = require('../utils/onlyKeysRemain')
18
9
 
19
10
  const _targetEntityDoesNotExist = async req => {
20
11
  const { query } = req
@@ -39,7 +30,7 @@ const _processorFn = req => {
39
30
  const { event, user, timestamp } = req
40
31
  const ts = new Date(timestamp).toISOString()
41
32
 
42
- return (row, key, element, plain, isRoot) => {
33
+ return ({ row, key, plain }) => {
43
34
  const categories = plain.categories
44
35
 
45
36
  for (const category of categories) {
@@ -89,8 +80,8 @@ module.exports = function () {
89
80
 
90
81
  let result
91
82
 
92
- // no changes, no op (otherwise, @cds.on.update gets new values), but we need to check existance
93
- if (req.event === 'UPDATE' && _onlyKeysRemain(req)) {
83
+ // no changes, no op (otherwise, @cds.on.update gets new values), but we need to check existence
84
+ if (req.event === 'UPDATE' && onlyKeysRemain(req)) {
94
85
  if (await _targetEntityDoesNotExist(req)) {
95
86
  req.reject(404)
96
87
  }
@@ -98,6 +89,16 @@ module.exports = function () {
98
89
  result = req.data
99
90
  }
100
91
 
92
+ if (req.event === 'DELETE' && req.target._isSingleton) {
93
+ if (!req.target['@odata.singleton.nullable']) {
94
+ req.reject(400, 'SINGLETON_NOT_NULLABLE')
95
+ }
96
+
97
+ const singleton = await cds.tx(req).run(SELECT.one(req.target))
98
+ if (!singleton) req.reject(404)
99
+ req.query.where(singleton)
100
+ }
101
+
101
102
  if (!result) {
102
103
  result = await cds.tx(req).run(req.query, req.data)
103
104
  }
@@ -16,9 +16,8 @@ const templateProcessor = require('../utils/templateProcessor')
16
16
  const { getDataFromCQN, setDataFromCQN } = require('../utils/data')
17
17
  const { isMandatory, isReadOnly } = require('../aspects/utils')
18
18
 
19
- const shouldSuppressErrorPropagation = ({ event, value, suppress = false }) => {
19
+ const shouldSuppressErrorPropagation = ({ event, value }) => {
20
20
  return (
21
- suppress ||
22
21
  event === 'NEW' ||
23
22
  event === 'PATCH' ||
24
23
  (event === 'UPDATE' && value.val === undefined) ||
@@ -35,7 +34,7 @@ const getSimpleCategory = category => {
35
34
  }
36
35
 
37
36
  const rowKeysGenerator = eventName => {
38
- return ({ keyNames, row, template }) => {
37
+ return (keyNames, row, template) => {
39
38
  if (eventName === 'UPDATE') return
40
39
 
41
40
  for (const keyName of keyNames) {
@@ -96,7 +95,7 @@ const _processCategory = ({ row, key, category, isRoot, event, value, req, eleme
96
95
  const processorFn = (errors, req) => {
97
96
  const { event } = req
98
97
 
99
- return (row, key, element, plain, isRoot, pathSegments, suppressErrorPropagation = false) => {
98
+ return ({ row, key, element, plain, isRoot, pathSegments }) => {
100
99
  const categories = plain.categories
101
100
  // ugly pointer passing for sonar
102
101
  const value = { mandatory: false, val: row && row[key] }
@@ -105,7 +104,7 @@ const processorFn = (errors, req) => {
105
104
  _processCategory({ row, key, category, isRoot, event, value, req, element })
106
105
  }
107
106
 
108
- if (shouldSuppressErrorPropagation({ event, value, suppress: suppressErrorPropagation })) {
107
+ if (shouldSuppressErrorPropagation({ event, value })) {
109
108
  return
110
109
  }
111
110
 
@@ -211,34 +210,30 @@ function _handler(req) {
211
210
  _callError(req, errors)
212
211
  }
213
212
 
214
- const processorFnForActionsFunctions = (errors, opName) => (row, tKey, element) => {
215
- const value = row && row[tKey]
213
+ const processorFnForActionsFunctions =
214
+ (errors, opName) =>
215
+ ({ row, key, element }) => {
216
+ const value = row && row[key]
216
217
 
217
- // REVISIT: Convert checkInputConstraints to template mechanism
218
- checkInputConstraints({ element, value, errors, key: opName })
219
- }
220
-
221
- const KINDS_TO_VALIDATE = {
222
- entity: 1,
223
- type: 1
224
- }
218
+ // REVISIT: Convert checkInputConstraints to template mechanism
219
+ checkInputConstraints({ element, value, errors, key: opName })
220
+ }
225
221
 
226
222
  const _processActionFunctionRow = (row, param, key, errors, event, service) => {
227
223
  const values = Array.isArray(row[key]) ? row[key] : [row[key]]
228
-
229
224
  // unstructured
230
225
  for (const value of values) {
231
226
  checkInputConstraints({ element: param, value, errors, key })
232
227
  }
233
228
 
234
229
  // structured
235
- if (param._type && KINDS_TO_VALIDATE[param._type.kind]) {
236
- const template = getTemplate('app-input-operation', service, param._type, { pick: _pick })
237
- if (template.elements.size) {
238
- for (const value of values) {
239
- const args = { processFn: processorFnForActionsFunctions(errors, key), row: value, template }
240
- templateProcessor(args)
241
- }
230
+ const template = getTemplate('app-input-operation', service, param, {
231
+ pick: _pick
232
+ })
233
+ if (template && template.elements.size) {
234
+ for (const value of values) {
235
+ const args = { processFn: processorFnForActionsFunctions(errors, key), row: value, template }
236
+ templateProcessor(args)
242
237
  }
243
238
  }
244
239
  }
@@ -246,7 +241,8 @@ const _processActionFunctionRow = (row, param, key, errors, event, service) => {
246
241
  const _processActionFunction = (row, eventParams, errors, event, service) => {
247
242
  for (const key in eventParams) {
248
243
  let param = eventParams[key]
249
- if (!param._type && param.items) param = param.items
244
+ const _type = param.type
245
+ if (!_type && param.items) param = param.items
250
246
  _processActionFunctionRow(row, param, key, errors, event, service)
251
247
  }
252
248
  }
@@ -280,8 +276,9 @@ function _actionFunctionHandler(req) {
280
276
  // REVISIT: find better solution, maybe compiler?
281
277
  // resolve enums like format, range, etc.
282
278
  for (const param of Object.values(eventParams)) {
283
- if (param._type) {
284
- param.enum = param._type.enum
279
+ const _type = param.type && this.model && this.model.definitions[param.type]
280
+ if (_type) {
281
+ param.enum = _type.enum
285
282
  }
286
283
  }
287
284
 
@@ -25,7 +25,7 @@ const _fillStructure = (row, parts, element, category, args) => {
25
25
  const processorFn = req => {
26
26
  const REST = req.constructor.name === 'RestRequest'
27
27
 
28
- return (row, key, element, plain) => {
28
+ return ({ row, key, element, plain }) => {
29
29
  if (!row || row[key] !== undefined) return
30
30
 
31
31
  const { category, args } = plain
@@ -5,7 +5,6 @@ const DRAFT_COLUMNS = ['IsActiveEntity', 'HasDraftEntity', 'HasActiveEntity']
5
5
 
6
6
  const _getStaticOrders = req => {
7
7
  const { target: entity, query } = req
8
-
9
8
  const defaultOrders = entity['@cds.default.order'] || entity['@odata.default.order'] || []
10
9
 
11
10
  if (!cds._deprecationWarningForDefaultSort && defaultOrders.length > 0) {
@@ -60,25 +59,26 @@ const _handler = function (req) {
60
59
 
61
60
  // remove defaultOrder if not part of group by
62
61
  if (select.groupBy && select.groupBy.length > 0) {
63
- staticOrders = staticOrders.filter(d => {
64
- return select.groupBy.find(e => e.ref[0] === d.by['='])
65
- })
62
+ staticOrders = staticOrders.filter(d => select.groupBy.find(e => e.ref[0] === d.by['=']))
66
63
  }
67
64
 
65
+ if (!select.orderBy && staticOrders.length === 0) return
68
66
  select.orderBy = select.orderBy || []
67
+
69
68
  for (const defaultOrder of staticOrders) {
70
- if (
71
- !select.orderBy.some(orderBy => {
72
- const managedKey = orderBy.ref && orderBy.ref.length > 1 && orderBy.ref.join('_')
73
- const element = managedKey && req.target.elements[managedKey]
74
- const isManagedKey = element && element.key && !element.is2one
75
- // don't add duplicates
76
- return (
77
- (orderBy.ref && orderBy.ref.length === 1 && orderBy.ref[0] === defaultOrder.by['=']) ||
78
- (isManagedKey && managedKey === defaultOrder.by['='])
79
- )
80
- })
81
- ) {
69
+ const some = select.orderBy.some(orderBy => {
70
+ const managedKey = orderBy.ref && orderBy.ref.length > 1 && orderBy.ref.join('_')
71
+ const element = managedKey && req.target.elements[managedKey]
72
+ const isManagedKey = element && element.key && !element.is2one
73
+
74
+ // don't add duplicates
75
+ return (
76
+ (orderBy.ref && orderBy.ref.length === 1 && orderBy.ref[0] === defaultOrder.by['=']) ||
77
+ (isManagedKey && managedKey === defaultOrder.by['='])
78
+ )
79
+ })
80
+
81
+ if (!some) {
82
82
  const orderByItem = { ref: [defaultOrder.by['=']], sort: defaultOrder.desc ? 'desc' : 'asc' }
83
83
  select.orderBy.push(orderByItem)
84
84
  }
@@ -98,7 +98,7 @@ module.exports = (key, locale = '', args = {}) => {
98
98
 
99
99
  // for locale OR app default OR cds default
100
100
  let text = i18ns[locale][key] || i18ns[''][key] || i18ns.default[key]
101
-
101
+ if (!text) return
102
102
  // best effort replacement
103
103
  try {
104
104
  const matches = text.match(/\{[\w][\w]*\}/g) || []
@@ -71,6 +71,7 @@ ENTITY_IS_READ_ONLY=Entity "{0}" is read-only
71
71
  ENTITY_IS_NOT_CRUD=Entity "{0}" is not {1}
72
72
  ENTITY_IS_NOT_CRUD_VIA_NAVIGATION=Entity "{0}" is not {1} via association "{2}"
73
73
  ENTITY_IS_AUTOEXPOSED=Entity "{0}" is not explicitely exposed as part of the service
74
+ EXPAND_IS_RESTRICTED=Navigation property "{0}" is not allowed for expand operation
74
75
 
75
76
  # rest protocol adapter
76
77
  INVALID_RESOURCE="{0}" is not a valid resource
@@ -87,3 +88,6 @@ CRUD_VIA_NAVIGATION_NOT_SUPPORTED=CRUD via navigations is not yet supported
87
88
  # draft
88
89
  DRAFT_ALREADY_EXISTS=A draft for this entity already exists
89
90
  DRAFT_LOCKED_BY_ANOTHER_USER=The entity is locked by another user
91
+
92
+ # singleton
93
+ SINGLETON_NOT_NULLABLE=The singleton entity is not nullable
@@ -33,15 +33,22 @@ const _getBacklinkNameFromOnCond = element => {
33
33
  }
34
34
  }
35
35
 
36
- const isBacklink = (element, parent, checkContained) => {
36
+ const isBacklink = (element, parent, checkContained, backLinkName) => {
37
37
  if (!element._isAssociationStrict) return false
38
38
  if (!parent || !(element.keys || element.on)) return false
39
39
  if (element.target !== parent.name) return false
40
40
 
41
- for (const parentElement of Object.values(parent.elements)) {
42
- if ((!checkContained || parentElement._isContained) && _getBacklinkNameFromOnCond(parentElement) === element.name) {
43
- return true
44
- }
41
+ const _isBackLink = parentElement =>
42
+ (!checkContained || parentElement._isContained) && _getBacklinkNameFromOnCond(parentElement) === element.name
43
+
44
+ if (backLinkName) {
45
+ const parentElement = parent.elements[backLinkName]
46
+ return parentElement.isAssociation && _isBackLink(parentElement)
47
+ }
48
+ for (const parentElementName in parent.elements) {
49
+ const parentElement = parent.elements[parentElementName]
50
+ if (!parentElement.isAssociation) continue
51
+ if (_isBackLink(parentElement)) return true
45
52
  }
46
53
 
47
54
  return false
@@ -12,6 +12,11 @@ const getEntityNameFromDeleteCQN = cqn => {
12
12
  return from
13
13
  }
14
14
 
15
+ const getEntityNameFromUpdateCQN = cqn => {
16
+ return (cqn.UPDATE.entity.ref && cqn.UPDATE.entity.ref[0]) || cqn.UPDATE.entity.name || cqn.UPDATE.entity
17
+ }
18
+
15
19
  module.exports = {
16
- getEntityNameFromDeleteCQN
20
+ getEntityNameFromDeleteCQN,
21
+ getEntityNameFromUpdateCQN
17
22
  }