@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
@@ -23,6 +23,7 @@ const _getNestedVal = (row, prefix) => {
23
23
  let val = row
24
24
  const splitted = prefix.split('_')
25
25
  let k = ''
26
+
26
27
  while (splitted.length > 0) {
27
28
  k += splitted.shift()
28
29
  if (k in val) {
@@ -32,11 +33,13 @@ const _getNestedVal = (row, prefix) => {
32
33
  k += '_'
33
34
  }
34
35
  }
36
+
35
37
  return val
36
38
  }
37
39
 
38
40
  const _propagateToChid = (foreignKeyPropagation, row, childRow) => {
39
41
  const { parentFieldName, childFieldName, prefix, parentFieldValue } = foreignKeyPropagation
42
+
40
43
  if (parentFieldName) {
41
44
  if (prefix) {
42
45
  const nested = _getNestedVal(row, prefix)
@@ -54,18 +57,26 @@ const _propagateToParent = (foreignKeyPropagations, childRow, row) => {
54
57
  const deep = foreignKeyPropagations.deep
55
58
  _propagateToParent(deep.propagation, childRow[deep.targetName], childRow)
56
59
  }
57
- if (childRow && Object.prototype.hasOwnProperty.call(childRow, foreignKeyPropagations.childFieldName))
60
+
61
+ if (childRow && Object.prototype.hasOwnProperty.call(childRow, foreignKeyPropagations.childFieldName)) {
58
62
  row[foreignKeyPropagations.parentFieldName] = childRow[foreignKeyPropagations.childFieldName]
63
+ }
59
64
  }
60
65
 
61
- const propagateForeignKeys = (tKey, row, foreignKeyPropagations) => {
66
+ const propagateForeignKeys = (tKey, row, foreignKeyPropagations, opts = {}) => {
62
67
  const childRows = Array.isArray(row[tKey]) ? row[tKey] : [row[tKey]]
68
+
63
69
  for (const childRow of childRows) {
64
70
  if (!childRow) return
71
+
65
72
  for (const foreignKeyPropagation of foreignKeyPropagations) {
66
73
  if (foreignKeyPropagation.fillChild) {
67
74
  _generateParentField(foreignKeyPropagation, row)
68
- _propagateToChid(foreignKeyPropagation, row, childRow)
75
+ if (opts.onlyWriteCompositionEffective && !foreignKeyPropagations._element._isCompositionEffective) {
76
+ delete row[tKey]
77
+ } else {
78
+ _propagateToChid(foreignKeyPropagation, row, childRow)
79
+ }
69
80
  } else {
70
81
  _generateChildField(foreignKeyPropagation, childRow)
71
82
  _propagateToParent(foreignKeyPropagation, childRow, row)
@@ -79,6 +90,7 @@ const _getSubOns = on => {
79
90
  const newOn = on.filter(e => e !== '(' && e !== ')')
80
91
  const subOns = []
81
92
  let currArr = []
93
+
82
94
  for (const onEl of newOn) {
83
95
  if (currArr.length === 0) subOns.push(currArr)
84
96
  if (onEl !== 'and') currArr.push(onEl)
@@ -86,11 +98,13 @@ const _getSubOns = on => {
86
98
  currArr = []
87
99
  }
88
100
  }
101
+
89
102
  for (const subOn of subOns) {
90
103
  // We don't support anything else than
91
104
  // A = B AND C = D AND ...
92
105
  if (subOn.length !== 3) return []
93
106
  }
107
+
94
108
  return subOns
95
109
  }
96
110
 
@@ -99,6 +113,7 @@ const _autoGenerate = el => el && el.type === 'cds.UUID' && el.key
99
113
  const _parentFieldsFromSimpleOnCond = (element, subOn) => {
100
114
  const idxChildField = subOn.findIndex(o => o.ref && o.ref[0] === element.name)
101
115
  if (idxChildField === -1 || subOn[1] !== '=') return
116
+
102
117
  const childFieldName = subOn[idxChildField].ref && subOn[idxChildField].ref.slice(1).join('_')
103
118
  const childElement = element._target.elements[childFieldName]
104
119
  const idxParentField = idxChildField === 2 ? 0 : 2
@@ -126,9 +141,11 @@ const _parentFieldsFromSimpleOnCond = (element, subOn) => {
126
141
  if (!childElement.on && parentRef && parentRef.length === 1) {
127
142
  return _foreignKeyPropagationsFromToManyOn(element, parentRef, childFieldName)
128
143
  }
144
+
129
145
  if ('val' in subOn[idxParentField]) {
130
146
  return _foreignKeyPropagationsFromStaticOn(childFieldName, idxParentField, subOn)
131
147
  }
148
+
132
149
  if (childElement._isAssociationStrict && childElement.on) {
133
150
  return _foreignKeyPropagationsFromCustomBacklink(element, childElement)
134
151
  }
@@ -144,6 +161,7 @@ const _foreignKeyPropagationsFromToManyOn = (element, parentRef, childFieldName)
144
161
  const parentFieldName = parentRef[0]
145
162
  if (parentFieldName === '$self') {
146
163
  const foreignKeys = _foreignKeysForTarget(element, childFieldName)
164
+
147
165
  // REVISIT foreignKeys is empty if we have deep operations where a sub element is annotated with persistence skip
148
166
  if (foreignKeys && foreignKeys.length) {
149
167
  const parentKeys = _parentKeys(element)
@@ -167,11 +185,13 @@ const _foreignKeyPropagationsFromToManyOn = (element, parentRef, childFieldName)
167
185
  const _foreignKeyPropagationsFromCustomBacklink = (element, childElement) => {
168
186
  const foreignKeyPropagations = []
169
187
  const subOns = _getSubOns(childElement.on)
188
+
170
189
  for (const subOn of subOns) {
171
190
  if (subOn[1] === '=') {
172
191
  const parentFieldIdx = subOn.findIndex(o => o.ref && o.ref[0] === childElement.name)
173
192
  const otherFieldIdx = parentFieldIdx === 0 ? 2 : 0
174
193
  const otherField = subOn[otherFieldIdx]
194
+
175
195
  if (otherField.ref && otherField.ref.length === 1) {
176
196
  const parentFieldName = subOn[parentFieldIdx].ref[1]
177
197
  foreignKeyPropagations.push({
@@ -192,17 +212,19 @@ const _foreignKeyPropagationsFromCustomBacklink = (element, childElement) => {
192
212
  }
193
213
  }
194
214
  }
215
+
195
216
  return foreignKeyPropagations
196
217
  }
197
218
 
198
219
  const _foreignKeyPropagationsFromOn = (element, on) => {
199
220
  const subOns = _getSubOns(on)
200
-
201
221
  const foreignKeyPropagations = []
222
+
202
223
  for (const subOn of subOns) {
203
224
  const subParentFields = _parentFieldsFromSimpleOnCond(element, subOn)
204
225
  if (subParentFields) foreignKeyPropagations.push(...subParentFields)
205
226
  }
227
+
206
228
  return foreignKeyPropagations
207
229
  }
208
230
 
@@ -226,6 +248,7 @@ const _resolve4struct = (others, struct, fkps, fillChild, childIsStruct, i) => {
226
248
  for (const k in struct.elements) {
227
249
  const other = others[i + j]
228
250
  const current = struct.elements[k]
251
+
229
252
  if (current._isStructured) {
230
253
  // call recursive and increment skip
231
254
  j += _resolve4struct(others, current, fkps, fillChild, childIsStruct, i + j)
@@ -239,6 +262,7 @@ const _resolve4struct = (others, struct, fkps, fillChild, childIsStruct, i) => {
239
262
  prefix = cur.name + '_' + prefix
240
263
  cur = cur.parent
241
264
  }
265
+
242
266
  // push propagation
243
267
  fkps.push({
244
268
  childFieldName: childIsStruct ? current.name : other.name,
@@ -248,6 +272,7 @@ const _resolve4struct = (others, struct, fkps, fillChild, childIsStruct, i) => {
248
272
  prefix,
249
273
  deep: !fillChild && _resolveTargetForeignKey(childIsStruct ? current : other)
250
274
  })
275
+
251
276
  // increment skip
252
277
  j++
253
278
  }
@@ -259,8 +284,8 @@ const _resolve4struct = (others, struct, fkps, fillChild, childIsStruct, i) => {
259
284
  const _resolveTargetForeignKey = targetKey => {
260
285
  const targetName = targetKey['@odata.foreignKey4']
261
286
  if (!targetName) return
262
- const _foreignKeyPropagations = foreignKeyPropagations(targetKey.parent.elements[targetName])
263
- const propagation = _foreignKeyPropagations.find(_fkp => targetKey.name === _fkp.parentFieldName)
287
+ const _foreignKeyProps = foreignKeyPropagations(targetKey.parent.elements[targetName])
288
+ const propagation = _foreignKeyProps.find(_fkp => targetKey.name === _fkp.parentFieldName)
264
289
  return { targetName, propagation }
265
290
  }
266
291
 
@@ -289,7 +314,7 @@ const resolvedKeys = (foreignKeys, targetKeys, fillChild) => {
289
314
  return foreignKeyPropagations
290
315
  }
291
316
 
292
- const foreignKeyPropagations = element => {
317
+ const _foreignKeyPropagations = element => {
293
318
  if (element.is2many && element.on) {
294
319
  return _foreignKeyPropagationsFromOn(element, element.on)
295
320
  }
@@ -297,6 +322,7 @@ const foreignKeyPropagations = element => {
297
322
  if (element.is2one) {
298
323
  if (!element.on) {
299
324
  const foreignKeys = _foreignKeys(element)
325
+
300
326
  if (foreignKeys) {
301
327
  const targetKeys = _targetKeys(element)
302
328
  return resolvedKeys(foreignKeys, targetKeys)
@@ -310,6 +336,12 @@ const foreignKeyPropagations = element => {
310
336
  }
311
337
  }
312
338
 
339
+ const foreignKeyPropagations = element => {
340
+ const foreignKeyProps = _foreignKeyPropagations(element)
341
+ if (foreignKeyProps) foreignKeyProps._element = element
342
+ return foreignKeyProps
343
+ }
344
+
313
345
  const _foreignKeys = csnElement => {
314
346
  return Object.values(csnElement.parent.elements).filter(element => element['@odata.foreignKey4'] === csnElement.name)
315
347
  }
@@ -74,20 +74,19 @@ const _foreignToOn = (csnElement, options) => {
74
74
  const foreignKeys = foreignKeyPropagations(csnElement)
75
75
 
76
76
  // for external services, there might be no foreign keys
77
- if (foreignKeys) {
78
- for (const key of foreignKeys) {
79
- if (on.length !== 0) {
80
- on.push('and')
81
- }
82
-
83
- // TODO static values possible here?
77
+ if (!foreignKeys) return on
84
78
 
85
- on.push(
86
- _toRef(aliases.select, key.prefix ? key.prefix + '_' + key.childFieldName : key.childFieldName),
87
- '=',
88
- _toRef(aliases.join, _structPrefix(csnElement) + key.parentFieldName)
89
- )
79
+ for (const key of foreignKeys) {
80
+ if (on.length !== 0) {
81
+ on.push('and')
90
82
  }
83
+
84
+ // TODO static values possible here?
85
+
86
+ const ref1 = _toRef(aliases.select, key.prefix ? `${key.prefix}_${key.childFieldName}` : key.childFieldName)
87
+ const structPrefix = _structPrefix(csnElement)
88
+ const ref2 = _toRef(aliases.join, `${structPrefix}${key.parentFieldName}`)
89
+ on.push(ref1, '=', ref2)
91
90
  }
92
91
 
93
92
  return on
@@ -0,0 +1,10 @@
1
+ module.exports = req => {
2
+ // if custom handlers uses only expression like {col: {'+=': 1}},
3
+ // req.data will only contain the keys
4
+ if (req.query.UPDATE.with && Object.keys(req.query.UPDATE.with).length > 0) {
5
+ return false
6
+ }
7
+
8
+ const keys = Object.keys(req.target.keys || {})
9
+ return !Object.keys(req.data).some(k => !keys.includes(k))
10
+ }
@@ -0,0 +1,35 @@
1
+ const cds = require('../../cds')
2
+
3
+ /*
4
+ * returns path like <service>.<entity>:<prop1>.<prop2> for ref = [{ id: '<service>.<entity>' }, '<prop1>', '<prop2>']
5
+ */
6
+ const getPathFromRef = ref => {
7
+ const x = ref.reduce((acc, cur) => {
8
+ acc += (acc ? ':' : '') + (cur.id ? cur.id : cur)
9
+ return acc
10
+ }, '')
11
+ const y = x.split(':')
12
+ let z = y.shift()
13
+ if (y.length) z += ':' + y.join('.')
14
+ return z
15
+ }
16
+
17
+ /*
18
+ * returns the target entity for the given path
19
+ */
20
+ const getEntityFromPath = (path, model) => {
21
+ let current = { elements: model.definitions }
22
+ path = typeof path === 'string' ? cds.parse.path(path) : path
23
+ const segments = [...path.ref]
24
+ while (segments.length) {
25
+ const segment = segments.shift()
26
+ current = current.elements[segment.id || segment]
27
+ if (current.target) current = model.definitions[current.target]
28
+ }
29
+ return current
30
+ }
31
+
32
+ module.exports = {
33
+ getPathFromRef,
34
+ getEntityFromPath
35
+ }
@@ -0,0 +1,86 @@
1
+ const { revertData } = require('./resolveView')
2
+
3
+ // creates a map with key "remote origin name" and value { as: "projection name"}
4
+ // if it is an expand, it contains an additional property .expand with classic ref/as syntax
5
+ // ref/as syntax is kept in order to reuse handleAliasInResult
6
+ const _createAliasMap = columns => {
7
+ if (columns) {
8
+ let aliasMap
9
+ for (const col of columns) {
10
+ const processor = {}
11
+ if (col.as) {
12
+ processor.as = col.as
13
+ aliasMap || (aliasMap = new Map())
14
+ if (col.ref) {
15
+ aliasMap.set(col.ref[col.ref.length - 1], processor)
16
+ }
17
+ }
18
+ if (col.expand) {
19
+ processor.expand = col.expand
20
+ }
21
+ }
22
+
23
+ return aliasMap
24
+ }
25
+ }
26
+
27
+ // Transforms the result of the remote service according to the provided aliases
28
+ const handleAliasInResult = (columns, result) => {
29
+ const postProcessor = _createAliasMap(columns)
30
+ const resultArray = Array.isArray(result) ? result : [result]
31
+ if (postProcessor) {
32
+ for (const row of resultArray) {
33
+ // we need to use a cache because of cross renamings
34
+ // e. g. column a is renamed to b and column b is renamed to a
35
+ const tempCache = new Map()
36
+
37
+ for (const col in row) {
38
+ const processor = postProcessor.get(col)
39
+ if (processor && processor.as !== col) {
40
+ // if a value for the alias is already present, add it to the cache
41
+ if (row[processor.as]) {
42
+ tempCache.set(processor.as, row[processor.as])
43
+ }
44
+
45
+ // get the value from cache if present
46
+ row[processor.as] = tempCache.get(col) || row[col]
47
+
48
+ // if it was not overridden because of a renaming,
49
+ // delete it from the row
50
+ if (!tempCache.has(processor.as)) {
51
+ delete row[col]
52
+ }
53
+ }
54
+
55
+ if (processor && processor.expand) {
56
+ handleAliasInResult(processor.expand, row[processor.as || col])
57
+ }
58
+ }
59
+ }
60
+ }
61
+ }
62
+
63
+ // REVISIT: todo renaming for expanded entities
64
+ // REVISIT: todo renaming for deep operations
65
+ const postProcess = (query, result, onlySelectAliases = false) => {
66
+ if (query.SELECT) {
67
+ handleAliasInResult(query.SELECT.columns, result)
68
+
69
+ if (!onlySelectAliases) {
70
+ const transition =
71
+ query.SELECT && query.SELECT._transitions && query.SELECT._transitions[query.SELECT._transitions.length - 1]
72
+ if (transition) return revertData(result, transition)
73
+ }
74
+
75
+ return result
76
+ }
77
+ if (query.DELETE) return result
78
+ let transition
79
+ if (query.INSERT) transition = query.INSERT._transitions[query.INSERT._transitions.length - 1]
80
+ if (query.UPDATE) transition = query.UPDATE._transitions[query.UPDATE._transitions.length - 1]
81
+ return revertData(result, transition)
82
+ }
83
+
84
+ module.exports = {
85
+ postProcess
86
+ }
@@ -1,39 +1,50 @@
1
1
  const cds = require('../../cds')
2
2
 
3
- // REVISIT: compiler to provide API for smart quoting (not just list)
4
- // require list from compiler
5
- const _COMPILER_RESERVED = {}
6
- try {
7
- const keywords = require('@sap/cds-compiler/lib/base/keywords')
8
- _COMPILER_RESERVED.hana = new Set(keywords.hana)
9
- _COMPILER_RESERVED.sqlite = new Set(keywords.sqlite)
10
- } catch (e) {
11
- // ignore
12
- }
3
+ const keywords = require('@sap/cds-compiler/lib/base/keywords')
4
+ const { smartId } = require('@sap/cds-compiler/lib/sql-identifier')
5
+
6
+ let _dialect
13
7
 
14
- // fallback
15
8
  const _DEFAULT_RESERVED = new Set(['WHERE', 'GROUP', 'ORDER', 'BY', 'AT', 'NO', 'LIMIT'])
16
- let RESERVED = _DEFAULT_RESERVED
9
+ const _COMPILER_RESERVED = {
10
+ hana: new Set(keywords.hana),
11
+ sqlite: new Set(keywords.sqlite)
12
+ }
13
+ let _reserved = _DEFAULT_RESERVED
17
14
 
18
- // exclude list
19
- const EXCLUDE_LIST = new Set(['CURRENT_TIMESTAMP'])
15
+ const _isTruthy = s => s
16
+ const _isQuoted = s => s.match(/^".*"$/)
20
17
 
21
- const _slugify = name => name.replace(/\./g, '_')
18
+ const _slugify = s => s.replace(/\./g, '_')
19
+ const _smartId = s => smartId(_slugify(s), _dialect || 'plain')
20
+ const _smartElement = s => {
21
+ if (s === '*' || _isQuoted(s)) return s
22
+ const upper = s.toUpperCase()
23
+ if (_reserved.has(upper)) return upper
24
+ return _smartId(s)
25
+ }
22
26
 
23
27
  module.exports = {
24
- quoted: name => `"${name}"`,
25
- plain: name => {
26
- const upper = name.toUpperCase()
27
- if (EXCLUDE_LIST.has(upper)) return name
28
+ plain: s => {
29
+ // set _dialect and _reserved once cds.db.kind is set
30
+ if (!_dialect && cds.db && cds.db.kind) {
31
+ _dialect = cds.db.options.dialect || cds.db.kind
32
+ _reserved = _COMPILER_RESERVED[_dialect] || _DEFAULT_RESERVED
33
+ }
34
+
35
+ // * or already quoted?
36
+ if (s === '*' || _isQuoted(s)) return s
28
37
 
29
- if (cds.db) {
30
- RESERVED = (cds.env.features.compiler_keywords !== false && _COMPILER_RESERVED[cds.db.kind]) || _DEFAULT_RESERVED
38
+ // expr or space in name?
39
+ // REVISIT: default behavior in cds^6?
40
+ if (s.match(/\s/) && !cds.env.sql.spaced_columns) {
41
+ return s.split(' ').filter(_isTruthy).map(_smartElement).join(' ')
31
42
  }
32
43
 
33
- // REVISIT: _slugify(name) correct? cap-samples' tests needs it this way
34
- return RESERVED.has(upper) ? `"${upper}"` : _slugify(name)
44
+ return _smartId(s)
35
45
  },
36
- 'all-upper': name => `"${_slugify(name.toUpperCase())}"`,
37
- 'all-lower': name => `"${_slugify(name.toLowerCase())}"`,
38
- bracketed: name => `[${name}]`
46
+ quoted: s => `"${s}"`,
47
+ bracketed: s => `[${s}]`,
48
+ 'all-upper': s => `"${_slugify(s.toUpperCase())}"`,
49
+ 'all-lower': s => `"${_slugify(s.toLowerCase())}"`
39
50
  }