@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
@@ -7,48 +7,21 @@ const {
7
7
  } = require('../okra/odata-server')
8
8
 
9
9
  const { getSapMessages } = require('../../../../common/error/frontend')
10
- const { actionAndFunctionQueries, getActionOrFunctionReturnType } = require('../utils/handlerUtils')
10
+ const { getActionOrFunctionReturnType, isReturnMinimal } = require('../utils/handlerUtils')
11
11
  const { validateResourcePath } = require('../utils/request')
12
- const readAfterWrite = require('../utils/readAfterWrite')
13
- const { setStatusCodeAndHeader, getKeyProperty } = require('../../../../fiori/utils/handler')
14
12
  const { toODataResult, postProcess } = require('../utils/result')
15
- const { mergeJson } = require('../../../services/utils/compareJson')
16
-
17
- const _isAssocOrCompNotLocalized = (reqTarget, el) => {
18
- return (
19
- reqTarget.elements[el].isAssociation && (!reqTarget.texts || reqTarget.elements[el].target !== reqTarget.texts.name)
20
- )
21
- }
22
-
23
- const _postProcessDraftActivate = async (req, result, service) => {
24
- // update req.data (keys needed in readAfterWrite)
25
- req.data = result
26
- const dataInDb = await readAfterWrite(req, service)
27
- if (dataInDb.length) result = mergeJson(dataInDb[0], result, req.target)
28
-
29
- // add static draft columns
30
- result.IsActiveEntity = true
31
- result.HasActiveEntity = false
32
- result.HasDraftEntity = false
33
-
34
- // remove children from result, excluding localized composition 'text'
35
- if (!(cds.env.effective.odata.structs || cds.env.features.ucsn_struct_conversion)) {
36
- for (const k in req.target.elements) {
37
- if (_isAssocOrCompNotLocalized(req.target, k)) delete result[k]
38
- }
39
- }
40
-
41
- return result
42
- }
13
+ const { DRAFT_EVENTS } = require('../../../../common/constants/events')
14
+ const { readAfterWrite } = require('../utils/readAfterWrite')
43
15
 
