@sap/cds 5.9.8 → 6.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (381) hide show
  1. package/CHANGELOG.md +277 -20
  2. package/apis/services.d.ts +1 -1
  3. package/app/fiori/preview.js +2 -6
  4. package/app/index.js +3 -3
  5. package/bin/build/buildTaskEngine.js +17 -15
  6. package/bin/build/buildTaskFactory.js +29 -19
  7. package/bin/build/buildTaskHandler.js +27 -11
  8. package/bin/build/buildTaskProvider.js +2 -4
  9. package/bin/build/buildTaskProviderFactory.js +11 -16
  10. package/bin/build/constants.js +14 -6
  11. package/bin/build/csv-reader.js +2 -1
  12. package/bin/build/index.js +12 -18
  13. package/bin/build/provider/buildTaskHandlerEdmx.js +3 -39
  14. package/bin/build/provider/buildTaskHandlerFeatureToggles.js +149 -0
  15. package/bin/build/provider/buildTaskHandlerInternal.js +2 -3
  16. package/bin/build/provider/buildTaskProviderInternal.js +108 -239
  17. package/bin/build/provider/fiori/index.js +2 -2
  18. package/bin/build/provider/hana/2migration.js +11 -11
  19. package/bin/build/provider/hana/2tabledata.js +3 -3
  20. package/bin/build/provider/hana/index.js +89 -99
  21. package/bin/build/provider/hana/migrationtable.js +4 -3
  22. package/bin/build/provider/java/index.js +101 -0
  23. package/bin/build/provider/java-cf/index.js +1 -101
  24. package/bin/build/provider/mtx/index.js +83 -41
  25. package/bin/build/provider/mtx/resourcesTarBuilder.js +68 -0
  26. package/bin/build/provider/mtx-sidecar/index.js +110 -0
  27. package/bin/build/provider/node-cf/index.js +1 -308
  28. package/bin/build/provider/nodejs/index.js +189 -0
  29. package/bin/build/util.js +21 -31
  30. package/bin/cds.js +5 -3
  31. package/bin/deploy/to-hana/cfUtil.js +31 -6
  32. package/bin/deploy/to-hana/gitUtil.js +5 -3
  33. package/bin/deploy/to-hana/hana.js +15 -13
  34. package/bin/{build → deploy/to-hana}/mtaUtil.js +10 -9
  35. package/bin/mtx/in-cds.js +19 -7
  36. package/bin/serve.js +49 -22
  37. package/bin/utils/log.js +13 -30
  38. package/bin/version.js +4 -3
  39. package/common.cds +61 -16
  40. package/lib/compile/cdsc.js +3 -2
  41. package/lib/compile/etc/_localized.js +15 -14
  42. package/lib/compile/for/drafts.js +3 -4
  43. package/lib/compile/for/java.js +13 -10
  44. package/lib/compile/for/nodejs.js +8 -8
  45. package/lib/compile/for/odata.js +7 -12
  46. package/lib/compile/for/sql.js +5 -6
  47. package/lib/compile/index.js +5 -4
  48. package/lib/compile/load.js +9 -11
  49. package/lib/compile/minify.js +8 -5
  50. package/lib/compile/parse.js +4 -2
  51. package/lib/compile/resolve.js +18 -15
  52. package/lib/compile/to/edm.js +0 -1
  53. package/lib/compile/to/gql.js +3 -2
  54. package/lib/compile/to/json.js +24 -17
  55. package/lib/connect/bindings.js +3 -2
  56. package/lib/connect/index.js +5 -5
  57. package/lib/core/classes.js +74 -2
  58. package/lib/core/entities.js +52 -3
  59. package/lib/core/reflect.js +2 -1
  60. package/lib/deploy.js +10 -8
  61. package/lib/env/defaults.js +4 -3
  62. package/lib/env/index.js +71 -31
  63. package/lib/env/presets.js +1 -14
  64. package/lib/env/requires.js +71 -20
  65. package/lib/env/serviceBindings.js +147 -0
  66. package/lib/i18n/localize.js +22 -23
  67. package/lib/index.js +148 -144
  68. package/lib/log/errors.js +55 -12
  69. package/lib/log/format/kibana.js +1 -1
  70. package/lib/log/index.js +4 -0
  71. package/lib/ql/SELECT.js +7 -2
  72. package/lib/ql/Whereable.js +8 -2
  73. package/lib/ql/index.js +2 -2
  74. package/lib/req/assert.js +71 -0
  75. package/lib/req/cds-context.js +38 -70
  76. package/lib/req/context.js +34 -21
  77. package/lib/req/request.js +12 -18
  78. package/lib/req/response.js +6 -2
  79. package/lib/req/user.js +30 -22
  80. package/lib/serve/Service-api.js +17 -12
  81. package/lib/serve/Service-dispatch.js +5 -9
  82. package/lib/serve/Service-methods.js +4 -3
  83. package/lib/serve/Transaction.js +24 -21
  84. package/lib/serve/adapters.js +15 -5
  85. package/lib/serve/factory.js +22 -20
  86. package/lib/serve/index.js +51 -54
  87. package/lib/utils/axios.js +8 -12
  88. package/lib/utils/index.js +13 -4
  89. package/lib/utils/resources/index.js +1 -44
  90. package/lib/utils/resources/tar.js +2 -1
  91. package/lib/utils/tests.js +13 -15
  92. package/libx/_runtime/.eslintrc +1 -1
  93. package/libx/_runtime/audit/Service.js +6 -4
  94. package/libx/_runtime/audit/generic/personal/access.js +19 -43
  95. package/libx/_runtime/audit/generic/personal/index.js +40 -34
  96. package/libx/_runtime/audit/generic/personal/modification.js +11 -9
  97. package/libx/_runtime/audit/generic/personal/utils.js +13 -6
  98. package/libx/_runtime/audit/utils/v2.js +6 -3
  99. package/libx/_runtime/auth/index.js +71 -66
  100. package/libx/_runtime/auth/strategies/JWT.js +3 -2
  101. package/libx/_runtime/auth/strategies/mock.js +54 -53
  102. package/libx/_runtime/auth/strategies/xssecUtils.js +3 -4
  103. package/libx/_runtime/auth/strategies/xsuaa.js +3 -2
  104. package/libx/_runtime/auth/utils.js +2 -15
  105. package/libx/_runtime/cds-services/adapter/odata-v4/Dispatcher.js +127 -41
  106. package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +9 -5
  107. package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +93 -73
  108. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/action.js +25 -45
  109. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/create.js +10 -14
  110. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/error.js +9 -5
  111. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +4 -2
  112. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +60 -53
  113. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +2 -2
  114. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +21 -26
  115. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +8 -15
  116. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/expandToCQN.js +29 -41
  117. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/index.js +1 -4
  118. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/readToCQN.js +13 -13
  119. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/selectToCQN.js +0 -7
  120. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/utils.js +24 -1
  121. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/edm/EdmEntityContainer.js +1 -1
  122. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/UriHelper.js +4 -3
  123. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/utils/PrimitiveValueDecoder.js +4 -5
  124. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/utils/ValueConverter.js +4 -3
  125. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/validator/ValueValidator.js +5 -3
  126. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/core/ResponseHeaderSetter.js +2 -0
  127. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/invocation/DebugSerializingCommand.js +1 -1
  128. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/invocation/PresetResponseHeadersCommand.js +1 -1
  129. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/invocation/SerializingCommand.js +1 -1
  130. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/invocation/SetResponseHeadersCommand.js +1 -1
  131. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/serializer/ContextURLFactory.js +3 -2
  132. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/serializer/ErrorJsonSerializer.js +3 -1
  133. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/serializer/SerializerFactory.js +1 -0
  134. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/serializer/TrustedResourceJsonSerializer.js +3 -3
  135. package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +36 -25
  136. package/libx/_runtime/cds-services/adapter/odata-v4/utils/handlerUtils.js +97 -92
  137. package/libx/_runtime/cds-services/adapter/odata-v4/utils/metaInfo.js +382 -0
  138. package/libx/_runtime/cds-services/adapter/odata-v4/utils/oDataConfiguration.js +1 -4
  139. package/libx/_runtime/cds-services/adapter/odata-v4/utils/omitValues.js +5 -6
  140. package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +82 -21
  141. package/libx/_runtime/cds-services/adapter/odata-v4/utils/request.js +3 -11
  142. package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +91 -69
  143. package/libx/_runtime/cds-services/adapter/odata-v4/utils/stream.js +27 -6
  144. package/libx/_runtime/cds-services/adapter/rest/utils/validation-checks.js +7 -17
  145. package/libx/_runtime/cds-services/services/Service.js +17 -76
  146. package/libx/_runtime/cds-services/services/utils/columns.js +6 -4
  147. package/libx/_runtime/cds-services/services/utils/compareJson.js +1 -53
  148. package/libx/_runtime/cds-services/services/utils/differ.js +15 -19
  149. package/libx/_runtime/cds-services/util/assert.js +107 -34
  150. package/libx/_runtime/cds.js +1 -31
  151. package/libx/_runtime/common/aspects/Association.js +40 -54
  152. package/libx/_runtime/common/aspects/any.js +61 -6
  153. package/libx/_runtime/common/aspects/entity.js +19 -79
  154. package/libx/_runtime/common/composition/data.js +2 -2
  155. package/libx/_runtime/common/composition/delete.js +8 -7
  156. package/libx/_runtime/common/composition/tree.js +10 -10
  157. package/libx/_runtime/common/composition/update.js +3 -2
  158. package/libx/_runtime/common/constants/events.js +13 -0
  159. package/libx/_runtime/common/error/entry.js +9 -3
  160. package/libx/_runtime/common/error/frontend.js +13 -19
  161. package/libx/_runtime/common/error/index.js +8 -3
  162. package/libx/_runtime/common/generic/auth/capabilities.js +2 -1
  163. package/libx/_runtime/common/generic/auth/constants.js +1 -4
  164. package/libx/_runtime/common/generic/auth/requires.js +1 -1
  165. package/libx/_runtime/common/generic/auth/restrict.js +12 -28
  166. package/libx/_runtime/common/generic/auth/restrictions.js +12 -4
  167. package/libx/_runtime/common/generic/auth/utils.js +2 -1
  168. package/libx/_runtime/common/generic/crud.js +9 -60
  169. package/libx/_runtime/common/generic/etag.js +41 -7
  170. package/libx/_runtime/common/generic/input.js +128 -66
  171. package/libx/_runtime/common/generic/paging.js +9 -3
  172. package/libx/_runtime/common/generic/put.js +2 -2
  173. package/libx/_runtime/common/generic/sorting.js +7 -3
  174. package/libx/_runtime/common/generic/temporal.js +0 -5
  175. package/libx/_runtime/common/i18n/messages.properties +2 -1
  176. package/libx/_runtime/common/utils/binary.js +69 -0
  177. package/libx/_runtime/common/utils/cqn.js +39 -14
  178. package/libx/_runtime/common/utils/cqn2cqn4sql.js +93 -59
  179. package/libx/_runtime/common/utils/csn.js +87 -85
  180. package/libx/_runtime/common/utils/dollar.js +8 -7
  181. package/libx/_runtime/common/utils/draft.js +1 -1
  182. package/libx/_runtime/common/utils/foreignKeyPropagations.js +23 -7
  183. package/libx/_runtime/common/utils/generateOnCond.js +2 -1
  184. package/libx/_runtime/common/utils/keys.js +30 -13
  185. package/libx/_runtime/common/utils/postProcessing.js +6 -1
  186. package/libx/_runtime/common/utils/quotingStyles.js +0 -23
  187. package/libx/_runtime/common/utils/resolveStructured.js +23 -26
  188. package/libx/_runtime/common/utils/resolveView.js +4 -1
  189. package/libx/_runtime/common/utils/rewriteAsterisks.js +3 -0
  190. package/libx/_runtime/common/utils/search2cqn4sql.js +4 -13
  191. package/libx/_runtime/common/utils/searchToLike.js +9 -13
  192. package/libx/_runtime/common/utils/streamProp.js +35 -0
  193. package/libx/_runtime/common/utils/structured.js +12 -18
  194. package/libx/_runtime/common/utils/template.js +3 -5
  195. package/libx/_runtime/common/utils/templateProcessor.js +22 -14
  196. package/libx/_runtime/common/utils/unionCqnTemplate.js +4 -14
  197. package/libx/_runtime/db/Service.js +2 -1
  198. package/libx/_runtime/db/expand/expand-v2.js +2 -2
  199. package/libx/_runtime/db/expand/expandCQNToJoin.js +7 -6
  200. package/libx/_runtime/db/generic/input.js +14 -17
  201. package/libx/_runtime/db/generic/integrity.js +1 -2
  202. package/libx/_runtime/db/generic/update.js +14 -1
  203. package/libx/_runtime/db/query/read.js +0 -1
  204. package/libx/_runtime/db/query/update.js +1 -1
  205. package/libx/_runtime/db/sql-builder/BaseBuilder.js +1 -1
  206. package/libx/_runtime/db/sql-builder/ExpressionBuilder.js +5 -31
  207. package/libx/_runtime/db/sql-builder/InsertBuilder.js +1 -1
  208. package/libx/_runtime/db/sql-builder/ReferenceBuilder.js +0 -9
  209. package/libx/_runtime/db/sql-builder/SelectBuilder.js +11 -10
  210. package/libx/_runtime/db/sql-builder/UpdateBuilder.js +2 -2
  211. package/libx/_runtime/db/sql-builder/annotations.js +1 -2
  212. package/libx/_runtime/db/utils/coloredTxCommands.js +5 -0
  213. package/libx/_runtime/db/utils/columns.js +1 -1
  214. package/libx/_runtime/db/utils/propagateForeignKeys.js +10 -2
  215. package/libx/_runtime/extensibility/activate.js +69 -0
  216. package/libx/_runtime/extensibility/add.js +41 -0
  217. package/libx/_runtime/extensibility/addExtension.js +68 -0
  218. package/libx/_runtime/extensibility/defaults.js +39 -0
  219. package/libx/_runtime/extensibility/{uiflex/handler → handler}/transformREAD.js +0 -0
  220. package/libx/_runtime/extensibility/{uiflex/handler → handler}/transformRESULT.js +2 -2
  221. package/libx/_runtime/extensibility/{uiflex/handler → handler}/transformWRITE.js +2 -2
  222. package/libx/_runtime/extensibility/push.js +61 -0
  223. package/libx/_runtime/extensibility/service.js +21 -0
  224. package/libx/_runtime/extensibility/{uiflex/utils.js → utils.js} +39 -3
  225. package/libx/_runtime/extensibility/validation.js +53 -0
  226. package/libx/_runtime/extensibility/views.js +12 -0
  227. package/libx/_runtime/fiori/generic/activate.js +2 -4
  228. package/libx/_runtime/fiori/generic/before.js +17 -29
  229. package/libx/_runtime/fiori/generic/cancel.js +2 -4
  230. package/libx/_runtime/fiori/generic/delete.js +2 -4
  231. package/libx/_runtime/fiori/generic/edit.js +4 -16
  232. package/libx/_runtime/fiori/generic/index.js +31 -0
  233. package/libx/_runtime/fiori/generic/new.js +5 -21
  234. package/libx/_runtime/fiori/generic/patch.js +10 -15
  235. package/libx/_runtime/fiori/generic/prepare.js +13 -22
  236. package/libx/_runtime/fiori/generic/read.js +148 -163
  237. package/libx/_runtime/fiori/generic/readOverDraft.js +10 -4
  238. package/libx/_runtime/fiori/utils/handler.js +10 -22
  239. package/libx/_runtime/fiori/utils/where.js +1 -4
  240. package/libx/_runtime/hana/Service.js +14 -7
  241. package/libx/_runtime/hana/customBuilder/CustomSelectBuilder.js +1 -1
  242. package/libx/_runtime/hana/dynatrace.js +2 -2
  243. package/libx/_runtime/hana/localized.js +7 -6
  244. package/libx/_runtime/hana/pool.js +9 -6
  245. package/libx/_runtime/hana/search.js +2 -3
  246. package/libx/_runtime/hana/{searchToContains.js → search2Contains.js} +5 -2
  247. package/libx/_runtime/hana/search2cqn4sql.js +20 -17
  248. package/libx/_runtime/index.js +2 -6
  249. package/libx/_runtime/messaging/AMQPWebhookMessaging.js +30 -22
  250. package/libx/_runtime/messaging/common-utils/AMQPClient.js +4 -3
  251. package/libx/_runtime/messaging/common-utils/appId.js +9 -0
  252. package/libx/_runtime/messaging/common-utils/authorizedRequest.js +2 -18
  253. package/libx/_runtime/messaging/common-utils/connections.js +1 -1
  254. package/libx/_runtime/messaging/enterprise-messaging-shared.js +2 -2
  255. package/libx/_runtime/messaging/enterprise-messaging-utils/EMManagement.js +305 -231
  256. package/libx/_runtime/messaging/enterprise-messaging-utils/cloudEvents.js +2 -2
  257. package/libx/_runtime/messaging/enterprise-messaging-utils/options-management.js +15 -8
  258. package/libx/_runtime/messaging/enterprise-messaging-utils/options-messaging.js +57 -14
  259. package/libx/_runtime/messaging/enterprise-messaging.js +14 -19
  260. package/libx/_runtime/messaging/file-based.js +3 -1
  261. package/libx/_runtime/messaging/http-utils/token.js +18 -6
  262. package/libx/_runtime/messaging/message-queuing-utils/options-management.js +22 -12
  263. package/libx/_runtime/messaging/message-queuing-utils/options-messaging.js +27 -14
  264. package/libx/_runtime/messaging/message-queuing.js +138 -85
  265. package/libx/_runtime/messaging/outbox/utils.js +13 -7
  266. package/libx/_runtime/messaging/redis-messaging.js +0 -1
  267. package/libx/_runtime/messaging/service.js +4 -1
  268. package/libx/_runtime/remote/Service.js +24 -18
  269. package/libx/_runtime/remote/utils/client.js +90 -48
  270. package/libx/_runtime/remote/utils/data.js +23 -6
  271. package/libx/_runtime/sqlite/Service.js +14 -13
  272. package/libx/_runtime/sqlite/convertAssocToOneManaged.js +2 -0
  273. package/libx/_runtime/sqlite/customBuilder/CustomSelectBuilder.js +1 -0
  274. package/libx/_runtime/sqlite/execute.js +3 -9
  275. package/libx/_runtime/types/api.js +23 -11
  276. package/libx/common/utils/ucsn.js +15 -9
  277. package/libx/odata/afterburner.js +109 -29
  278. package/libx/odata/cqn2odata.js +48 -9
  279. package/libx/odata/grammar.pegjs +263 -156
  280. package/libx/odata/index.js +21 -9
  281. package/libx/odata/parseToCqn.js +8 -5
  282. package/libx/odata/parser.js +1 -1
  283. package/libx/odata/utils.js +13 -3
  284. package/libx/rest/RestAdapter.js +173 -113
  285. package/libx/rest/RestRequest.js +3 -2
  286. package/libx/rest/middleware/create.js +8 -6
  287. package/libx/rest/middleware/delete.js +6 -13
  288. package/libx/rest/middleware/error.js +1 -1
  289. package/libx/rest/middleware/input.js +6 -6
  290. package/libx/rest/middleware/operation.js +8 -3
  291. package/libx/rest/middleware/parse.js +3 -3
  292. package/libx/rest/middleware/payload.js +12 -0
  293. package/libx/rest/middleware/read.js +12 -2
  294. package/libx/rest/middleware/update.js +3 -3
  295. package/package.json +4 -6
  296. package/server.js +3 -44
  297. package/srv/extensibility-service.cds +56 -0
  298. package/srv/extensibility-service.js +1 -0
  299. package/srv/extensions.cds +8 -0
  300. package/srv/model-provider.cds +59 -0
  301. package/srv/model-provider.js +163 -0
  302. package/srv/mtx.cds +2 -0
  303. package/srv/mtx.js +22 -0
  304. package/srv/outbox.cds +2 -0
  305. package/tasks/enterprise-messaging-deploy.js +19 -12
  306. package/lib/serve/Service-compat.js +0 -36
  307. package/libx/_runtime/audit/generic/personal/constants.js +0 -4
  308. package/libx/_runtime/auth/strategies/dwc.js +0 -45
  309. package/libx/_runtime/cds-services/adapter/odata-v4/utils/dispatcherUtils.js +0 -56
  310. package/libx/_runtime/cds-services/adapter/rest/Rest.js +0 -183
  311. package/libx/_runtime/cds-services/adapter/rest/RestRequest.js +0 -67
  312. package/libx/_runtime/cds-services/adapter/rest/handlers/create.js +0 -82
  313. package/libx/_runtime/cds-services/adapter/rest/handlers/delete.js +0 -39
  314. package/libx/_runtime/cds-services/adapter/rest/handlers/operation.js +0 -63
  315. package/libx/_runtime/cds-services/adapter/rest/handlers/read.js +0 -52
  316. package/libx/_runtime/cds-services/adapter/rest/handlers/update.js +0 -81
  317. package/libx/_runtime/cds-services/adapter/rest/rest-to-cqn/index.js +0 -56
  318. package/libx/_runtime/cds-services/adapter/rest/rest-to-cqn/utils.js +0 -33
  319. package/libx/_runtime/cds-services/adapter/rest/to.js +0 -8
  320. package/libx/_runtime/cds-services/adapter/rest/utils/binary.js +0 -50
  321. package/libx/_runtime/cds-services/adapter/rest/utils/data.js +0 -117
  322. package/libx/_runtime/cds-services/adapter/rest/utils/header-checks.js +0 -14
  323. package/libx/_runtime/cds-services/adapter/rest/utils/key-value-utils.js +0 -30
  324. package/libx/_runtime/cds-services/adapter/rest/utils/parse-url.js +0 -250
  325. package/libx/_runtime/cds-services/adapter/rest/utils/result.js +0 -26
  326. package/libx/_runtime/cds-services/services/utils/handlerUtils.js +0 -200
  327. package/libx/_runtime/common/aspects/utils.js +0 -152
  328. package/libx/_runtime/common/toggles/handler.js +0 -21
  329. package/libx/_runtime/common/utils/extensibilityUtils.js +0 -18
  330. package/libx/_runtime/extensibility/mps/index.js +0 -5
  331. package/libx/_runtime/extensibility/mps/service.js +0 -111
  332. package/libx/_runtime/extensibility/mps/tar.js +0 -42
  333. package/libx/_runtime/extensibility/mps/utils.js +0 -11
  334. package/libx/_runtime/extensibility/uiflex/index.js +0 -54
  335. package/libx/_runtime/extensibility/uiflex/service.js +0 -276
  336. package/libx/_runtime/messaging/common-utils/naming-conventions.js +0 -20
  337. package/libx/_runtime/remote/utils/client-types.d.ts +0 -7
  338. package/libx/gql/GraphQLAdapter.js +0 -33
  339. package/libx/gql/constants/adapter.js +0 -69
  340. package/libx/gql/constants/cds.js +0 -18
  341. package/libx/gql/constants/graphql.js +0 -33
  342. package/libx/gql/readme.md +0 -1
  343. package/libx/gql/resolvers/crud/create.js +0 -20
  344. package/libx/gql/resolvers/crud/delete.js +0 -29
  345. package/libx/gql/resolvers/crud/index.js +0 -6
  346. package/libx/gql/resolvers/crud/read.js +0 -30
  347. package/libx/gql/resolvers/crud/update.js +0 -42
  348. package/libx/gql/resolvers/crud/utils/index.js +0 -36
  349. package/libx/gql/resolvers/field.js +0 -5
  350. package/libx/gql/resolvers/index.js +0 -7
  351. package/libx/gql/resolvers/mutation.js +0 -23
  352. package/libx/gql/resolvers/parse/ast/enrich.js +0 -52
  353. package/libx/gql/resolvers/parse/ast/fragment.js +0 -11
  354. package/libx/gql/resolvers/parse/ast/fromObject.js +0 -39
  355. package/libx/gql/resolvers/parse/ast/index.js +0 -3
  356. package/libx/gql/resolvers/parse/ast/meta.js +0 -4
  357. package/libx/gql/resolvers/parse/ast/variable.js +0 -7
  358. package/libx/gql/resolvers/parse/ast2cqn/columns.js +0 -44
  359. package/libx/gql/resolvers/parse/ast2cqn/entries.js +0 -31
  360. package/libx/gql/resolvers/parse/ast2cqn/index.js +0 -8
  361. package/libx/gql/resolvers/parse/ast2cqn/limit.js +0 -6
  362. package/libx/gql/resolvers/parse/ast2cqn/orderBy.js +0 -24
  363. package/libx/gql/resolvers/parse/ast2cqn/utils/index.js +0 -3
  364. package/libx/gql/resolvers/parse/ast2cqn/where.js +0 -70
  365. package/libx/gql/resolvers/parse/utils/index.js +0 -8
  366. package/libx/gql/resolvers/query.js +0 -13
  367. package/libx/gql/resolvers/root.js +0 -34
  368. package/libx/gql/schema/generate.js +0 -18
  369. package/libx/gql/schema/index.js +0 -5
  370. package/libx/gql/schema/mutation.js +0 -76
  371. package/libx/gql/schema/query.js +0 -108
  372. package/libx/gql/schema/typeDefMap.js +0 -45
  373. package/libx/gql/schema/utils/index.js +0 -54
  374. package/libx/gql/utils/index.js +0 -12
  375. package/libx/rest/middleware/auth.js +0 -20
  376. package/libx/rest/middleware/content.js +0 -19
  377. package/srv/flex.cds +0 -21
  378. package/srv/flex.js +0 -1
  379. package/srv/mps.cds +0 -23
  380. package/srv/mps.js +0 -1
  381. package/srv/outbox.js +0 -0
