@sap/cds 7.9.2 → 8.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 (279) hide show
  1. package/CHANGELOG.md +139 -3656
  2. package/_i18n/i18n_en_US_saptrc.properties +113 -0
  3. package/_i18n/i18n_zh_CN.properties +7 -4
  4. package/app/index.css +129 -0
  5. package/app/index.html +16 -64
  6. package/app/index.js +14 -9
  7. package/bin/args.js +34 -0
  8. package/bin/serve.js +18 -24
  9. package/bin/test.js +97 -0
  10. package/common.cds +5 -12
  11. package/eslint.config.mjs +133 -0
  12. package/lib/auth/basic-auth.js +16 -20
  13. package/lib/auth/dummy-auth.js +1 -1
  14. package/lib/auth/ias-auth.js +12 -30
  15. package/lib/auth/index.js +1 -14
  16. package/lib/auth/jwt-auth.js +14 -30
  17. package/lib/compile/cds-compile.js +1 -2
  18. package/lib/compile/cdsc.js +21 -26
  19. package/lib/compile/etc/_localized.js +1 -6
  20. package/lib/compile/etc/csv.js +1 -1
  21. package/lib/compile/etc/properties.js +1 -1
  22. package/lib/compile/for/java.js +1 -1
  23. package/lib/compile/for/lean_drafts.js +4 -6
  24. package/lib/compile/for/nodejs.js +1 -1
  25. package/lib/compile/parse.js +4 -0
  26. package/lib/compile/resolve.js +4 -4
  27. package/lib/compile/to/edm-files.js +16 -23
  28. package/lib/compile/to/hana.js +27 -0
  29. package/lib/compile/to/json.js +1 -1
  30. package/lib/compile/to/sql.js +5 -1
  31. package/lib/compile/to/srvinfo.js +1 -1
  32. package/lib/compile/to/yaml.js +3 -3
  33. package/lib/dbs/cds-deploy.js +4 -2
  34. package/lib/env/cds-env.js +10 -14
  35. package/lib/env/cds-requires.js +29 -13
  36. package/lib/env/defaults.js +46 -16
  37. package/lib/env/plugins.js +1 -1
  38. package/lib/env/schemas/cds-rc.js +8 -4
  39. package/lib/env/schemas/index.js +7 -7
  40. package/lib/env/serviceBindings.js +1 -1
  41. package/lib/index.js +12 -10
  42. package/lib/lazy.js +1 -1
  43. package/lib/linked/classes.js +36 -8
  44. package/lib/linked/entities.js +2 -10
  45. package/lib/linked/models.js +2 -1
  46. package/lib/linked/validate.js +292 -0
  47. package/lib/log/cds-error.js +0 -6
  48. package/lib/log/cds-log.js +3 -3
  49. package/lib/log/format/json.js +1 -1
  50. package/lib/log/service/index.js +0 -1
  51. package/lib/plugins.js +3 -3
  52. package/lib/ql/Query.js +2 -10
  53. package/lib/ql/SELECT.js +1 -1
  54. package/lib/ql/Whereable.js +3 -2
  55. package/lib/req/cds-context.js +14 -25
  56. package/lib/req/context.js +23 -25
  57. package/lib/req/request.js +1 -34
  58. package/lib/req/user.js +47 -35
  59. package/lib/srv/bindings.js +1 -1
  60. package/lib/srv/cds-connect.js +4 -4
  61. package/lib/srv/cds-serve.js +2 -2
  62. package/lib/srv/factory.js +1 -1
  63. package/lib/srv/middlewares/cds-context.js +11 -22
  64. package/lib/srv/middlewares/ctx-model.js +2 -3
  65. package/lib/srv/middlewares/errors.js +41 -8
  66. package/lib/srv/middlewares/index.js +3 -3
  67. package/lib/srv/middlewares/trace.js +0 -2
  68. package/lib/srv/protocols/hcql.js +15 -10
  69. package/lib/srv/protocols/http.js +44 -49
  70. package/lib/srv/protocols/index.js +1 -23
  71. package/lib/srv/protocols/odata-v4.js +12 -74
  72. package/lib/srv/protocols/rest.js +1 -13
  73. package/lib/srv/srv-api.js +0 -20
  74. package/lib/srv/srv-dispatch.js +3 -2
  75. package/lib/srv/srv-handlers.js +22 -11
  76. package/lib/srv/srv-methods.js +2 -2
  77. package/lib/srv/srv-models.js +3 -36
  78. package/lib/test/expect.js +343 -0
  79. package/lib/test/index.js +2 -0
  80. package/lib/test/reporter.js +176 -0
  81. package/lib/utils/axios.js +10 -9
  82. package/lib/utils/cds-test.js +86 -37
  83. package/lib/utils/cds-utils.js +54 -7
  84. package/lib/utils/check-version.js +0 -4
  85. package/lib/utils/colors.js +49 -0
  86. package/lib/utils/data.js +5 -4
  87. package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +2 -7
  88. package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +3 -30
  89. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/error.js +6 -12
  90. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +1 -3
  91. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +0 -1
  92. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +4 -7
  93. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +12 -6
  94. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +2 -4
  95. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/applyToCQN.js +1 -0
  96. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/expandToCQN.js +1 -1
  97. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/index.js +0 -1
  98. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/readToCQN.js +1 -3
  99. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/utils.js +1 -1
  100. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/edm/AbstractEdmStructuredType.js +1 -2
  101. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/ResourceJsonDeserializer.js +5 -0
  102. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/serializer/ContextURLFactory.js +1 -1
  103. package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +9 -43
  104. package/libx/_runtime/cds-services/adapter/odata-v4/utils/metaInfo.js +0 -1
  105. package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +8 -3
  106. package/libx/_runtime/cds-services/adapter/odata-v4/utils/request.js +4 -2
  107. package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +1 -3
  108. package/libx/_runtime/cds-services/util/assert.js +1 -1
  109. package/libx/_runtime/cds.js +10 -3
  110. package/libx/_runtime/common/Service.js +12 -32
  111. package/libx/_runtime/common/aspects/any.js +1 -0
  112. package/libx/_runtime/common/code-ext/execute.js +1 -1
  113. package/libx/_runtime/common/code-ext/worker.js +0 -1
  114. package/libx/_runtime/common/composition/data.js +0 -1
  115. package/libx/_runtime/common/composition/delete.js +0 -1
  116. package/libx/_runtime/common/composition/insert.js +2 -2
  117. package/libx/_runtime/common/composition/tree.js +0 -1
  118. package/libx/_runtime/common/composition/update.js +3 -3
  119. package/libx/_runtime/common/error/frontend.js +21 -12
  120. package/libx/_runtime/common/error/log.js +36 -0
  121. package/libx/_runtime/common/error/utils.js +2 -5
  122. package/libx/_runtime/common/generic/auth/autoexpose.js +18 -17
  123. package/libx/_runtime/common/generic/auth/expand.js +1 -1
  124. package/libx/_runtime/common/generic/auth/readOnly.js +1 -2
  125. package/libx/_runtime/common/generic/auth/restrict.js +23 -42
  126. package/libx/_runtime/common/generic/auth/restrictions.js +2 -7
  127. package/libx/_runtime/common/generic/auth/utils.js +91 -88
  128. package/libx/_runtime/common/generic/crud.js +6 -5
  129. package/libx/_runtime/common/generic/etag.js +7 -12
  130. package/libx/_runtime/common/generic/input.js +70 -68
  131. package/libx/_runtime/common/generic/paging.js +1 -0
  132. package/libx/_runtime/common/generic/sorting.js +1 -0
  133. package/libx/_runtime/common/generic/temporal.js +8 -2
  134. package/libx/_runtime/common/i18n/index.js +1 -1
  135. package/libx/_runtime/common/i18n/messages.properties +3 -1
  136. package/libx/_runtime/common/utils/binary.js +8 -2
  137. package/libx/_runtime/common/utils/compareJson.js +5 -1
  138. package/libx/_runtime/common/utils/copy.js +6 -11
  139. package/libx/_runtime/common/utils/cqn2cqn4sql.js +16 -14
  140. package/libx/_runtime/common/utils/differ.js +3 -6
  141. package/libx/_runtime/common/utils/keys.js +77 -18
  142. package/libx/_runtime/common/utils/postProcess.js +12 -15
  143. package/libx/_runtime/common/utils/propagateForeignKeys.js +0 -1
  144. package/libx/_runtime/common/utils/resolveView.js +2 -3
  145. package/libx/_runtime/common/utils/restrictions.js +45 -17
  146. package/libx/_runtime/common/utils/rewriteAsterisks.js +1 -8
  147. package/libx/_runtime/common/utils/stream.js +3 -16
  148. package/libx/_runtime/common/utils/streamProp.js +8 -18
  149. package/libx/_runtime/common/utils/structured.js +1 -1
  150. package/libx/_runtime/common/utils/ucsn.js +0 -2
  151. package/libx/_runtime/db/Service.js +0 -72
  152. package/libx/_runtime/db/data-conversion/post-processing.js +0 -1
  153. package/libx/_runtime/db/expand/expandCQNToJoin.js +9 -9
  154. package/libx/_runtime/db/expand/rawToExpanded.js +0 -8
  155. package/libx/_runtime/db/generic/input.js +3 -8
  156. package/libx/_runtime/db/generic/rewrite.js +27 -4
  157. package/libx/_runtime/db/query/read.js +2 -2
  158. package/libx/_runtime/db/sql-builder/ExpressionBuilder.js +0 -1
  159. package/libx/_runtime/db/sql-builder/InsertBuilder.js +1 -1
  160. package/libx/_runtime/db/utils/columns.js +2 -6
  161. package/libx/_runtime/fiori/lean-draft.js +138 -56
  162. package/libx/_runtime/hana/Service.js +0 -1
  163. package/libx/_runtime/hana/driver.js +1 -1
  164. package/libx/_runtime/hana/dynatrace.js +1 -2
  165. package/libx/_runtime/hana/pool.js +11 -21
  166. package/libx/_runtime/hana/streaming.js +0 -1
  167. package/libx/_runtime/messaging/common-utils/AMQPClient.js +0 -1
  168. package/libx/_runtime/messaging/common-utils/authorizedRequest.js +1 -1
  169. package/libx/_runtime/messaging/common-utils/normalizeIncomingMessage.js +1 -1
  170. package/libx/_runtime/messaging/enterprise-messaging-utils/getTenantInfo.js +1 -1
  171. package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +19 -33
  172. package/libx/_runtime/messaging/event-broker.js +0 -12
  173. package/libx/_runtime/messaging/file-based.js +3 -3
  174. package/libx/_runtime/messaging/http-utils/token.js +1 -1
  175. package/libx/_runtime/messaging/kafka.js +2 -2
  176. package/libx/_runtime/messaging/redis-messaging.js +0 -1
  177. package/libx/_runtime/remote/Service.js +25 -25
  178. package/libx/_runtime/remote/utils/client.js +4 -5
  179. package/libx/_runtime/remote/utils/cloudSdkProvider.js +0 -3
  180. package/libx/_runtime/remote/utils/data.js +0 -1
  181. package/libx/_runtime/sqlite/Service.js +1 -2
  182. package/libx/_runtime/ucl/Service.js +37 -78
  183. package/libx/common/assert/index.js +22 -21
  184. package/libx/common/assert/type-relaxed.js +39 -0
  185. package/libx/common/assert/utils.js +3 -2
  186. package/libx/common/assert/validation.js +3 -8
  187. package/libx/common/utils/index.js +5 -0
  188. package/libx/common/utils/path.js +51 -0
  189. package/libx/odata/ODataAdapter.js +126 -0
  190. package/libx/odata/index.js +15 -2
  191. package/libx/odata/middleware/batch.js +261 -72
  192. package/libx/odata/middleware/body-parser.js +33 -0
  193. package/libx/odata/middleware/create.js +44 -59
  194. package/libx/odata/middleware/delete.js +23 -12
  195. package/libx/odata/middleware/error.js +30 -6
  196. package/libx/odata/middleware/metadata.js +38 -26
  197. package/libx/odata/middleware/operation.js +93 -69
  198. package/libx/odata/middleware/parse.js +6 -8
  199. package/libx/odata/middleware/read.js +117 -93
  200. package/libx/odata/middleware/service-document.js +22 -19
  201. package/libx/odata/middleware/stream.js +54 -56
  202. package/libx/odata/middleware/update.js +79 -87
  203. package/libx/odata/parse/afterburner.js +191 -175
  204. package/libx/odata/parse/cqn2odata.js +8 -8
  205. package/libx/odata/parse/grammar.peggy +27 -20
  206. package/libx/odata/parse/multipartToJson.js +17 -9
  207. package/libx/odata/parse/parser.js +1 -1
  208. package/libx/odata/utils/etag.js +14 -6
  209. package/libx/odata/utils/index.js +84 -12
  210. package/libx/odata/utils/metadata.js +161 -0
  211. package/libx/odata/utils/postProcess.js +89 -0
  212. package/libx/odata/utils/readAfterWrite.js +134 -17
  213. package/libx/odata/utils/result.js +36 -142
  214. package/libx/outbox/index.js +5 -4
  215. package/libx/rest/RestAdapter.js +115 -182
  216. package/libx/rest/middleware/create.js +28 -24
  217. package/libx/rest/middleware/delete.js +7 -10
  218. package/libx/rest/middleware/error.js +19 -16
  219. package/libx/rest/middleware/operation.js +48 -41
  220. package/libx/rest/middleware/parse.js +128 -126
  221. package/libx/rest/middleware/read.js +20 -27
  222. package/libx/rest/middleware/update.js +26 -31
  223. package/package.json +16 -12
  224. package/server.js +4 -2
  225. package/tasks/enterprise-messaging-deploy.js +1 -1
  226. package/apis/cds.d.ts +0 -3
  227. package/apis/core.d.ts +0 -21
  228. package/apis/cqn.d.ts +0 -18
  229. package/apis/csn.d.ts +0 -21
  230. package/apis/events.d.ts +0 -18
  231. package/apis/internal/inference.d.ts +0 -18
  232. package/apis/linked.d.ts +0 -18
  233. package/apis/log.d.ts +0 -20
  234. package/apis/models.d.ts +0 -18
  235. package/apis/ql.d.ts +0 -18
  236. package/apis/reflect.d.ts +0 -32
  237. package/apis/server.d.ts +0 -18
  238. package/apis/services.d.ts +0 -22
  239. package/bin/cds-serve.js +0 -56
  240. package/lib/compile/to/gql.js +0 -15
  241. package/lib/srv/protocols/_legacy.js +0 -44
  242. package/lib/utils/jest.js +0 -43
  243. package/libx/_runtime/auth/index.js +0 -193
  244. package/libx/_runtime/auth/strategies/JWT.js +0 -37
  245. package/libx/_runtime/auth/strategies/basic.js +0 -20
  246. package/libx/_runtime/auth/strategies/dummy.js +0 -14
  247. package/libx/_runtime/auth/strategies/ias-auth.js +0 -1
  248. package/libx/_runtime/auth/strategies/mock.js +0 -77
  249. package/libx/_runtime/auth/strategies/xssecUtils.js +0 -93
  250. package/libx/_runtime/auth/strategies/xsuaa.js +0 -38
  251. package/libx/_runtime/common/perf/index.js +0 -19
  252. package/libx/_runtime/common/utils/ensureIEEE754.js +0 -29
  253. package/libx/_runtime/fiori/draft.js +0 -2
  254. package/libx/_runtime/fiori/generic/activate.js +0 -190
  255. package/libx/_runtime/fiori/generic/before.js +0 -201
  256. package/libx/_runtime/fiori/generic/cancel.js +0 -19
  257. package/libx/_runtime/fiori/generic/delete.js +0 -21
  258. package/libx/_runtime/fiori/generic/edit.js +0 -157
  259. package/libx/_runtime/fiori/generic/index.js +0 -25
  260. package/libx/_runtime/fiori/generic/new.js +0 -82
  261. package/libx/_runtime/fiori/generic/patch.js +0 -101
  262. package/libx/_runtime/fiori/generic/prepare.js +0 -57
  263. package/libx/_runtime/fiori/generic/read.js +0 -1340
  264. package/libx/_runtime/fiori/generic/readOverDraft.js +0 -146
  265. package/libx/_runtime/fiori/utils/csn.js +0 -13
  266. package/libx/_runtime/fiori/utils/delete.js +0 -114
  267. package/libx/_runtime/fiori/utils/handler.js +0 -264
  268. package/libx/_runtime/fiori/utils/lockInfo.js +0 -27
  269. package/libx/_runtime/fiori/utils/req.js +0 -23
  270. package/libx/_runtime/fiori/utils/stream.js +0 -36
  271. package/libx/_runtime/fiori/utils/where.js +0 -254
  272. package/libx/_runtime/index.js +0 -22
  273. package/libx/odata/utils/handler.js +0 -120
  274. package/libx/odata/utils/metaInfo.js +0 -410
  275. package/libx/odata/utils/path.js +0 -75
  276. package/libx/rest/RestRequest.js +0 -32
  277. package/libx/rest/index.js +0 -3
  278. package/libx/rest/readme.md +0 -1
  279. /package/libx/common/assert/{type.js → type-strict.js} +0 -0