44
16
  const _postProcess = async (req, odataReq, odataRes, tx, result) => {
45
- postProcess(req, odataRes, tx, result)
46
-
47
- // REVISIT: harmonize getactionreturntype functions
48
- const actionReturnType = getActionOrFunctionReturnType(odataReq.getUriInfo().getPathSegments(), tx.model.definitions)
49
- if (actionReturnType && actionReturnType.kind === 'entity' && odataReq.getQueryOptions()) {
50
- result = await actionAndFunctionQueries(req, odataReq, result, tx, actionReturnType)
17
+ const returnType = getActionOrFunctionReturnType(odataReq.getUriInfo().getPathSegments(), tx.model.definitions)
18
+ // as of spec meeting: no generic support of $select/$expand for custom actions/functions
19
+ if (returnType && returnType.kind === 'entity' && (req.event in DRAFT_EVENTS || req.event === 'EDIT')) {
20
+ result = await readAfterWrite(req, tx, { operation: { result, returnType } })
21
+ if (result && !('IsActiveEntity' in result)) result.IsActiveEntity = req.event === 'draftActivate'
51
22
  }
23
+ const _req = Object.setPrototypeOf({ target: returnType || req.target }, req)
24
+ postProcess(_req, odataRes, tx, result)
52
25
  return result
53
26
  }
54
27
 
@@ -78,14 +51,6 @@ const action = service => {
78
51
  try {
79
52
  result = await tx.dispatch(req)
80
53
 
81
- // post processing for draftActivate
82
- if (req.event === 'draftActivate') {
83
- result = await _postProcessDraftActivate(req, result, service)
84
-
85
- const k = getKeyProperty(req.target.keys)
86
- setStatusCodeAndHeader(odataRes, { [k]: result[k] }, req.target.name.replace(`${service.name}.`, ''), true)
87
- }
88
-
89
54
  result = await _postProcess(req, odataReq, odataRes, tx, result)
90
55
 
91
56
  if (changeset) {
@@ -94,6 +59,21 @@ const action = service => {
94
59
  } else {
95
60
  await tx.commit(result)
96
61
  }
62
+
63
+ if (isReturnMinimal(req) || result === null) odataRes.setStatusCode(204)
64
+ else if (req.event === 'draftActivate' || req.event === 'EDIT') {
65
+ odataRes.setStatusCode(201)
66
+ const keys = Object.keys(req.target.keys).filter(k => {
67
+ return k !== 'IsActiveEntity' && !req.target.keys[k]._isAssociationStrict
68
+ })
69
+ const keysString = keys.map(key => `${key}=${result[key]}`).join(',')
70
+ odataRes.setHeader(
71
+ 'location',
72
+ `../${req.target.name.replace(`${service.name}.`, '')}(${keysString},IsActiveEntity=${
73
+ req.event === 'draftActivate'
74
+ })`
75
+ )
76
+ }
97
77
  } catch (e) {
98
78
  err = e
99
79
 
@@ -7,11 +7,9 @@ const {
7
7
 
8
8
  const { validateResourcePath } = require('../utils/request')
9
9
  const { isReturnMinimal } = require('../utils/handlerUtils')
10
- const readAfterWrite = require('../utils/readAfterWrite')
10
+ const { readAfterWrite } = require('../utils/readAfterWrite')
11
11
  const { toODataResult, postProcess, postProcessMinimal } = require('../utils/result')
12
12
 
13
- const { mergeJson } = require('../../../services/utils/compareJson')
14
-
15
13
  const { getSapMessages } = require('../../../../common/error/frontend')
16
14
 
17
15
  /**
@@ -40,17 +38,15 @@ const create = service => {
40
38
  try {
41
39
  result = await tx.dispatch(req)
42
40
 
43
- // REVISIT readAfterWrite -> commit -> postProcessing
44
-
41
+ // REVISIT:
42
+ // Performance: For `isReturnMinimal` it's enough to just read the etag.
43
+ // Note: Without read access, one cannot return the etag.
44
+ if (req._.readAfterWrite) {
45
+ result = await readAfterWrite(req, service, { operation: { result } })
46
+ }
45
47
  if (isReturnMinimal(req)) {
46
- postProcessMinimal(req, result)
48
+ result = postProcessMinimal(req, service, result)
47
49
  } else {
48
- // REVISIT: find better solution
49
- if (req._.readAfterWrite) {
50
- const dataInDb = await readAfterWrite(req, service)
51
- if (dataInDb.length) result = mergeJson(dataInDb[0], result, req.target)
52
- }
53
-
54
50
  postProcess(req, odataRes, service, result)
55
51
  }
56
52
 
@@ -61,7 +57,7 @@ const create = service => {
61
57
  await tx.commit(result)
62
58
  }
63
59
 
64
- if (isReturnMinimal(req)) {
60
+ if (isReturnMinimal(req) || result === null) {
65
61
  odataRes.setStatusCode(204)
66
62
  }
67
63
  } catch (e) {
@@ -78,7 +74,7 @@ const create = service => {
78
74
  req.messages && odataRes.setHeader('sap-messages', getSapMessages(req.messages, req._.req))
79
75
 
80
76
  if (err) next(err)
81
- else next(null, toODataResult(result))
77
+ else next(null, toODataResult(result, req))
82
78
  }
83
79
  }
84
80
  }
@@ -12,14 +12,12 @@ const ERROR_TO_HTTP_CODE = {
12
12
  MethodNotAllowedError: HttpStatusCodes.METHOD_NOT_ALLOWED,
13
13
  NotAcceptableError: HttpStatusCodes.NOT_ACCEPTABLE,
14
14
  NotAuthorizedError: HttpStatusCodes.UNAUTHORIZED,
15
- InternalServerError: HttpStatusCodes.INTERNAL_SERVER_ERROR,
16
15
  PreconditionFailedError: HttpStatusCodes.PRECONDITION_FAILED,
17
16
  PreconditionRequiredError: HttpStatusCodes.PRECONDITION_REQUIRED,
18
17
  ConflictError: HttpStatusCodes.CONFLICT,
19
18
  NotFoundError: HttpStatusCodes.NOT_FOUND,
20
19
  BadRequestError: HttpStatusCodes.BAD_REQUEST,
21
20
  // custom
22
- SerializationError: HttpStatusCodes.INTERNAL_SERVER_ERROR,
23
21
  DeserializationError: HttpStatusCodes.BAD_REQUEST
24
22
  }
25
23
 
@@ -40,9 +38,9 @@ const _buildRootCauseMessage = (message, rootCause) => {
40
38
  }
41
39
 
42
40
  const _betterOkraError = err => {
43
- const statusCode = ERROR_TO_HTTP_CODE[err.name] || 500
44
- if (!('code' in err)) err.code = String(statusCode)
45
- if (!err.statusCode) err.statusCode = statusCode
41
+ const statusCode = ERROR_TO_HTTP_CODE[err.name]
42
+ if (statusCode && !('code' in err)) err.code = String(statusCode)
43
+ if (statusCode && !err.statusCode) err.statusCode = statusCode
46
44
 
47
45
  err.message = _buildRootCauseMessage(err.message, err.getRootCause())
48
46
 
@@ -68,6 +66,10 @@ const _betterOkraError = err => {
68
66
  'An error occurred during serialization of the entity collection. An error occurred during serialization of',
69
67
  'Serialization Error for'
70
68
  )
69
+ } else if (err.name === 'PreconditionFailedError') {
70
+ // REVISIT use cds.error here once it is official API?
71
+ const { error } = normalizeError(new cds.Request().error(412, '412'), { headers: {}, query: {} })
72
+ return error
71
73
  }
72
74
 
73
75
  return err
@@ -129,6 +131,8 @@ const getErrorHandler = (crashOnError = true, srv) => {
129
131
  if (contentId && !contentId.match(/^~/)) err['@Core.ContentID'] = contentId
130
132
 
131
133
  const { error, statusCode } = normalizeError(err, req)
134
+ // REVISIT: We should also pass stack traces in development
135
+ // if (!cds.env.production) error.stack = err.stack
132
136
 
133
137
  next(null, Object.assign(error, { statusCode }))
134
138
  }
@@ -3,6 +3,7 @@ const LOG = cds.log('odata')
3
3
 
4
4
  const { toODataResult } = require('../utils/result')
5
5
  const { normalizeError } = require('../../../../common/error/frontend')
6
+ const getError = require('../../../../common/error')
6
7
 
7
8
  const _getMetadata4Tenant = async (tenant, locale, service) => {
8
9
  return await cds.mtx.getEdmx(tenant, service.name, locale)
@@ -24,7 +25,7 @@ const metadata = service => {
24
25
  try {
25
26
  let edmx
26
27
 
27
- if (cds._mtxEnabled && service._isExtended) {
28
+ if (cds.mtx && service._isExtended) {
28
29
  edmx = await _getMetadata4Tenant(tenant, locale, service)
29
30
  }
30
31
 
@@ -44,7 +45,8 @@ const metadata = service => {
44
45
  LOG.error(e)
45
46
  }
46
47
  // return 503 to client
47
- const { error, statusCode } = normalizeError(Object.assign(e, { statusCode: 503 }), req)
48
+ const err = getError(Object.assign(e, { statusCode: 503 }))
49
+ const { error, statusCode } = normalizeError(err, req)
48
50
  return next(Object.assign(error, { statusCode }))
49
51
  }
50
52
  }
@@ -1,7 +1,5 @@
1
1
  const cds = require('../../../../cds')
2
2
 
3
- const { SELECT } = cds.ql
4
-
5
3
  const ODataRequest = require('../ODataRequest')
6
4
 
7
5
  const {
@@ -16,14 +14,14 @@ const {
16
14
  const FUNCTION = { [BOUND_FUNCTION]: 1, [FUNCTION_IMPORT]: 1 }
17
15
 
18
16
  const { isCustomOperation } = require('../utils/request')
19
- const { actionAndFunctionQueries, getActionOrFunctionReturnType } = require('../utils/handlerUtils')
17
+ const { getActionOrFunctionReturnType } = require('../utils/handlerUtils')
20
18
  const { validateResourcePath } = require('../utils/request')
21
19
  const { toODataResult, postProcess } = require('../utils/result')
22
20
  const { isStreaming, getStreamProperties } = require('../utils/stream')
23
21
  const { resolveStructuredName } = require('../utils/handlerUtils')
24
-
25
22
  const getError = require('../../../../common/error')
26
23
  const { getSapMessages } = require('../../../../common/error/frontend')
24
+ const { getMaxPageSize } = require('../../../../common/utils/page')
27
25
 
28
26
  /**
29
27
  * Checks whether a bound function or function import is invoked.
@@ -34,10 +32,6 @@ const { getSapMessages } = require('../../../../common/error/frontend')
34
32
  */
35
33
  const _isFunction = segments => segments[segments.length - 1].getKind() in FUNCTION
36
34
 
37
- const _selectOrExpandInQueryOptions = queryOptions => {
38
- return queryOptions && (queryOptions.$select || queryOptions.$expand)
39
- }
40
-
41
35
  /**
42
36
  * Invoke a function.
43
37
  *
@@ -47,23 +41,9 @@ const _selectOrExpandInQueryOptions = queryOptions => {
47
41
  * @returns {Promise}
48
42
  * @private
49
43
  */
50
- const _invokeFunction = async (tx, req, odataReq) => {
44
+ const _invokeFunction = async (tx, req) => {
51
45
  let result = await tx.dispatch(req)
52
46
 
53
- const functionReturnType = getActionOrFunctionReturnType(
54
- odataReq.getUriInfo().getPathSegments(),
55
- tx.model.definitions
56
- )
57
-
58
- // if $select or $expand is present, do it
59
- if (
60
- functionReturnType &&
61
- functionReturnType.kind === 'entity' &&
62
- _selectOrExpandInQueryOptions(odataReq.getQueryOptions())
63
- ) {
64
- result = await actionAndFunctionQueries(req, odataReq, result, tx, functionReturnType)
65
- }
66
-
67
47
  return toODataResult(result, req)
68
48
  }
69
49
 
@@ -86,31 +66,43 @@ const _isCount = segments => segments[segments.length - 1].getKind() === COUNT
86
66
  * @private
87
67
  */
88
68
  const _getCount = async (tx, readReq) => {
89
- // REVISIT: this process appears to be rather clumsy
90
-
91
- // Copy CQN including from and where and changing columns
92
- const select = SELECT.from(readReq.query.SELECT.from)
93
- select.SELECT.columns = [{ func: 'count', args: [{ val: '1' }], as: '$count' }]
94
-
95
- if (readReq.query.SELECT.where) select.SELECT.where = readReq.query.SELECT.where
96
- if (readReq.query.SELECT.search) select.SELECT.search = readReq.query.SELECT.search
97
- const req = readReq
98
-
99
- // preserve _target
100
- select._target = req.query._target
101
-
102
- // remove as Object.defineProperty would cause a conflict
103
- delete req.query
104
-
105
- // Define new CQN
106
- req.query = select
107
- // todo check limit
108
- const result = await tx.dispatch(req)
109
-
110
- const count = (result[0] && (result[0].$count || result[0]._counted_)) || 0
111
-
112
- // Transform into scalar result
113
- return toODataResult(count)
69
+ // REVISIT once new parser is out of beta
70
+ // New parser directly removes unapplicable query options from query, no copying of cqn needed
71
+ if (cds.env.features.odata_new_parser) {
72
+ // todo check limit
73
+ const result = await tx.dispatch(readReq)
74
+
75
+ const count = result.reduce((acc, val) => {
76
+ return acc + ((val && (val.$count || val._counted_)) || (val[0] && (val[0].$count || val[0]._counted_))) || 0
77
+ }, 0)
78
+ // Transform into scalar result
79
+ return toODataResult(count)
80
+ } else {
81
+ // REVISIT: this process appears to be rather clumsy
82
+ // Copy CQN including from, where and search + changing columns
83
+ const select = SELECT.from(readReq.query.SELECT.from)
84
+ select.SELECT.columns = [{ func: 'count', args: [{ val: '1' }], as: '$count' }]
85
+
86
+ if (readReq.query.SELECT.where) select.SELECT.where = readReq.query.SELECT.where
87
+ if (readReq.query.SELECT.search) select.SELECT.search = readReq.query.SELECT.search
88
+ const req = readReq
89
+
90
+ // preserve _target
91
+ select._target = req.query._target
92
+
93
+ // remove as Object.defineProperty would cause a conflict
94
+ delete req.query
95
+
96
+ // Define new CQN
97
+ req.query = select
98
+ // todo check limit
99
+ const result = await tx.dispatch(req)
100
+
101
+ const count = result.$count || result._counted_ || (result[0] && (result[0].$count || result[0]._counted_)) || 0
102
+
103
+ // Transform into scalar result
104
+ return toODataResult(count, req)
105
+ }
114
106
  }
115
107
 
116
108
  /**
@@ -232,12 +224,12 @@ const _readEntityOrProperty = async (tx, req, segments) => {
232
224
  if (propertyElement === null) {
233
225
  _transformRedirectProperties(req, result)
234
226
 
235
- return toODataResult(result[0])
227
+ return toODataResult(result[0], req)
236
228
  }
237
229
 
238
230
  result = _getResult(resolveStructuredName(segments, segments.length - 2), result[0])
239
231
 
240
- if (req.target._etag) result.$etag = result[req.target._etag]
232
+ if (req.target._etag) result.$etag = result[req.target._etag.name]
241
233
 
242
234
  const odataResult = toODataResult(result, req)
243
235
 
@@ -269,10 +261,25 @@ const _readEntityOrProperty = async (tx, req, segments) => {
269
261
  */
270
262
  const _readCollection = async (tx, req, odataReq) => {
271
263
  const result = (await tx.dispatch(req)) || []
264
+ if (Array.isArray(req.query)) {
265
+ const adjustedResult = []
266
+ if (req.query[0].SELECT.count) adjustedResult.$count = 0
267
+ adjustedResult.push(...result[0])
268
+ adjustedResult.$count += result[0].$count ? result[0].$count : 0
269
+ for (let i = 1; i < result.length; i++) {
270
+ adjustedResult.push(...result[i])
271
+ adjustedResult.$count += result[i].$count ? result[i].$count : 0
272
+ //Add OData context, if it deviates from main context
273
+ if (req._metaInfo.contextUrl !== req._metaInfo.additionalContextUrl[i - 1])
274
+ result[i].forEach(entry => (entry['*@odata.context'] = req._metaInfo.additionalContextUrl[i - 1]))
275
+ }
276
+ result.splice(0, result.length, ...adjustedResult)
277
+ if (req.query[0].SELECT.count) result.$count = adjustedResult.$count || 0
278
+ } else if (req.query.SELECT.count && !('$count' in result)) result.$count = 0
272
279
 
273
- if (req.query.SELECT.count && !('$count' in result)) result.$count = 0
274
-
275
- const limit = req.query.SELECT.limit && req.query.SELECT.limit.rows && req.query.SELECT.limit.rows.val
280
+ const limit = Array.isArray(req.query)
281
+ ? getMaxPageSize(req.query[0]._target)
282
+ : req.query.SELECT.limit && req.query.SELECT.limit.rows && req.query.SELECT.limit.rows.val
276
283
  const top = odataReq.getUriInfo().getQueryOption(QueryOptions.TOP)
277
284
  if (limit && limit === result.length && limit !== top && !('$nextLink' in result)) {
278
285
  const token = odataReq.getUriInfo().getQueryOption(QueryOptions.SKIPTOKEN)
@@ -25,7 +25,7 @@ module.exports = srv => {
25
25
  }
26
26
 
27
27
  // check @requires as soon as possible (DoS)
28
- if (requires.length > 0 && !requires.some(r => user.is(r))) {
28
+ if (requires && !requires.some(r => user.is(r))) {
29
29
  // > unauthorized or forbidden?
30
30
  if (user._is_anonymous) {
31
31
  if (user._challenges) res.set('WWW-Authenticate', user._challenges.join(';'))
@@ -51,7 +51,7 @@ module.exports = srv => {
51
51
  })
52
52
  }
53
53
 
54
- odataReq.setApplicationData({ req })
54
+ odataReq.setApplicationData({ req, res })
55
55
  }
56
56
 
57
57
  next()
@@ -8,28 +8,25 @@ const {
8
8
 
9
9
  const { validateResourcePath } = require('../utils/request')
10
10
  const { isReturnMinimal } = require('../utils/handlerUtils')
11
- const readAfterWrite = require('../utils/readAfterWrite')
11
+ const { readAfterWrite } = require('../utils/readAfterWrite')
12
12
  const { toODataResult, postProcess, postProcessMinimal } = require('../utils/result')
13
13
  const { hasOmitValuesPreference } = require('../utils/omitValues')
14
14
 
15
- const { mergeJson } = require('../../../services/utils/compareJson')
16
-
17
15
  const { getSapMessages } = require('../../../../common/error/frontend')
18
16
 
19
17
  const _isUpsertAllowed = target => {
20
18
  return !(cds.env.runtime && cds.env.runtime.allow_upsert === false) && !(target && target._isDraftEnabled)
21
19
  }
22
20
 
23
- const _infoForeignKeyInParent = (req, odataReq, odataRes, tx) => {
21
+ const _infoForeignKeyInParent = (req, tx) => {
24
22
  const info = {}
25
23
  // keys not in data
26
24
  if (req.target.keys && Object.keys(req.target.keys).some(key => key in req.data)) {
27
25
  return info
28
26
  }
29
27
 
30
- req = new ODataRequest(DATA_CREATE_HANDLER, tx, odataReq, odataRes, true)
31
- const nav = req.query.INSERT.into.ref && req.query.INSERT.into.ref.length !== 0 && req.query.INSERT.into.ref[1]
32
- const parent = req.query.INSERT.into.ref && req.query.INSERT.into.ref[0].id
28
+ const nav = req.query.UPDATE.entity.ref && req.query.UPDATE.entity.ref.length !== 0 && req.query.UPDATE.entity.ref[1]
29
+ const parent = req.query.UPDATE.entity.ref && req.query.UPDATE.entity.ref[0].id
33
30
 
34
31
  // not a navigation
35
32
  if (!parent || !nav) {
@@ -40,18 +37,18 @@ const _infoForeignKeyInParent = (req, odataReq, odataRes, tx) => {
40
37
  const navElement = tx.model.definitions[parent].elements[navID]
41
38
 
42
39
  // not a containment
43
- if (!navElement['@odata.contained']) {
40
+ if (!navElement._isContained) {
44
41
  return info
45
42
  }
46
43
 
47
- const where = req.query.INSERT.into.ref[0].where
44
+ const where = req.query.UPDATE.entity.ref[0].where
48
45
  return { parent, navElement, where }
49
46
  }
50
47
 
51
48
  const _create = async (req, odataReq, odataRes, tx) => {
52
49
  let result
53
50
 
54
- const { parent, navElement, where } = _infoForeignKeyInParent(req, odataReq, odataRes, tx)
51
+ const { parent, navElement, where } = _infoForeignKeyInParent(req, tx)
55
52
  if (parent && navElement && where) {
56
53
  const onKeys = navElement._foreignKeys
57
54
  const parentKeys = onKeys.filter(key => key.parentElement).map(key => key.parentElement.name)
@@ -107,14 +104,10 @@ const _updateThenCreate = async (req, odataReq, odataRes, tx) => {
107
104
  return [result, req]
108
105
  }
109
106
 
110
- const _readAfterWriteAndVirtuals = async (req, service, result) => {
111
- const dataInDb = await readAfterWrite(req, service)
112
- if (dataInDb.length) result = mergeJson(dataInDb[0], result, req.target)
113
- return result
114
- }
115
-
116
107
  const _shouldReadPreviousResult = req =>
117
- req.event === 'UPDATE' && !isReturnMinimal(req) && hasOmitValuesPreference(req.headers.prefer, 'defaults')
108
+ req.event === 'UPDATE' &&
109
+ !isReturnMinimal(req) &&
110
+ (hasOmitValuesPreference(req.headers.prefer, 'defaults') || hasOmitValuesPreference(req.headers.prefer, 'nulls'))
118
111
 
119
112
  /**
120
113
  * The handler that will be registered with odata-v4.
@@ -149,21 +142,23 @@ const update = service => {
149
142
  let previousResult
150
143
 
151
144
  if (_shouldReadPreviousResult(req)) {
152
- previousResult = await _readAfterWriteAndVirtuals(req, service, result)
145
+ // this is not a read AFTER update, but BEFORE
146
+ previousResult = await readAfterWrite(req, service, { isBefore: true })
153
147
  }
154
148
 
155
149
  // try UPDATE and, on 404 error, try CREATE
156
150
  ;[result, req] = await _updateThenCreate(req, odataReq, odataRes, tx)
157
151
 
152
+ if (!primitive && req._.readAfterWrite) {
153
+ // REVISIT:
154
+ // Performance: For `isReturnMinimal` it's enough to just read the etag.
155
+ // Note: Without read access, one cannot return the etag.
156
+ result = await readAfterWrite(req, service, { operation: { result } })
157
+ }
158
158
  if (!isReturnMinimal(req)) {
159
- // REVISIT: find better solution
160
- if (!primitive && req._.readAfterWrite) {
161
- result = await _readAfterWriteAndVirtuals(req, service, result)
162
- }
163
-
164
159
  postProcess(req, odataRes, service, result, previousResult)
165
160
  } else {
166
- postProcessMinimal(req, result)
161
+ result = postProcessMinimal(req, service, result)
167
162
  }
168
163
 
169
164
  if (changeset) {
@@ -173,7 +168,7 @@ const update = service => {
173
168
  await tx.commit(result)
174
169
  }
175
170
 
176
- if (isReturnMinimal(req)) {
171
+ if (isReturnMinimal(req) || result === null) {
177
172
  odataRes.setStatusCode(204)
178
173
  }
179
174
  } catch (e) {
@@ -195,7 +190,7 @@ const update = service => {
195
190
  const res = { value: result[prop] }
196
191
  for (const k of Object.keys(result).filter(k => k.match(/^\*/))) res[k] = result[k]
197
192
  next(null, res)
198
- } else next(null, toODataResult(result))
193
+ } else next(null, toODataResult(result, req))
199
194
  }
200
195
  }
201
196
  }
@@ -6,6 +6,7 @@ const MethodKind = odata.uri.MethodExpression.MethodKind
6
6
  const ResourceKind = odata.uri.UriResource.ResourceKind
7
7
  const EdmPrimitiveTypeKind = odata.edm.EdmPrimitiveTypeKind
8
8
  const { getFeatureNotSupportedError } = require('../../../util/errors')
9
+ const { getSegmentKeyValue } = require('./utils')
9
10
 
10
11
  const _binaryOperatorToCQN = new Map([
11
12
  [BinaryOperatorKind.EQ, '='],
@@ -115,11 +116,13 @@ class ExpressionToCQN {
115
116
  nextSegments[nextSegments.length - 1].getKind() === ResourceKind.COUNT &&
116
117
  segment.getKeyPredicates().reduce((prev, curr) => {
117
118
  if (prev.length > 0) prev.push('and')
118
- prev.push({ ref: [curr.getEdmRef().getName()] }, '=', { val: curr.getText() })
119
+ const { keyName, val } = getSegmentKeyValue(curr)
120
+ const ref = keyName.includes('/') ? keyName.split('/') : [keyName]
121
+ prev.push({ ref }, '=', { val })
119
122
  return prev
120
123
  }, [])
121
124
 
122
- return [where ? { id: name, where } : name, ...this._getMemberRecursively(nextSegments)]
125
+ return [where && where.length ? { id: name, where } : name, ...this._getMemberRecursively(nextSegments)]
123
126
  }
124
127
 
125
128
  if (segment.getKind() === ResourceKind.NAVIGATION_TO_MANY) {
@@ -240,7 +243,7 @@ class ExpressionToCQN {
240
243
 
241
244
  _compare(operator, left, right, unary) {
242
245
  return unary === 'not'
243
- ? [unary, '(', left, _binaryOperatorToCQN.get(operator), right, ')']
246
+ ? [unary, { xpr: [left, _binaryOperatorToCQN.get(operator), right] }]
244
247
  : [left, _binaryOperatorToCQN.get(operator), right]
245
248
  }
246
249
 
@@ -258,17 +261,13 @@ class ExpressionToCQN {
258
261
  switch (operator) {
259
262
  case BinaryOperatorKind.AND:
260
263
  return unary === 'not'
261
- ? [unary, '(', ...this._ensureArr(left), 'and', ...this._ensureArr(right), ')']
264
+ ? [unary, { xpr: [...this._ensureArr(left), 'and', ...this._ensureArr(right)] }]
262
265
  : [...this._ensureArr(left), 'and', ...this._ensureArr(right)]
263
266
 
264
267
  case BinaryOperatorKind.OR:
265
268
  return [
266
269
  ...(unary === 'not' ? [unary] : []),
267
- '(',
268
- ...this._ensureArr(left),
269
- 'or',
270
- ...this._ensureArr(right),
271
- ')'
270
+ { xpr: [...this._ensureArr(left), 'or', ...this._ensureArr(right)] }
272
271
  ]
273
272
 
274
273
  case BinaryOperatorKind.NE:
@@ -304,23 +303,17 @@ class ExpressionToCQN {
304
303
  switch (expression.getKind()) {
305
304
  case ExpressionKind.ALIAS:
306
305
  return this.parse(expression.getExpression())
307
-
308
306
  case ExpressionKind.BINARY:
309
307
  operator = operator || expression.getOperator()
310
308
  return this._binary(expression, operator)
311
-
312
309
  case ExpressionKind.LITERAL:
313
310
  return this._convert(expression)
314
-
315
311
  case ExpressionKind.MEMBER:
316
312
  return this._member(expression, operator)
317
-
318
313
  case ExpressionKind.METHOD:
319
314
  return this._method(expression, operator)
320
-
321
315
  case ExpressionKind.UNARY:
322
316
  return this._unary(expression)
323
-
324
317
  default:
325
318
  throw getFeatureNotSupportedError(`Expression "${expression.getKind()}" in $filter or $orderby query options`)
326
319
  }