@@ -1,97 +1,117 @@
1
1
  const cds = require('../../../../cds')
2
- const { SELECT } = cds.ql
3
2
  const { isCustomOperation } = require('./request')
4
- const expandToCQN = require('../odata-to-cqn/expandToCQN')
5
- const QueryOptions = require('../okra/odata-server').QueryOptions
6
- const { COMPLEX_PROPERTY, PRIMITIVE_PROPERTY } = require('../okra/odata-server').uri.UriResource.ResourceKind
7
- const { mergeJson } = require('../../../services/utils/compareJson')
8
- const { getColumns } = require('../../../services/utils/columns')
9
-
10
- const _selectForFunction = (selectColumns, result, opReturnType) => {
11
- if (!Array.isArray(result)) result = [result]
12
-
13
- const keys = opReturnType.keys
14
-
15
- for (const row of result) {
16
- for (const entry in row) {
17
- if (keys[entry] || entry.match(/^\*/)) continue
18
-
19
- if (!selectColumns.includes(entry)) {
20
- delete row[entry]
21
- }
3
+ const {
4
+ uri: {
5
+ UriResource: {
6
+ ResourceKind: { COMPLEX_PROPERTY, PRIMITIVE_PROPERTY }
22
7
  }
23
8
  }
24
- }
9
+ } = require('../okra/odata-server')
10
+ const { DRAFT_COLUMNS_MAP } = require('../../../../common/constants/draft')
11
+ const { SELECT } = cds.ql
25
12
 
26
- const { ensureDraftsSuffix, isDraftActivateAction } = require('../../../../fiori/utils/handler')
13
+ const _keysOf = (row, target) => {
14
+ const keyElements = Object.values(target.keys || {})
15
+ // > singleton
16
+ if (!keyElements.length) return
17
+ const keys = {}
18
+ for (const key of keyElements) {
19
+ if (key._isAssociationStrict) continue
20
+ keys[key.name] = key.elements ? { val: JSON.stringify(row[key.name]) } : row[key.name]
21
+ }
22
+ return keys
23
+ }
27
24
 
28
- const _expand = (model, uriInfo, options) => {
29
- const expand = uriInfo.getQueryOption(QueryOptions.EXPAND)
25
+ const getSimpleSelectCQN = (target, data, columns) => {
26
+ const keys = _keysOf(data, target)
27
+ // don't use `ql.where()` to get `where` in `from` for location header
28
+ const cqn = keys ? SELECT.one(target, keys) : /* singleton */ SELECT.one(target)
30
29
 
31
- if (!expand || expand.length === 0) {
32
- return []
30
+ if (columns) {
31
+ cqn.columns(...columns)
33
32
  }
34
33
 
35
- return expandToCQN(model, expand, uriInfo.getFinalEdmType(), options)
36
- }
34
+ if (target.query && target.query.SELECT && target.query.SELECT.orderBy) {
35
+ cqn.SELECT.orderBy = target.query.SELECT.orderBy
36
+ }
37
37
 
38
- const _compareKeys = (first, second) => key => {
39
- const val1 = first[key]
40
- const val2 = second[key]
41
- if (Array.isArray(val1) || Buffer.isBuffer(val1)) return val1.every((_, i) => _compareKeys(val1, val2)(i))
42
- if (val1 && typeof val1 === 'object') return Object.keys(val1).every(_compareKeys(val1, val2))
43
- return val1 === val2
38
+ return cqn
44
39
  }
45
40
 
46
- const _expandForFunction = async (uriInfo, result, req, srv, opReturnType) => {
47
- const results = Array.isArray(result) ? result : [result]
48
- const isDraft = opReturnType._isDraftEnabled
49
- const isDraftActivate = isDraftActivateAction(req)
50
-
51
- // REVISIT: what happens here exactly?
52
- const selectQuery = SELECT.from(
53
- isDraft && !isDraftActivate ? ensureDraftsSuffix(opReturnType.name) : opReturnType.name
54
- )
55
- const keys = getColumns(opReturnType, {
56
- onlyNames: true,
57
- removeIgnore: true,
58
- filterDraft: !isDraft || isDraftActivate,
59
- filterVirtual: true,
60
- keysOnly: true
61
- })
62
- const expandCqn = _expand(srv.model, uriInfo, { rewriteAsterisks: true })
63
- selectQuery.columns(expandCqn)
64
- selectQuery.columns(keys)
65
- for (const row of results) {
66
- const where = ['(']
67
- for (const key of keys) {
68
- where.push({ ref: [key] }, '=', { val: row[key] }, 'and')
41
+ /*
42
+ * merge CQNs
43
+ */
44
+ const _mergeExpandCQNs = cqns => {
45
+ const cols = cqns[0].SELECT.columns
46
+ for (const cqn of cqns.slice(1)) {
47
+ for (const col of cqn.SELECT.columns) {
48
+ if (!col.expand) continue
49
+ const idx = cols.findIndex(ele => {
50
+ if (!col.ref) return
51
+ if (ele.ref) return ele.ref[0] === col.ref[0]
52
+ if (ele.as) return ele.as === col.ref[0]
53
+ })
54
+ if (idx === -1) {
55
+ cols.push(col)
56
+ } else {
57
+ const colExists = cols[idx]
58
+ if (colExists.as && colExists.val === null) {
59
+ cols[idx] = col
60
+ continue
61
+ }
62
+ if (col.as && col.val === null) continue
63
+ const mergedExpandCQN = _mergeExpandCQNs([
64
+ { SELECT: { columns: colExists.expand } },
65
+ { SELECT: { columns: col.expand } }
66
+ ])
67
+ colExists.expand = mergedExpandCQN.SELECT.columns
68
+ }
69
69
  }
70
- where.pop() // last 'and'
71
- where.push(')')
72
- if (!selectQuery.SELECT.where) selectQuery.where(where)
73
- else selectQuery.or(where)
74
70
  }
75
- const expandedResults = await cds.tx(req).run(selectQuery)
71
+ return cqns[0]
72
+ }
76
73
 
77
- for (let i = 0; i < results.length; i++) {
78
- const result = results[i]
79
- const res = expandedResults.find(r => keys.every(_compareKeys(result, r)))
80
- if (res) results[i] = mergeJson(res, result, opReturnType)
74
+ const _getExpandColumn = (data, element) => {
75
+ const key = element.name
76
+ if (!(key in data)) return
77
+ data = data[key]
78
+ if ((Array.isArray(data) && data.length === 0) || data == null) {
79
+ // performance tweak, keep in mind it is only for compositions
80
+ return { val: null, as: key }
81
81
  }
82
- return Array.isArray(result) ? results : results[0]
82
+ const cqn = Array.isArray(data)
83
+ ? _mergeExpandCQNs(data.map(data => getDeepSelect({ target: element._target, data })))
84
+ : getDeepSelect({ target: element._target, data })
85
+ return { ref: [key], expand: cqn.SELECT.columns }
83
86
  }
84
87
 
85
- const _cleanupResult = (result, opReturnType) => {
86
- if (!Array.isArray(result)) result = [result]
87
-
88
- for (const row of result) {
89
- for (const element in opReturnType.elements) {
90
- if (opReturnType.elements[element].is2many) {
91
- delete row[element]
92
- }
88
+ const _getColumns = (target, data, prefix = []) => {
89
+ const columns = []
90
+ for (const each in target.elements) {
91
+ if (each in DRAFT_COLUMNS_MAP) continue
92
+ const element = target.elements[each]
93
+ if (element.elements && data[each]) {
94
+ prefix.push(element.name)
95
+ columns.push(..._getColumns(element, data[each], prefix))
96
+ prefix.pop()
97
+ } else if (element.isComposition && !prefix.length) {
98
+ const col = _getExpandColumn(data, element, prefix)
99
+ if (col) columns.push(col)
100
+ } else if (!element.isAssociation) {
101
+ columns.push({ ref: [...prefix, each] })
93
102
  }
94
103
  }
104
+ return columns
105
+ }
106
+
107
+ /*
108
+ * recursively builds a select cqn for deep read after write
109
+ * (depth determined by req.data)
110
+ */
111
+ const getDeepSelect = req => {
112
+ let { target, data } = req
113
+ const columns = _getColumns(target, data)
114
+ return getSimpleSelectCQN(target, data, columns)
95
115
  }
96
116
 
97
117
  const getActionOrFunctionReturnType = (pathSegments, definitions) => {
@@ -108,21 +128,6 @@ const getActionOrFunctionReturnType = (pathSegments, definitions) => {
108
128
  }
109
129
  }
110
130
 
111
- const actionAndFunctionQueries = async (req, odataReq, result, srv, opReturnType) => {
112
- _cleanupResult(result, opReturnType)
113
-
114
- // REVISIT consider $expand columns as inline content for $select
115
- if (odataReq.getQueryOptions().$select) {
116
- _selectForFunction(odataReq.getQueryOptions().$select.split(','), result, opReturnType)
117
- }
118
-
119
- // REVISIT: we need to read directly from db for this, which might not be there!
120
- if (odataReq.getQueryOptions().$expand && cds.db) {
121
- result = await _expandForFunction(odataReq.getUriInfo(), result, req, srv, opReturnType)
122
- }
123
- return result
124
- }
125
-
126
131
  const resolveStructuredName = (pathSegments, index, nameArr = []) => {
127
132
  if (pathSegments[index].getKind() === COMPLEX_PROPERTY) {
128
133
  const prop = pathSegments[index].getProperty()
@@ -147,9 +152,9 @@ const isReturnMinimal = req => {
147
152
  }
148
153
 
149
154
  module.exports = {
150
- _expand,
151
155
  resolveStructuredName,
152
- actionAndFunctionQueries,
153
156
  getActionOrFunctionReturnType,
154
- isReturnMinimal
157
+ isReturnMinimal,
158
+ getDeepSelect,
159
+ getSimpleSelectCQN
155
160
  }
@@ -0,0 +1,382 @@
1
+ const cds = require('../../../../cds')
2
+ const LOG = cds.log('odata')
3
+ const { appURL } = require('../../../../common/utils/vcap')
4
+ const { resolveFromSelect, targetFromPath } = require('../../../../common/utils/cqn')
5
+ const { setEntityContained } = require('../../../../common/utils/csn')
6
+ const { getNavigationIfStruct } = require('../../../../common/utils/structured')
7
+ const getTemplate = require('../../../../common/utils/template')
8
+ const templateProcessor = require('../../../../common/utils/templateProcessor')
9
+
10
+ const _ignoreColumns = (columns, options) => {
11
+ if (!(Array.isArray(columns) && columns.some(c => c === '*' || c.as || c.ref))) return true
12
+ // REVISIT expand=* => list all expanded properties (as by okra's implementation)
13
+ // OData spec is clarified (https://github.tools.sap/cap/cds/pull/1183#pullrequestreview-1775872)
14
+ if (options && !options.$select && options.$expand === '*') return true
15
+ }
16
+
17
+ const _getNestedQueryOptions = (ref, expand, expandString) => {
18
+ const isNested = expandString.match(new RegExp(`${ref}(?=\\()`))
19
+ // if no "ref(" i.e. "ref" without open bracket => no nested options => shift and return
20
+ if (!(isNested && Array.isArray(expand) && expand.length)) return { _expand: expandString.replace(ref, '') }
21
+ // if "ref(" found, shift to the first position after "("
22
+ expandString = expandString.slice(isNested.index + ref.length + 1)
23
+ // i.e. we found 1 open bracket already
24
+ let openBrackets = 1
25
+ let head = ''
26
+ // if expandString is '$top=10;$expand=foo($select=*),bar($select=buz));$select=a,b)',
27
+ // then outterQueryOptions is '$top=10;$expand=foo,bar;$select=a,b'
28
+ let outterQueryOptions = ''
29
+ let nestedExpand = ''
30
+
31
+ // parse until the last even closing bracket
32
+ while (openBrackets) {
33
+ const bracketFound = expandString.match(/\(|\)/)
34
+ head = expandString.substring(0, bracketFound.index)
35
+ expandString = expandString.slice(bracketFound.index + 1)
36
+ nestedExpand = `${nestedExpand}${head}${bracketFound[0]}`
37
+ // every time we have only 1 opened bracket and find another one,
38
+ // everything to the left is related to outter query options
39
+ if (openBrackets === 1 && bracketFound[0] === '(') {
40
+ outterQueryOptions = `${outterQueryOptions}${head}`
41
+ }
42
+ openBrackets = bracketFound[0] === '(' ? openBrackets + 1 : openBrackets - 1
43
+ }
44
+ outterQueryOptions = `${outterQueryOptions}${head}`
45
+
46
+ // outterQueryOptions also contain $expand, but without nested options i.e. can safely be split by ";"
47
+ const $select = outterQueryOptions.split(';').find(s => s.startsWith('$select'))
48
+
49
+ const expandIndex = nestedExpand.indexOf('$expand=')
50
+ // last symbol is a pair to open bracket in "ref(" => slice(..., -1)
51
+ const $expand = expandIndex === -1 ? '' : nestedExpand.slice(expandIndex + '$expand='.length, -1)
52
+
53
+ return {
54
+ $select: $select && $select.replace('$select=', ''),
55
+ $expand,
56
+ _expand: expandString
57
+ }
58
+ }
59
+
60
+ const _columnsFromQuery = (columns, target, options) => {
61
+ // must use query.columns as it includes columns from $apply except of $apply=expand()
62
+ // must use query options to get nested $selects inside $expand() as they are mixed into query columns
63
+ // example: GET /Foo?$select=bar&$expand=bar => @odata.context: $metadata#Foo(bar,bar())
64
+ // REVISIT tbd if having expand column in $select could be integrated into query in grammar.pegjs
65
+ // REVISIT support $apply=expand()
66
+ if (_ignoreColumns(columns, options)) return ''
67
+ const context = []
68
+ const _select = options.$select ? options.$select.split(',') : []
69
+ let _expand = options.$expand || ''
70
+
71
+ const hasAsterisk = _select.indexOf('*') > -1
72
+ if (hasAsterisk) context.push('*')
73
+
74
+ for (const c of columns) {
75
+ if (!c) continue
76
+ const ref = c.ref && c.ref.join('/')
77
+ if (!hasAsterisk && !c.expand) {
78
+ if (c.as) context.push(c.as)
79
+ else if (ref) context.push(ref)
80
+ } else if (c.expand) {
81
+ if (!hasAsterisk && _select.indexOf(ref) > -1) context.push(ref)
82
+
83
+ const nextTarget = getNavigationIfStruct(target, c.ref)
84
+ if (nextTarget && nextTarget._target && nextTarget._target.elements) {
85
+ const nestedOptions = _getNestedQueryOptions(ref, c.expand, _expand)
86
+ _expand = nestedOptions._expand
87
+ context.push(`${ref}(${_columnsFromQuery(c.expand, nextTarget._target, nestedOptions)})`)
88
+ }
89
+ }
90
+ }
91
+ if (context.length) return context.join(',')
92
+ else if (hasAsterisk) return '*'
93
+ return ''
94
+ }
95
+
96
+ const _processFn = columns => {
97
+ return ({ row, key, element, pathSegments }) => {
98
+ if (!(key in row) || row[key] === null) return
99
+ let cur = columns
100
+ if (element.parent._isStructured) {
101
+ const prefix = pathSegments.join('/')
102
+ key = `${prefix}/${key}`
103
+ } else {
104
+ for (let p of pathSegments) {
105
+ if (!cur[p]) cur[p] = {}
106
+ cur = cur[p]
107
+ }
108
+ }
109
+ if (!cur[key]) cur[key] = {}
110
+ }
111
+ }
112
+
113
+ const _columnsFromData = (data, definition, service) => {
114
+ const columns = {}
115
+ const template = getTemplate('odata-context', service, definition, { pick: element => element.isAssociation })
116
+ if (!template || !template.elements.size) return ''
117
+ const arrayData = Array.isArray(data) ? data : data ? [data] : []
118
+ for (const row of arrayData) {
119
+ templateProcessor({ processFn: _processFn(columns), row, template, pathOptions: { pathSegments: [] } })
120
+ }
121
+ return _stringifyColumnsFromData(columns)
122
+ }
123
+
124
+ const _stringifyColumnsFromData = columns =>
125
+ Object.keys(columns)
126
+ .map(key => `${key}(${_stringifyColumnsFromData(columns[key])})`)
127
+ .join(',')
128
+
129
+ const _listColumns = ({ columns, data, isUpsert, returnType, event, /* express */ _req, service }) => {
130
+ // query options ($select, $expand, etc) as strings
131
+ const queryOptions = _req.query
132
+ let columnsStr
133
+ if (!isUpsert && event in { CREATE: 1 }) {
134
+ columnsStr = _columnsFromData(data, returnType, service)
135
+ } else {
136
+ columnsStr = _columnsFromQuery(columns, returnType, queryOptions)
137
+ }
138
+ return columnsStr && `(${columnsStr})`
139
+ }
140
+
141
+ const _getContextUrlPrefix = ({ _req, path, target }) => {
142
+ if (cds.env.odata.contextAbsoluteUrl) {
143
+ try {
144
+ if (typeof cds.env.odata.contextAbsoluteUrl === 'string') {
145
+ const userDefinedURL = new URL(cds.env.odata.contextAbsoluteUrl, cds.env.odata.contextAbsoluteUrl).toString()
146
+ return (!userDefinedURL.endsWith('/') && `${userDefinedURL}/`) || userDefinedURL
147
+ }
148
+ } catch (e) {
149
+ e.message = `cds.odata.contextAbsoluteUrl could not be parsed as URL: ${cds.env.odata.contextAbsoluteUrl}`
150
+ LOG._warn && LOG.warn(e)
151
+ }
152
+ const reqURL = _req && _req.get && _req.get('host') && `${_req.protocol || 'https'}://${_req.get('host')}`
153
+ const baseAppURL = appURL || reqURL || ''
154
+ const serviceUrl = `${(_req && _req.baseUrl) || ''}/`
155
+ return baseAppURL && new URL(serviceUrl, baseAppURL).toString()
156
+ }
157
+ return target && target.params ? '../'.repeat(path.length) : '../'.repeat(path.length - 1)
158
+ }
159
+
160
+ const _findEdmNameFor = (definition, namespace, fullyQualified = false) => {
161
+ let name
162
+ if (!definition) return ''
163
+ if (definition._isStructured) {
164
+ const structured = [definition.name]
165
+ while (definition.parent) {
166
+ definition = definition.parent
167
+ structured.unshift(definition.name)
168
+ }
169
+ name = structured.join('_')
170
+ } else {
171
+ name = definition.name
172
+ }
173
+ if (!name.startsWith(`${namespace}.`)) return name
174
+ return fullyQualified ? name : name.replace(new RegExp(`^${namespace}\\.`), '')
175
+ }
176
+
177
+ const _opResultName = ({ service, returnType, operation, isServiceEntity }) => {
178
+ const { namespace } = service
179
+ if (returnType.name) {
180
+ const resultName = _findEdmNameFor(returnType, namespace)
181
+ if (returnType.name.startsWith(`${namespace}.`)) {
182
+ if (isServiceEntity) return resultName.replace(/\./g, '_')
183
+ return `${namespace}.${resultName.replace(/\./g, '_')}`
184
+ }
185
+ return resultName
186
+ }
187
+ // bound action / function returns inline structure
188
+ if (operation.parent) {
189
+ const boundEntityName = _findEdmNameFor(operation.parent, namespace, true).replace(/\./g, '_')
190
+ // REVISIT exactly this return type name is generated in edm by compiler
191
+ return `${namespace}.return_${boundEntityName}_${_findEdmNameFor(operation, namespace)}`
192
+ }
193
+ // unbound action / function returns inline structure
194
+ // REVISIT exactly this return type name is generated in edm by compiler
195
+ return `${namespace}.return_${_findEdmNameFor(operation, namespace, true).replace(/\./g, '_')}`
196
+ }
197
+
198
+ const _isNavToDraftAdmin = path => path.length > 1 && path[path.length - 1] === 'DraftAdministrativeData'
199
+
200
+ const _getCanonicalUrl = (path, target, model) => {
201
+ const toManySegment =
202
+ path.length > 1 && Array.isArray(path[path.length - 1].where) && path[path.length - 1].where.length && path.pop()
203
+ if (target.params) path.push('Set')
204
+ const odataUrl = cds.odata.urlify({ SELECT: { from: { ref: path } } }, { model, kind: 'odata' })
205
+ let contextPath = odataUrl.path && odataUrl.path.match(/^([^?]*)\??/)[1]
206
+ if (toManySegment) {
207
+ contextPath += `/${toManySegment.id}`
208
+ path.push(toManySegment)
209
+ }
210
+ return contextPath
211
+ }
212
+
213
+ const _getReturnTypeUrl = options => {
214
+ const {
215
+ service,
216
+ isCollection,
217
+ returnType,
218
+ operation,
219
+ path,
220
+ target,
221
+ propertyName,
222
+ isServiceEntity,
223
+ isTargetComposition
224
+ } = options
225
+ const { namespace } = service
226
+ if (operation) {
227
+ const resultName = _opResultName(options)
228
+ if (isServiceEntity) return resultName
229
+ return isCollection ? `Collection(${resultName})` : resultName
230
+ }
231
+ if (isTargetComposition || propertyName || target.params || _isNavToDraftAdmin(path)) {
232
+ return _getCanonicalUrl(path, target, service.model)
233
+ }
234
+ if (isServiceEntity) return _findEdmNameFor(returnType, namespace).replace(/\./g, '_')
235
+ return isCollection ? `Collection(${returnType.name})` : returnType.name
236
+ }
237
+
238
+ const _isSingleEntity = options => {
239
+ const { isCollection, propertyName, returnType, isServiceEntity, isTargetComposition } = options
240
+ if (isCollection || (returnType && returnType._isSingleton) || propertyName) return false
241
+ return isServiceEntity || isTargetComposition
242
+ }
243
+
244
+ const _getContextUrl = options => {
245
+ if (!options.returnType) return ''
246
+ const contextUrlPrefix = _getContextUrlPrefix(options)
247
+ const returnTypeUrl = _getReturnTypeUrl(options)
248
+ const columnsStringified = _listColumns(options)
249
+ const $entity = _isSingleEntity(options) ? '/$entity' : ''
250
+ return `${contextUrlPrefix}$metadata#${returnTypeUrl}${columnsStringified}${$entity}`
251
+ }
252
+
253
+ const _getAdditionalContextUrl = (query, service, data, eventType, _req, isUpsert) => {
254
+ if (Array.isArray(query)) {
255
+ const additionalContextUrls = []
256
+ for (let i = 1; i < query.length; i++) {
257
+ additionalContextUrls.push(
258
+ _getContextUrl(
259
+ Object.assign(_getQueryInfo(query[i], service, data, eventType), { _req, service, data, isUpsert })
260
+ )
261
+ )
262
+ }
263
+ return additionalContextUrls
264
+ }
265
+ return []
266
+ }
267
+
268
+ const _partialCopyColumn = c => {
269
+ if (c.expand) {
270
+ const copy = { expand: Array.isArray(c.expand) ? c.expand.map(_partialCopyColumn) : c.expand }
271
+ if (c.ref) copy.ref = [...c.ref]
272
+ return copy
273
+ }
274
+ if (c.ref) return { ref: [...c.ref] }
275
+ if (c.as) return { as: c.as }
276
+ return c
277
+ }
278
+
279
+ const _partialCopyColumns = query => {
280
+ if (query.SELECT) {
281
+ // stop digging into subSelects as soon as columns found, as deeper columns will be shadowed by these
282
+ if (!query.SELECT.columns && query.SELECT.from.SELECT) return _partialCopyColumns(query.SELECT.from)
283
+ if (query.SELECT.columns) return query.SELECT.columns.map(_partialCopyColumn)
284
+ }
285
+ return []
286
+ }
287
+
288
+ const _getPathInfo = (query, model) => {
289
+ const queryFrom =
290
+ (query.SELECT && resolveFromSelect(query)) ||
291
+ (query.INSERT && query.INSERT.into) ||
292
+ (query.UPDATE && query.UPDATE.entity) ||
293
+ (query.DELETE && query.DELETE.from)
294
+ const { last, target, path, isTargetComposition } = targetFromPath(queryFrom, model)
295
+ const operation = (last.kind === 'action' || last.kind === 'function') && last
296
+ let returnType, isCollection, propertyName, unbound
297
+ if (operation) {
298
+ // last segment is bound action/function => must not be in ref
299
+ queryFrom && queryFrom.ref && queryFrom.ref.pop()
300
+ unbound = !operation.parent
301
+ if (operation.returns) {
302
+ returnType = setEntityContained(operation.returns.items || operation.returns, model)
303
+ isCollection = !!operation.returns.items
304
+ }
305
+ // no propertyName as operations do not (yet?) support navigation
306
+ } else {
307
+ returnType = target
308
+ isCollection = Array.isArray(query) || (query.SELECT && !query.SELECT.one)
309
+ propertyName = !isCollection && last.kind !== 'entity' && last.name
310
+ }
311
+ const isStream = last['@Core.MediaType']
312
+ return {
313
+ path,
314
+ target,
315
+ last,
316
+ operation,
317
+ returnType,
318
+ isCollection,
319
+ propertyName,
320
+ isStream,
321
+ unbound,
322
+ isTargetComposition
323
+ }
324
+ }
325
+
326
+ const _getEvent = (eventType, namespace, data, { last, target }) => {
327
+ if (last && (last.kind === 'action' || last.kind === 'function')) {
328
+ // BOUND
329
+ if (last.parent) eventType = last.name
330
+ // UNBOUND
331
+ eventType = last.name.replace(`${namespace}.`, '')
332
+ }
333
+ // draft
334
+ if (target && target._isDraftEnabled) {
335
+ if (eventType === 'CREATE') return 'NEW'
336
+ else if (eventType === 'draftEdit') return 'EDIT'
337
+ else if (eventType === 'UPDATE') return 'PATCH'
338
+ else if (eventType === 'DELETE' && data.IsActiveEntity !== true) return 'CANCEL'
339
+ }
340
+ return eventType
341
+ }
342
+
343
+ const _getQueryInfo = (query, service, data, eventType) => {
344
+ const { namespace, model } = service
345
+ const _pathInfo = _getPathInfo(Array.isArray(query) ? query[0] : query, model)
346
+ const { returnType } = _pathInfo
347
+
348
+ // store original columns before they are polluted by drafts, db and so on
349
+ const columns = _partialCopyColumns(Array.isArray(query) ? query[0] : query)
350
+ const isServiceEntity =
351
+ _findEdmNameFor(returnType, namespace) in model.entities(namespace) && !returnType._isContained
352
+ const event = _getEvent(eventType, namespace, data, _pathInfo)
353
+ return Object.assign(_pathInfo, {
354
+ columns,
355
+ isServiceEntity,
356
+ event
357
+ })
358
+ }
359
+
360
+ module.exports = (query, eventType, service, data, /* express req */ _req, isUpsert) => {
361
+ const queryInfo = _getQueryInfo(query, service, data, eventType)
362
+
363
+ const { isCollection, isStream, propertyName, unbound, event, returnType, isServiceEntity } = queryInfo
364
+
365
+ const contextUrl = _getContextUrl(Object.assign(queryInfo, { _req, service, data, isUpsert }))
366
+
367
+ const additionalContextUrl = _getAdditionalContextUrl(query, service, data, eventType, _req, isUpsert)
368
+
369
+ return {
370
+ event,
371
+ unbound,
372
+ metadata: {
373
+ isCollection,
374
+ isStream,
375
+ propertyName,
376
+ contextUrl,
377
+ returnType,
378
+ isServiceEntity,
379
+ additionalContextUrl
380
+ }
381
+ }
382
+ }
@@ -21,10 +21,7 @@ const _getEntitySets = (edm, namespace) => {
21
21
  const _getConcurrent = (namespace, element, csn) => {
22
22
  // autoexposed entities now used . in csn and _ in edm
23
23
  const e = findCsnTargetFor(element, csn, namespace)
24
-
25
- return Object.values(e.elements).some(val => {
26
- return val['@odata.etag']
27
- })
24
+ return !!e._etag
28
25
  }
29
26
 
30
27
  const oDataConfiguration = (edm, csn) => {
@@ -40,27 +40,26 @@ const applyOmitValuesPreference = (response, omitValuesPreference) => {
40
40
  *
41
41
  * **REVISIT**: The handling of delta payloads and instance annotations is not currently
42
42
  * implemented, as the runtime does not yet support those features.
43
- * In the future, you might want to use the `processArgs.pathSegments` argument for the
43
+ * In the future, you might want to use the `elementInfo.pathSegments` argument for the
44
44
  * implementation of delta payloads.
45
45
  *
46
- * @param {import('../../../../types/api').templateProcessorProcessFnArgs} processArgs
46
+ * @param {import('../../../../types/api').templateElementInfo} elementInfo
47
47
  * @param {import('../../../../cds-services/adapter/odata-v4/ODataRequest')} request
48
48
  * @param {Map<string, boolean> | null} omitValuesPreference
49
49
  * @param {object | undefined} previousRow
50
50
  */
51
- const omitValue = (processArgs, request, omitValuesPreference, previousRow) => {
51
+ const omitValue = (elementInfo, request, omitValuesPreference, previousRow) => {
52
52
  const preferHeader = request.headers.prefer
53
53
  if (!preferHeader || !omitValuesPreference) return
54
54
 
55
- const { row, key, element, isRoot } = processArgs
55
+ const { row, key, element } = elementInfo
56
56
  const defaultValue = element.default && element.default.val ? element.default.val : null
57
57
  const responseValue = row[key]
58
58
  const isDefaultValue = responseValue === defaultValue
59
59
 
60
60
  if (isDefaultValue) {
61
61
  // Don't omit the response value if the request is an update operation and it has changed it
62
- // REVISIT: We don't have access to deep previous rows, therefore we always ignore default values in deep operations
63
- if (request.event === 'UPDATE' && isRoot) {
62
+ if (request.event === 'UPDATE') {
64
63
  if (previousRow === undefined) return
65
64
  if (responseValue !== previousRow[key]) return
66
65
  }