@@ -1,21 +0,0 @@
1
- const cds = require('../../cds')
2
- const { deleteDraft } = require('../utils/delete')
3
-
4
- /**
5
- * Generic Handler for DELETE requests.
6
- * In case of success it returns an empty object.
7
- * If the entry to be deleted does not exist, it rejects with error to return a 404.
8
- *
9
- * @param req
10
- */
11
- const fioriGenericDelete = function (req, next) {
12
- if (!req.target._isDraftEnabled) return next()
13
-
14
- // we should call deleteDraft only for draft tables and call next
15
- // to pass delete of active tables to our general implementation
16
- return deleteDraft(req, this, true)
17
- }
18
-
19
- module.exports = cds.service.impl(function (srv) {
20
- srv.on('DELETE', '*', fioriGenericDelete)
21
- })
@@ -1,157 +0,0 @@
1
- const cds = require('../../cds')
2
- const getLockInfo = require('../utils/lockInfo')
3
- const { INSERT, SELECT, DELETE } = cds.ql
4
-
5
- const { getCompositionTree } = require('../../common/composition')
6
- const { getColumns } = require('../../common/utils/columns')
7
- const { draftIsLocked, ensureDraftsSuffix, ensureNoDraftsSuffix, getSubCQNs } = require('../utils/handler')
8
- const { isActiveEntityRequested } = require('../utils/where')
9
-
10
- const _getDraftColumns = draftUUID => ({
11
- IsActiveEntity: false,
12
- HasDraftEntity: false,
13
- HasActiveEntity: true,
14
- DraftAdministrativeData_DraftUUID: draftUUID
15
- })
16
-
17
- const _getAdminData = ({ user }, draftUUID, time) => {
18
- const currentUser = user.id || null
19
- return {
20
- DraftUUID: draftUUID,
21
- CreationDateTime: time,
22
- CreatedByUser: currentUser,
23
- LastChangeDateTime: time,
24
- LastChangedByUser: currentUser,
25
- DraftIsCreatedByMe: true,
26
- DraftIsProcessedByMe: true,
27
- InProcessByUser: currentUser
28
- }
29
- }
30
-
31
- const _getInsertAdminDataCQN = ({ user }, draftUUID, time) => {
32
- return INSERT.into('DRAFT.DraftAdministrativeData').entries(_getAdminData({ user }, draftUUID, time))
33
- }
34
-
35
- async function _lockAndSelectActive(req, lockRecordCQN, selectCQNs, draftExistsCQN) {
36
- try {
37
- await this.run(lockRecordCQN)
38
- } catch (e) {
39
- const drafts = await this.run(draftExistsCQN)
40
- if (drafts.length) req.reject(409, 'DRAFT_ALREADY_EXISTS')
41
- req.reject(409, 'ENTITY_LOCKED')
42
- }
43
-
44
- const cqns = [this.run(draftExistsCQN), ...selectCQNs.map(cqn => this.run(cqn))]
45
- const promisesResults = await Promise.allSettled(cqns)
46
- const firstRejected = promisesResults.find(r => r.status === 'rejected')
47
- if (firstRejected) req.reject(firstRejected.reason)
48
- return promisesResults.map(result => result.value)
49
- }
50
-
51
- /**
52
- * Generic event handler for draft edit requests.
53
- *
54
- * @param req
55
- */
56
- const fioriGenericEdit = async function (req, next) {
57
- if (!req.target._isDraftEnabled) return next()
58
-
59
- if (!isActiveEntityRequested(req.query.SELECT.where || [])) {
60
- req.reject(400, 'Action "draftEdit" can only be called on the active entity')
61
- }
62
-
63
- if (!cds.db) req.reject('NO_DATABASE_CONNECTION')
64
-
65
- const { definitions } = this.model
66
- const lockInfo = getLockInfo(req)
67
- const rootWhere = lockInfo.rootWhere
68
-
69
- // Ensure exclusive access to the root record of the active entity by applying a lock,
70
- // which effectively prevents the creation or overwriting of duplicate draft entities.
71
- // This lock mechanism enforces a strict processing order for active entities,
72
- // allowing only one entity to be worked on at any given time.
73
- // By using .forUpdate() with a wait value of 0, we immediately lock the record,
74
- // ensuring there is no waiting time for other users attempting to edit the same record concurrently.
75
- const activeLockCQN = SELECT.from(lockInfo.target, [1]).where(lockInfo.where).forUpdate({ wait: 0 })
76
-
77
- const columnNames = getColumns(req.target, { onlyNames: true, filterVirtual: true })
78
- const rootCQN = SELECT.from(req.target, columnNames).where(rootWhere)
79
- const subCQNs = getSubCQNs({
80
- definitions,
81
- rootCQN,
82
- compositionTree: getCompositionTree({ definitions, rootEntityName: ensureNoDraftsSuffix(req.target.name) })
83
- })
84
- const rootDraftName = ensureDraftsSuffix(req.target.name)
85
- const draftExistsCQN = SELECT.from(rootDraftName, ['DraftAdministrativeData_DraftUUID as DraftUUID']).where(rootWhere)
86
- const selectCQNs = [rootCQN, ...subCQNs.map(obj => obj.cqn)]
87
-
88
- // fetch unlocalized data if not a texts entity
89
- for (const q of selectCQNs) {
90
- const entity = definitions[q.SELECT.from.ref[0]]
91
- if (entity && !entity.name.match(/\.texts$/)) {
92
- q.SELECT.localized = false
93
- }
94
- }
95
-
96
- const dbtx = cds.tx(req)
97
- // REVISIT: Use service.read with expand **
98
- const [draftExists, ...results] = await _lockAndSelectActive.call(
99
- dbtx,
100
- req,
101
- activeLockCQN,
102
- [...selectCQNs],
103
- draftExistsCQN
104
- )
105
-
106
- if (!results[0].length) req.reject(404)
107
-
108
- if (draftExists.length) {
109
- const adminData = await dbtx.run(
110
- SELECT.one('DRAFT.DraftAdministrativeData', ['InProcessByUser', 'LastChangeDateTime']).where(draftExists[0])
111
- )
112
-
113
- // temp check if draft admin data in not maintained - raise 500 error
114
- if (!adminData) req.reject(500, 'Draft administrative data is not maintained')
115
-
116
- // draft is locked (default cancellation timeout timer has not expired) OR
117
- // draft is not locked but must be rejected for popup
118
- if (draftIsLocked(adminData.LastChangeDateTime) || req.data.PreserveChanges) {
119
- req.reject(409, 'DRAFT_ALREADY_EXISTS')
120
- }
121
-
122
- await Promise.all([
123
- dbtx.run(DELETE.from('DRAFT.DraftAdministrativeData').where(draftExists[0])),
124
- dbtx.run(DELETE.from(rootDraftName).where(rootWhere))
125
- ])
126
- }
127
-
128
- const draftUUID = cds.utils.uuid()
129
- const insertCQNs = [_getInsertAdminDataCQN(req, draftUUID, req.timestamp)]
130
-
131
- for (const resultIndex in results) {
132
- if (results[resultIndex].length === 0) continue
133
- const draftEntity = ensureDraftsSuffix(selectCQNs[resultIndex].SELECT.from.ref[0])
134
- const entries = results[resultIndex].map(entityResult =>
135
- Object.assign({}, entityResult, _getDraftColumns(draftUUID))
136
- )
137
-
138
- insertCQNs.push(INSERT.into(draftEntity).entries(entries))
139
- }
140
-
141
- await Promise.all(insertCQNs.map(CQN => dbtx.run(CQN)))
142
-
143
- // REVISIT: we need to use okra API here because it must be set in the batched request
144
- // status code must be set in handler to allow overriding for FE V2
145
- // REVISIT: needs reworking for new adapter, especially re $batch
146
- if (req._?.odataRes) {
147
- req._?.odataRes?.setStatusCode(201, { overwrite: true })
148
- } else if (req.http?.res) {
149
- req.http.res.status(201)
150
- }
151
-
152
- return results[0][0]
153
- }
154
-
155
- module.exports = cds.service.impl(function (srv) {
156
- srv.on('EDIT', '*', fioriGenericEdit)
157
- })
@@ -1,25 +0,0 @@
1
- const cds = require('../../cds')
2
-
3
- exports.impl = cds.service.impl(function () {
4
- _before(this)
5
- _new(this)
6
- _patch(this)
7
- _cancel(this)
8
- _edit(this)
9
- _prepare(this)
10
- _activate(this)
11
- _delete(this)
12
- _readOverDraft(this)
13
- _read(this) // have to go last
14
- })
15
-
16
- const _before = require('../../fiori/generic/before')
17
- const _new = require('../../fiori/generic/new')
18
- const _patch = require('../../fiori/generic/patch')
19
- const _cancel = require('../../fiori/generic/cancel')
20
- const _edit = require('../../fiori/generic/edit')
21
- const _prepare = require('../../fiori/generic/prepare')
22
- const _activate = require('../../fiori/generic/activate')
23
- const _readOverDraft = require('../../fiori/generic/readOverDraft')
24
- const _read = require('../../fiori/generic/read')
25
- const _delete = require('../../fiori/generic/delete')
@@ -1,82 +0,0 @@
1
- const cds = require('../../cds')
2
- const { INSERT, UPDATE } = cds.ql
3
-
4
- const onDraftActivate = require('./activate')._handler
5
- const { isNavigationToMany } = require('../utils/req')
6
- const { ensureDraftsSuffix } = require('../utils/handler')
7
-
8
- const _getUpdateDraftAdminCQN = ({ user, timestamp }, draftUUID) => {
9
- return UPDATE('DRAFT.DraftAdministrativeData')
10
- .data({
11
- InProcessByUser: user.id,
12
- LastChangedByUser: user.id,
13
- LastChangeDateTime: timestamp
14
- })
15
- .where({ DraftUUID: draftUUID })
16
- }
17
-
18
- const _getInsertDraftAdminCQN = ({ user, timestamp }, uuid) => {
19
- return INSERT.into('DRAFT.DraftAdministrativeData').entries({
20
- DraftUUID: uuid,
21
- CreationDateTime: timestamp,
22
- CreatedByUser: user.id,
23
- LastChangeDateTime: timestamp,
24
- LastChangedByUser: user.id,
25
- DraftIsCreatedByMe: true,
26
- DraftIsProcessedByMe: true,
27
- InProcessByUser: user.id
28
- })
29
- }
30
-
31
- const _getInsertDataCQN = (req, draftUUID) => {
32
- const draftName = ensureDraftsSuffix(req.target.name)
33
-
34
- const insertData = INSERT.into(draftName).entries(req.query.INSERT.entries[0]) // entries is always set because there are no entities without keys
35
-
36
- req.data.IsActiveEntity = false
37
- req.data.HasDraftEntity = false
38
- req.data.HasActiveEntity = false
39
- req.data.DraftAdministrativeData_DraftUUID = draftUUID
40
-
41
- return insertData
42
- }
43
-
44
- /**
45
- * Generic Handler for CREATE requests in the context of draft.
46
- * In case of success it returns the created entry.
47
- *
48
- * @param req
49
- * @param next
50
- */
51
- const fioriGenericNew = async function (req, next) {
52
- if (!req.target._isDraftEnabled) return next()
53
-
54
- if (!req._draftMetadata) {
55
- // REVISIT: when is this the case?
56
- return onDraftActivate(req, next)
57
- }
58
-
59
- if (!cds.db) req.reject('NO_DATABASE_CONNECTION')
60
-
61
- const isRoot = typeof req.query.INSERT.into === 'string' || req.query.INSERT.into.ref?.length === 1
62
- // Only allowed for pseudo draft roots (entities with this action)
63
- if (isRoot && !req.target['@Common.DraftRoot.ActivationAction']) req.reject(403, 'DRAFT_MODIFICATION_ONLY_VIA_ROOT')
64
-
65
- const navigationToMany = isNavigationToMany(req, this.model)
66
-
67
- const adminDataCQN = navigationToMany
68
- ? _getUpdateDraftAdminCQN(req, req.data.DraftAdministrativeData_DraftUUID)
69
- : _getInsertDraftAdminCQN(req, req.data.DraftAdministrativeData_DraftUUID)
70
- const insertDataCQN = _getInsertDataCQN(req, req.data.DraftAdministrativeData_DraftUUID)
71
-
72
- const dbtx = cds.tx(req)
73
-
74
- await Promise.all([dbtx.run(adminDataCQN), dbtx.run(insertDataCQN)])
75
-
76
- req._.readAfterWrite = true
77
- return { ...req.data, IsActiveEntity: false }
78
- }
79
-
80
- module.exports = cds.service.impl(function (srv) {
81
- srv.on('NEW', '*', fioriGenericNew)
82
- })
@@ -1,101 +0,0 @@
1
- const cds = require('../../cds')
2
- const { UPDATE, SELECT } = cds.ql
3
-
4
- const { getUpdateDraftAdminCQN, ensureDraftsSuffix } = require('../utils/handler')
5
- const { removeIsActiveEntityRecursively } = require('../utils/where')
6
- const { deepCopyArray } = require('../../common/utils/copy')
7
- const { cqn2cqn4sql } = require('../../common/utils/cqn2cqn4sql')
8
-
9
- const _getSelectCQN = ({ query }) => {
10
- const fromRef = deepCopyArray(query.UPDATE.entity.ref)
11
- for (const item of fromRef) {
12
- if (item.where) {
13
- item.where = removeIsActiveEntityRecursively(item.where)
14
- }
15
- }
16
- fromRef[0].id = ensureDraftsSuffix(fromRef[0].id)
17
- const from = { ref: fromRef }
18
-
19
- return SELECT.from(from)
20
- }
21
-
22
- const _getUpdateDraftCQN = ({ query }, where, targetRef) => {
23
- const set = {}
24
-
25
- for (const entry in query.UPDATE.data) {
26
- if (entry === 'DraftAdministrativeData_DraftUUID') {
27
- continue
28
- }
29
-
30
- set[entry] = query.UPDATE.data[entry]
31
- }
32
-
33
- if (set.IsActiveEntity) set.IsActiveEntity = false
34
-
35
- return UPDATE(targetRef).data(set).where(where)
36
- }
37
-
38
- const _joinDraftAdministrativeData = (selectResolved, target) => {
39
- const columns = []
40
- columns.push({ ref: ['DRAFT.DraftAdministrativeData', 'inProcessByUser'], as: 'draftAdmin_inProcessByUser' })
41
- columns.push({ ref: [target, 'DraftAdministrativeData_DraftUUID'] })
42
-
43
- return selectResolved
44
- .columns(columns)
45
- .join('DRAFT.DraftAdministrativeData')
46
- .on([
47
- { ref: [target, 'DraftAdministrativeData_DraftUUID'] },
48
- '=',
49
- { ref: ['DRAFT.DraftAdministrativeData', 'DraftUUID'] }
50
- ])
51
- }
52
-
53
- /**
54
- * Generic Handler for PATCH requests in the context of draft.
55
- * In case of success it returns the updated entry.
56
- * If the entry to be updated does not exist, it rejects with error to return a 404.
57
- * If a draft is already in process of another user it rejects with 403.
58
- *
59
- * @param req
60
- */
61
- const fioriGenericPatch = async function (req, next) {
62
- if (!req.target._isDraftEnabled) return next()
63
-
64
- if (req.data.IsActiveEntity === true) req.reject(400, 'Patch can only be applied to a draft entity')
65
-
66
- if (!cds.db) req.reject('NO_DATABASE_CONNECTION')
67
-
68
- const dbtx = cds.tx(req)
69
-
70
- const selectResolved = cqn2cqn4sql(_getSelectCQN(req), this.model)
71
-
72
- const targetName = selectResolved.SELECT.from.ref[selectResolved.SELECT.from.ref.length - 1]
73
- const alias = selectResolved.SELECT.from.as
74
- const selectWithAdmin = _joinDraftAdministrativeData(selectResolved, alias || targetName)
75
-
76
- if (req._etagValidationClause) selectWithAdmin.where(removeIsActiveEntityRecursively(req._etagValidationClause))
77
-
78
- const results = await dbtx.run(selectWithAdmin)
79
-
80
- if (results.length === 0) req.reject(req._etagValidationType ? 412 : 404)
81
-
82
- const result = results[0]
83
-
84
- // Potential timeout scenario supported
85
- if (result.draftAdmin_inProcessByUser && result.draftAdmin_inProcessByUser !== req.user.id) req.reject(403)
86
-
87
- const updateDraftCQN = _getUpdateDraftCQN(req, selectResolved.SELECT.where, {
88
- ref: [targetName],
89
- as: alias || targetName
90
- })
91
- const updateDraftAdminCQN = getUpdateDraftAdminCQN(req, result.DraftAdministrativeData_DraftUUID)
92
-
93
- await Promise.all([dbtx.run(updateDraftCQN), dbtx.run(updateDraftAdminCQN)])
94
- req._.readAfterWrite = true
95
-
96
- return { ...req.data, IsActiveEntity: false }
97
- }
98
-
99
- module.exports = cds.service.impl(function (srv) {
100
- srv.on('PATCH', '*', fioriGenericPatch)
101
- })
@@ -1,57 +0,0 @@
1
- const cds = require('../../cds')
2
- const { SELECT } = cds.ql
3
-
4
- const { isActiveEntityRequested } = require('../utils/where')
5
- const { ensureDraftsSuffix, ensureNoDraftsSuffix } = require('../utils/handler')
6
- const { getColumns } = require('../../common/utils/columns')
7
-
8
- /**
9
- * Generic Handler for PreparationAction requests.
10
- * In case of success it returns the prepared draft entry.
11
- *
12
- * @param req
13
- */
14
- const fioriGenericPrepare = async function (req, next) {
15
- if (!req.target._isDraftEnabled) return next()
16
-
17
- if (req.query.SELECT.from.ref.length > 1 || isActiveEntityRequested(req.query.SELECT.from.ref[0].where || [])) {
18
- req.reject(400, 'Action "draftPrepare" can only be called on a draft entity')
19
- }
20
-
21
- if (!cds.db) req.reject('NO_DATABASE_CONNECTION')
22
-
23
- const target = ensureDraftsSuffix(req.target.name)
24
-
25
- const columns = getColumns(this.model.definitions[ensureNoDraftsSuffix(req.target.name)], {
26
- keysOnly: true,
27
- removeIgnore: true,
28
- filterVirtual: true,
29
- onlyNames: true
30
- })
31
- columns.push({ ref: ['DRAFT.DraftAdministrativeData', 'inProcessByUser'], as: 'draftAdmin_inProcessByUser' })
32
-
33
- const select = SELECT.one(target)
34
- .columns(columns)
35
- .join('DRAFT.DraftAdministrativeData')
36
- .on([
37
- { ref: [target, 'DraftAdministrativeData_DraftUUID'] },
38
- '=',
39
- { ref: ['DRAFT.DraftAdministrativeData', 'DraftUUID'] }
40
- ])
41
- .where(req.query.SELECT.from.ref[0].where)
42
-
43
- const result = await cds.tx(req).run(select)
44
-
45
- if (!result) req.reject(404)
46
-
47
- if (result.draftAdmin_inProcessByUser !== req.user.id)
48
- req.reject(403, 'DRAFT_LOCKED_BY_ANOTHER_USER', [result.draftAdmin_inProcessByUser])
49
-
50
- delete result.draftAdmin_inProcessByUser
51
-
52
- return result
53
- }
54
-
55
- module.exports = cds.service.impl(function (srv) {
56
- srv.on('draftPrepare', '*', fioriGenericPrepare)
57
- })