@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
@@ -1,6 +1,7 @@
1
1
  const { getNavigationIfStruct } = require('./structured')
2
2
  const getColumns = require('../../db/utils/columns')
3
3
  const _isAsteriskCol = col => col === '*' || (col.ref && col.ref[0] === '*')
4
+ const cds = require('../../../../libx/_runtime/cds')
4
5
 
5
6
  const _isDraft = req => {
6
7
  return (
@@ -10,43 +11,62 @@ const _isDraft = req => {
10
11
  )
11
12
  }
12
13
 
13
- const _rewriteExpandAsterisks = (expand, entity, refs) => {
14
+ const _getColumns = target => {
15
+ const columns = getColumns(target)
16
+ return columns.map(col => ({ ref: [col.name] }))
17
+ }
18
+
19
+ const _rewriteExpandAsterisks = (column, entity, refs) => {
14
20
  const navigation = getNavigationIfStruct(entity, refs)
15
- const targetEntity = navigation._target
21
+ const targetEntity = navigation && navigation._target
16
22
 
17
- expand.forEach(col => {
18
- if (col.ref && col.expand) {
19
- _rewriteExpandAsterisks(col.expand, targetEntity, col.ref)
20
- }
21
- })
23
+ if (Array.isArray(column.expand) && targetEntity) {
24
+ column.expand.forEach(col => {
25
+ if (col.ref && col.expand) {
26
+ _rewriteExpandAsterisks(col, targetEntity, col.ref)
27
+ }
28
+ })
29
+ }
30
+
31
+ if (column.expand === '*') {
32
+ column.expand = _getColumns(targetEntity)
33
+ return
34
+ }
22
35
 
23
- const asteriskColumnIndex = expand.findIndex(col => _isAsteriskCol(col))
36
+ if (Array.isArray(column.expand)) {
37
+ const asteriskColumnIndex = column.expand.findIndex(col => _isAsteriskCol(col))
38
+ if (asteriskColumnIndex === -1) return // * not found
24
39
 
25
- if (asteriskColumnIndex !== -1) {
26
- expand.splice(asteriskColumnIndex, 1)
27
- getColumns(targetEntity).forEach(col => {
28
- expand.push({ ref: [col.name] })
40
+ column.expand.splice(asteriskColumnIndex, 1)
41
+ const columns = getColumns(targetEntity)
42
+ columns.forEach(col => {
43
+ column.expand.push({ ref: [col.name] })
29
44
  })
30
45
  }
31
46
  }
32
47
 
33
48
  const _rewriteAsterisks = req => {
34
- if (!_isDraft(req) && req.query.SELECT && req.query.SELECT.columns) {
35
- const asteriskColumnIndex = req.query.SELECT.columns.findIndex(col => _isAsteriskCol(col))
36
-
37
- if (asteriskColumnIndex !== -1) {
38
- req.query.SELECT.columns.splice(asteriskColumnIndex, 1)
39
- getColumns(req.target).forEach(col => {
40
- req.query.SELECT.columns.push({ ref: [col.name] })
41
- })
42
- }
49
+ if (_isDraft(req) || !req.query.SELECT) return
43
50
 
44
- req.query.SELECT.columns.forEach(col => {
45
- if (col.ref && col.ref[0] !== 'DraftAdministrativeData' && col.expand && req.target) {
46
- _rewriteExpandAsterisks(col.expand, req.target, col.ref)
47
- }
48
- })
51
+ if (cds.env.features.odata_new_parser && !req.query.SELECT.columns) {
52
+ req.query.SELECT.columns = _getColumns(req.target)
53
+ return
49
54
  }
55
+
56
+ if (!req.query.SELECT.columns) return
57
+ const columnsIncludesAsterisk = req.query.SELECT.columns.some(col => _isAsteriskCol(col))
58
+
59
+ if (columnsIncludesAsterisk) {
60
+ const expandColumns = req.query.SELECT.columns.filter(column => column.expand)
61
+ const columns = _getColumns(req.target)
62
+ req.query.SELECT.columns = expandColumns.length ? [...columns, ...expandColumns] : columns
63
+ }
64
+
65
+ req.query.SELECT.columns.forEach(col => {
66
+ if (col.ref && col.ref[0] !== 'DraftAdministrativeData' && col.expand && req.target) {
67
+ _rewriteExpandAsterisks(col, req.target, col.ref)
68
+ }
69
+ })
50
70
  }
51
71
 
52
72
  module.exports = _rewriteAsterisks
@@ -36,6 +36,7 @@ const _flattenStructuredInExpand = (column, { _target: expandedEntity }) => {
36
36
  continue
37
37
  }
38
38
 
39
+ if (!expandElement.ref) continue
39
40
  const propertyName = expandElement.ref[expandElement.ref.length - 1]
40
41
  const element = expandedEntity.elements[expandElement.ref[0]] // TODO alias
41
42
  if (!element) continue
@@ -56,7 +57,7 @@ const _flattenStructuredInExpand = (column, { _target: expandedEntity }) => {
56
57
  column.orderBy = orderBy
57
58
  }
58
59
  column.where = flattenStructuredWhereHaving(column.where, expandedEntity)
59
- column.expand = column.expand.filter(e => !toBeDeleted.includes(e.ref[e.ref.length - 1]))
60
+ column.expand = column.expand.filter(e => !e.ref || !toBeDeleted.includes(e.ref[e.ref.length - 1]))
60
61
  column.expand.push(...flattenedElements)
61
62
  }
62
63
 
@@ -175,7 +176,7 @@ const _transformStructToFlatWhereHaving = ([first, op, second], resArray, struct
175
176
  } catch (e) {
176
177
  /* since val === string */
177
178
  }
178
- if (flattenedElement && structData === val) {
179
+ if (flattenedElement && (structData === val || `${structData}` === val)) {
179
180
  flattenedElement.ref.unshift(...nav)
180
181
  resArray.push(flattenedElement, op, { val })
181
182
  } else {
@@ -234,17 +235,10 @@ const _entityFromRef = ref => {
234
235
  if (ref) return ref[0].id || ref[0]
235
236
  }
236
237
  const getNavigationIfStruct = (entity, ref) => {
237
- const element = entity.elements[_entityFromRef(ref)]
238
-
238
+ const element = entity && entity.elements && entity.elements[_entityFromRef(ref)]
239
239
  if (!element) return
240
-
241
- if (element._target) return element
242
-
243
- if (ref.length > 1) {
244
- return getNavigationIfStruct(element, ref.slice(1))
245
- }
246
-
247
- return element.elements[_entityFromRef(ref)]
240
+ if (ref.length > 1) return getNavigationIfStruct(element._target || element, ref.slice(1))
241
+ return element
248
242
  }
249
243
 
250
244
  const _flattenColumns = (SELECT, flattenedElements, toBeDeleted, csnEntity) => {
@@ -1,3 +1,5 @@
1
+ const DELIMITER = require('./templateDelimiter')
2
+
1
3
  const _addSubTemplate = (templateElements, elementName, subTemplate) => {
2
4
  if (subTemplate.elements.size > 0) {
3
5
  const t = templateElements.get(elementName)
@@ -48,7 +50,7 @@ const _getNextTarget = (model, element, currentPath = []) => {
48
50
  }
49
51
  } else if (_isInlineStructured(element)) {
50
52
  return {
51
- nextTargetName: [...currentPath, element.name].join(' '),
53
+ nextTargetName: [...currentPath, element.name].join(DELIMITER),
52
54
  nextTarget: element.items || element
53
55
  }
54
56
  }
@@ -73,7 +75,7 @@ function _getTemplate(model, cache, target, { pick, ignore }, parent = null, ent
73
75
  const templateElements = new Map()
74
76
  const template = { target, elements: templateElements }
75
77
  const currentPath = [...targetPath, target.name]
76
- entityMap.set(currentPath.join(' '), { template })
78
+ entityMap.set(currentPath.join(DELIMITER), { template })
77
79
 
78
80
  if (target.elements) {
79
81
  for (const elementName in target.elements) {
@@ -82,7 +84,7 @@ function _getTemplate(model, cache, target, { pick, ignore }, parent = null, ent
82
84
 
83
85
  _pick(pick, element, target, parent, templateElements, elementName)
84
86
  if (element.items) {
85
- _pick(pick, element.items, target, parent, templateElements, ['_itemsOf', elementName].join(' '))
87
+ _pick(pick, element.items, target, parent, templateElements, ['_itemsOf', elementName].join(DELIMITER))
86
88
  }
87
89
 
88
90
  const { nextTargetName, nextTarget } = _getNextTarget(model, element, currentPath)
@@ -121,16 +123,19 @@ const getCache = (anything, cache, newCacheFn) => {
121
123
  module.exports = (usecase, tx, target, ...args) => {
122
124
  // get model first as it may be added to tx (cf. "_ensureModel")
123
125
  const model = tx.model
126
+ if (!model) return
124
127
  // double-check with get target from model
125
128
  // since target might come from anywhere like via cqn etc
126
- const root = target && model && model.definitions[target.name]
129
+ if (!target) return
130
+ const root = (model && model.definitions[target.name]) || (target.elements && target)
131
+ if (!root) return
127
132
  // tx could be the service itself
128
133
  // prefer ApplicationService (i.e., tx.context._tx.__proto__)
129
134
  // REVISIT: context._tx is not a stable API -> pls do not rely on that
130
135
  const service = tx.context
131
136
  ? (tx.context._tx && Object.getPrototypeOf(tx.context._tx)) || Object.getPrototypeOf(tx)
132
137
  : tx
133
- if (!model || !service || !root) return
138
+ if (!service) return
134
139
  // cache templates at service for garbage collection
135
140
  if (!service._templateCache) service._templateCache = new Map()
136
141
  // model can be also a subset from tx
@@ -0,0 +1 @@
1
+ module.exports = '|$|'
@@ -1,11 +1,12 @@
1
- const _formatRowContext = ({ tKey, keyNames, row }) => {
1
+ const DELIMITER = require('./templateDelimiter')
2
+
3
+ const _formatRowContext = (tKey, keyNames, row) => {
2
4
  const keyValuePairs = keyNames.map(key => `${key}=${row[key]}`)
3
5
  const keyValuePairsSerialized = keyValuePairs.join(',')
4
6
  return `${tKey}(${keyValuePairsSerialized})`
5
7
  }
6
8
 
7
- const _processElement = args => {
8
- const { processFn, row, key, elements, picked = {}, complex = false, isRoot, pathOptions } = args
9
+ const _processElement = (processFn, row, key, elements, picked = {}, complex = false, isRoot, pathOptions) => {
9
10
  const { segments: pathSegments } = pathOptions
10
11
  const element = elements[key]
11
12
  const { plain } = picked
@@ -13,53 +14,45 @@ const _processElement = args => {
13
14
  if (plain) {
14
15
  if (!complex && pathSegments) pathSegments.push(key)
15
16
 
16
- // skip processing if row is undefined, it is not mandatory, and null is allowed
17
- // where should this go? `if (row && (row[key] !== undefined || element._isMandatory || element.notNull))`
18
- processFn(row, key, element, plain, isRoot, pathSegments)
17
+ /**
18
+ * @type import('../../types/api').templateProcessorProcessFnArgs
19
+ */
20
+ const elementInfo = { row, key, element, plain, isRoot, pathSegments }
21
+ processFn(elementInfo)
19
22
  }
20
23
  }
21
24
 
22
- const _processRow = ({ processFn, row, template, tKey, tValue, isRoot, pathOptions }) => {
25
+ const _processRow = (processFn, row, template, tKey, tValue, isRoot, pathOptions) => {
23
26
  const { template: subTemplate, picked } = tValue
24
- const key = tKey.split(' ').pop()
27
+ const key = tKey.split(DELIMITER).pop()
25
28
 
26
- const args = {
27
- processFn,
28
- row,
29
- key,
30
- elements: template.target.elements,
31
- picked,
32
- complex: !!subTemplate,
33
- isRoot,
34
- pathOptions
35
- }
36
- _processElement(args)
29
+ _processElement(processFn, row, key, template.target.elements, picked, !!subTemplate, isRoot, pathOptions)
37
30
 
38
31
  // process deep
39
32
  if (subTemplate) {
40
33
  let subRows = row && row[key]
41
34
  subRows = Array.isArray(subRows) ? subRows : [subRows]
42
- const complexArgs = { processFn, rows: subRows, template: subTemplate, tKey: key, pathOptions }
43
- _processComplex(complexArgs)
35
+ _processComplex(processFn, subRows, subTemplate, key, pathOptions)
44
36
  }
45
37
  }
46
38
 
47
- const _processComplex = ({ processFn, rows, template, tKey, pathOptions }) => {
39
+ const _processComplex = (processFn, rows, template, tKey, pathOptions) => {
48
40
  if (rows.length === 0) return
49
41
 
50
- const segments = pathOptions.segments && [...pathOptions.segments]
51
-
42
+ const segments = pathOptions.segments
52
43
  let keyNames
44
+
53
45
  for (const row of rows) {
54
46
  if (row == null) continue
55
-
56
47
  const args = { processFn, row, template, isRoot: false, pathOptions }
48
+
57
49
  if (pathOptions.includeKeyValues) {
58
50
  keyNames = keyNames || (template.target.keys && Object.keys(template.target.keys)) || []
59
- pathOptions.rowKeysGenerator({ keyNames, row, template })
60
- const pathSegment = _formatRowContext({ tKey, keyNames, row: { ...row, ...pathOptions.extraKeys } })
51
+ pathOptions.rowKeysGenerator(keyNames, row, template)
52
+ const pathSegment = _formatRowContext(tKey, keyNames, { ...row, ...pathOptions.extraKeys })
61
53
  args.pathOptions.segments = segments ? [...segments, pathSegment] : [pathSegment]
62
54
  }
55
+
63
56
  templateProcessor(args)
64
57
  }
65
58
  }
@@ -71,9 +64,8 @@ const templateProcessor = ({ processFn, row, template, isRoot = true, pathOption
71
64
  const segments = pathOptions.segments && [...pathOptions.segments]
72
65
 
73
66
  for (const [tKey, tValue] of template.elements) {
74
- const args = { processFn, row, template, tKey, tValue, isRoot, pathOptions }
75
- if (segments) args.pathOptions.segments = [...segments]
76
- _processRow(args)
67
+ if (segments) pathOptions.segments = [...segments]
68
+ _processRow(processFn, row, template, tKey, tValue, isRoot, pathOptions)
77
69
  }
78
70
  }
79
71
 
@@ -0,0 +1,31 @@
1
+ const CQN_TEMPLATE_STRING = JSON.stringify(require('./unionCqnTemplate'))
2
+
3
+ function getCQNUnionFrom(columns, active, draft, keys, user) {
4
+ let cqn = CQN_TEMPLATE_STRING
5
+
6
+ const activeCols = []
7
+ const draftCols = []
8
+ for (const col of columns) {
9
+ activeCols.push(`{ "ref": ["${col}"] }`)
10
+ draftCols.push(`{ "ref": ["${draft}", "${col}"] }`)
11
+ }
12
+ cqn = cqn.replace(/"%%ACTIVE_COLUMNS%%"/g, activeCols.join(', '))
13
+ cqn = cqn.replace(/"%%DRAFT_COLUMNS%%"/g, draftCols.join(', '))
14
+
15
+ cqn = cqn.replace(/%%ACTIVE%%/g, active)
16
+ cqn = cqn.replace(/%%DRAFT%%/g, draft)
17
+
18
+ const keyCondition = []
19
+ for (const key of keys) {
20
+ keyCondition.push(`{ "ref": ["${active}", "${key}"] }, "=", { "ref": ["${draft}", "${key}"] }`)
21
+ }
22
+ cqn = cqn.replace(/"%%KEYS%%"/g, keyCondition.join(', "and", '))
23
+
24
+ cqn = cqn.replace(/%%USER%%/g, user)
25
+
26
+ return JSON.parse(cqn)
27
+ }
28
+
29
+ module.exports = {
30
+ getCQNUnionFrom
31
+ }
@@ -0,0 +1,184 @@
1
+ module.exports = {
2
+ SET: {
3
+ op: 'union',
4
+ all: true,
5
+ args: [
6
+ {
7
+ SELECT: {
8
+ from: {
9
+ join: 'inner',
10
+ args: [
11
+ {
12
+ ref: ['%%DRAFT%%']
13
+ },
14
+ {
15
+ ref: ['DRAFT.DraftAdministrativeData'],
16
+ as: 'filterAdmin'
17
+ }
18
+ ],
19
+ on: [
20
+ {
21
+ ref: ['%%DRAFT%%', 'DraftAdministrativeData_DraftUUID']
22
+ },
23
+ '=',
24
+ {
25
+ ref: ['filterAdmin', 'DraftUUID']
26
+ }
27
+ ]
28
+ },
29
+ where: [
30
+ {
31
+ ref: ['filterAdmin', 'InProcessByUser']
32
+ },
33
+ '=',
34
+ {
35
+ val: '%%USER%%'
36
+ }
37
+ ],
38
+ columns: [
39
+ '%%DRAFT_COLUMNS%%',
40
+ {
41
+ ref: ['IsActiveEntity'],
42
+ cast: {
43
+ type: 'cds.Boolean'
44
+ }
45
+ },
46
+ {
47
+ ref: ['HasActiveEntity'],
48
+ cast: {
49
+ type: 'cds.Boolean'
50
+ }
51
+ },
52
+ {
53
+ ref: ['HasDraftEntity'],
54
+ cast: {
55
+ type: 'cds.Boolean'
56
+ }
57
+ },
58
+ {
59
+ ref: ['DraftAdministrativeData_DraftUUID']
60
+ }
61
+ ]
62
+ }
63
+ },
64
+ {
65
+ SELECT: {
66
+ from: {
67
+ ref: ['%%ACTIVE%%']
68
+ },
69
+ columns: [
70
+ '%%ACTIVE_COLUMNS%%',
71
+ {
72
+ val: true,
73
+ as: 'IsActiveEntity',
74
+ cast: {
75
+ type: 'cds.Boolean'
76
+ }
77
+ },
78
+ {
79
+ val: false,
80
+ as: 'HasActiveEntity',
81
+ cast: {
82
+ type: 'cds.Boolean'
83
+ }
84
+ },
85
+ {
86
+ xpr: [
87
+ 'case',
88
+ 'when',
89
+ {
90
+ SELECT: {
91
+ from: {
92
+ ref: ['%%DRAFT%%']
93
+ },
94
+ columns: [
95
+ {
96
+ val: 1
97
+ }
98
+ ],
99
+ where: ['(', '%%KEYS%%', ')']
100
+ },
101
+ as: 'HasDraftEntity',
102
+ cast: {
103
+ type: 'cds.Boolean'
104
+ }
105
+ },
106
+ 'IS NOT NULL',
107
+ 'then',
108
+ 'true',
109
+ 'else',
110
+ 'false',
111
+ 'end'
112
+ ],
113
+ as: 'HasDraftEntity',
114
+ cast: {
115
+ type: 'cds.Boolean'
116
+ }
117
+ },
118
+ {
119
+ SELECT: {
120
+ from: {
121
+ ref: ['%%DRAFT%%']
122
+ },
123
+ columns: [
124
+ {
125
+ ref: ['DraftAdministrativeData_DraftUUID']
126
+ }
127
+ ],
128
+ where: ['(', '%%KEYS%%', ')']
129
+ }
130
+ }
131
+ ],
132
+ where: [
133
+ 'not exists',
134
+ {
135
+ SELECT: {
136
+ from: {
137
+ join: 'inner',
138
+ args: [
139
+ {
140
+ ref: ['%%DRAFT%%']
141
+ },
142
+ {
143
+ ref: ['DRAFT.DraftAdministrativeData'],
144
+ as: 'filterAdmin'
145
+ }
146
+ ],
147
+ on: [
148
+ {
149
+ ref: ['%%DRAFT%%', 'DraftAdministrativeData_DraftUUID']
150
+ },
151
+ '=',
152
+ {
153
+ ref: ['filterAdmin', 'DraftUUID']
154
+ }
155
+ ]
156
+ },
157
+ columns: [
158
+ {
159
+ val: 1
160
+ }
161
+ ],
162
+ where: [
163
+ '(',
164
+ {
165
+ ref: ['filterAdmin', 'InProcessByUser']
166
+ },
167
+ '=',
168
+ {
169
+ val: '%%USER%%'
170
+ },
171
+ ')',
172
+ 'and',
173
+ '(',
174
+ '%%KEYS%%',
175
+ ')'
176
+ ]
177
+ }
178
+ }
179
+ ]
180
+ }
181
+ }
182
+ ]
183
+ }
184
+ }
@@ -106,7 +106,7 @@ class DatabaseService extends cds.Service {
106
106
  return {
107
107
  from: (...args) => {
108
108
  const streamQuery = SELECT.from(...args)
109
- if (!streamQuery.SELECT.columns || streamQuery.SELECT.columns.length !== 0) {
109
+ if (query && (!streamQuery.SELECT.columns || streamQuery.SELECT.columns.length !== 0)) {
110
110
  streamQuery.columns([query])
111
111
  }
112
112
  delete streamQuery.SELECT.one
@@ -1,13 +1,6 @@
1
1
  function timestampToISO(ts) {
2
- if (typeof ts === 'number') {
3
- return new Date(ts).toISOString()
4
- }
5
-
6
- // REVISIT: instanceof or object
7
- if (ts instanceof Date) {
8
- return ts.toISOString()
9
- }
10
-
2
+ if (typeof ts === 'number') return new Date(ts).toISOString()
3
+ if (ts instanceof Date) return ts.toISOString()
11
4
  return ts
12
5
  }
13
6