@sap/cds 7.9.4 → 8.0.4

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 (276) hide show
  1. package/CHANGELOG.md +128 -3659
  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 +9 -41
  15. package/lib/auth/index.js +1 -14
  16. package/lib/auth/jwt-auth.js +10 -40
  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/yaml.js +3 -3
  32. package/lib/dbs/cds-deploy.js +4 -2
  33. package/lib/env/cds-env.js +10 -14
  34. package/lib/env/cds-requires.js +30 -13
  35. package/lib/env/defaults.js +46 -16
  36. package/lib/env/plugins.js +1 -1
  37. package/lib/env/schemas/cds-rc.js +8 -4
  38. package/lib/env/schemas/index.js +7 -7
  39. package/lib/env/serviceBindings.js +1 -1
  40. package/lib/index.js +12 -10
  41. package/lib/lazy.js +1 -1
  42. package/lib/linked/classes.js +36 -8
  43. package/lib/linked/entities.js +2 -10
  44. package/lib/linked/models.js +2 -1
  45. package/lib/linked/validate.js +292 -0
  46. package/lib/log/cds-error.js +0 -6
  47. package/lib/log/cds-log.js +3 -3
  48. package/lib/log/format/json.js +1 -1
  49. package/lib/log/service/index.js +0 -1
  50. package/lib/plugins.js +2 -2
  51. package/lib/ql/Query.js +2 -10
  52. package/lib/ql/SELECT.js +1 -1
  53. package/lib/ql/Whereable.js +3 -2
  54. package/lib/req/cds-context.js +14 -25
  55. package/lib/req/context.js +23 -25
  56. package/lib/req/request.js +1 -34
  57. package/lib/req/user.js +47 -35
  58. package/lib/srv/bindings.js +1 -1
  59. package/lib/srv/cds-connect.js +4 -4
  60. package/lib/srv/cds-serve.js +2 -2
  61. package/lib/srv/factory.js +1 -1
  62. package/lib/srv/middlewares/cds-context.js +11 -22
  63. package/lib/srv/middlewares/ctx-model.js +2 -3
  64. package/lib/srv/middlewares/errors.js +41 -8
  65. package/lib/srv/middlewares/index.js +3 -3
  66. package/lib/srv/middlewares/trace.js +0 -2
  67. package/lib/srv/protocols/hcql.js +15 -10
  68. package/lib/srv/protocols/http.js +44 -49
  69. package/lib/srv/protocols/index.js +1 -23
  70. package/lib/srv/protocols/odata-v4.js +12 -74
  71. package/lib/srv/protocols/rest.js +1 -13
  72. package/lib/srv/srv-api.js +0 -20
  73. package/lib/srv/srv-dispatch.js +3 -2
  74. package/lib/srv/srv-handlers.js +22 -11
  75. package/lib/srv/srv-methods.js +2 -2
  76. package/lib/srv/srv-models.js +3 -36
  77. package/lib/test/expect.js +343 -0
  78. package/lib/test/index.js +2 -0
  79. package/lib/test/reporter.js +176 -0
  80. package/lib/utils/axios.js +10 -9
  81. package/lib/utils/cds-test.js +85 -36
  82. package/lib/utils/cds-utils.js +54 -7
  83. package/lib/utils/check-version.js +0 -4
  84. package/lib/utils/colors.js +49 -0
  85. package/lib/utils/data.js +5 -4
  86. package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +2 -7
  87. package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +3 -30
  88. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/error.js +6 -12
  89. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +1 -3
  90. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +0 -1
  91. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +4 -7
  92. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +12 -6
  93. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +2 -4
  94. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/applyToCQN.js +1 -0
  95. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/expandToCQN.js +1 -1
  96. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/index.js +0 -1
  97. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/readToCQN.js +1 -3
  98. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/utils.js +1 -1
  99. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/edm/AbstractEdmStructuredType.js +1 -2
  100. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/ResourceJsonDeserializer.js +5 -0
  101. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/serializer/ContextURLFactory.js +1 -1
  102. package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +9 -43
  103. package/libx/_runtime/cds-services/adapter/odata-v4/utils/metaInfo.js +0 -1
  104. package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +8 -3
  105. package/libx/_runtime/cds-services/adapter/odata-v4/utils/request.js +4 -2
  106. package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +1 -3
  107. package/libx/_runtime/cds-services/util/assert.js +1 -1
  108. package/libx/_runtime/cds.js +10 -3
  109. package/libx/_runtime/common/Service.js +12 -32
  110. package/libx/_runtime/common/aspects/any.js +1 -0
  111. package/libx/_runtime/common/code-ext/execute.js +1 -1
  112. package/libx/_runtime/common/code-ext/worker.js +0 -1
  113. package/libx/_runtime/common/composition/data.js +0 -1
  114. package/libx/_runtime/common/composition/delete.js +0 -1
  115. package/libx/_runtime/common/composition/tree.js +0 -1
  116. package/libx/_runtime/common/composition/update.js +3 -3
  117. package/libx/_runtime/common/error/frontend.js +21 -12
  118. package/libx/_runtime/common/error/log.js +36 -0
  119. package/libx/_runtime/common/error/utils.js +2 -5
  120. package/libx/_runtime/common/generic/auth/autoexpose.js +18 -17
  121. package/libx/_runtime/common/generic/auth/expand.js +1 -1
  122. package/libx/_runtime/common/generic/auth/readOnly.js +1 -2
  123. package/libx/_runtime/common/generic/auth/restrict.js +23 -42
  124. package/libx/_runtime/common/generic/auth/restrictions.js +2 -7
  125. package/libx/_runtime/common/generic/auth/utils.js +91 -88
  126. package/libx/_runtime/common/generic/crud.js +6 -5
  127. package/libx/_runtime/common/generic/etag.js +7 -12
  128. package/libx/_runtime/common/generic/input.js +70 -68
  129. package/libx/_runtime/common/generic/paging.js +1 -0
  130. package/libx/_runtime/common/generic/sorting.js +1 -0
  131. package/libx/_runtime/common/generic/temporal.js +8 -2
  132. package/libx/_runtime/common/i18n/index.js +1 -1
  133. package/libx/_runtime/common/i18n/messages.properties +3 -1
  134. package/libx/_runtime/common/utils/binary.js +8 -2
  135. package/libx/_runtime/common/utils/compareJson.js +5 -1
  136. package/libx/_runtime/common/utils/copy.js +6 -11
  137. package/libx/_runtime/common/utils/cqn2cqn4sql.js +16 -14
  138. package/libx/_runtime/common/utils/differ.js +3 -6
  139. package/libx/_runtime/common/utils/keys.js +77 -18
  140. package/libx/_runtime/common/utils/postProcess.js +12 -15
  141. package/libx/_runtime/common/utils/propagateForeignKeys.js +0 -1
  142. package/libx/_runtime/common/utils/resolveView.js +2 -3
  143. package/libx/_runtime/common/utils/restrictions.js +45 -17
  144. package/libx/_runtime/common/utils/rewriteAsterisks.js +1 -8
  145. package/libx/_runtime/common/utils/stream.js +3 -16
  146. package/libx/_runtime/common/utils/streamProp.js +8 -18
  147. package/libx/_runtime/common/utils/structured.js +1 -1
  148. package/libx/_runtime/common/utils/ucsn.js +0 -2
  149. package/libx/_runtime/db/Service.js +0 -72
  150. package/libx/_runtime/db/data-conversion/post-processing.js +0 -1
  151. package/libx/_runtime/db/expand/expandCQNToJoin.js +9 -9
  152. package/libx/_runtime/db/expand/rawToExpanded.js +0 -8
  153. package/libx/_runtime/db/generic/input.js +3 -8
  154. package/libx/_runtime/db/generic/rewrite.js +1 -0
  155. package/libx/_runtime/db/query/read.js +2 -2
  156. package/libx/_runtime/db/sql-builder/ExpressionBuilder.js +0 -1
  157. package/libx/_runtime/db/sql-builder/InsertBuilder.js +1 -1
  158. package/libx/_runtime/db/utils/columns.js +2 -6
  159. package/libx/_runtime/fiori/lean-draft.js +138 -56
  160. package/libx/_runtime/hana/Service.js +0 -1
  161. package/libx/_runtime/hana/driver.js +1 -1
  162. package/libx/_runtime/hana/dynatrace.js +1 -2
  163. package/libx/_runtime/hana/pool.js +11 -21
  164. package/libx/_runtime/hana/streaming.js +0 -1
  165. package/libx/_runtime/messaging/common-utils/AMQPClient.js +0 -1
  166. package/libx/_runtime/messaging/common-utils/authorizedRequest.js +1 -1
  167. package/libx/_runtime/messaging/common-utils/normalizeIncomingMessage.js +1 -1
  168. package/libx/_runtime/messaging/enterprise-messaging-utils/getTenantInfo.js +1 -1
  169. package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +19 -33
  170. package/libx/_runtime/messaging/event-broker.js +54 -27
  171. package/libx/_runtime/messaging/file-based.js +3 -3
  172. package/libx/_runtime/messaging/http-utils/token.js +1 -1
  173. package/libx/_runtime/messaging/kafka.js +2 -2
  174. package/libx/_runtime/messaging/redis-messaging.js +0 -1
  175. package/libx/_runtime/remote/Service.js +25 -25
  176. package/libx/_runtime/remote/utils/client.js +4 -5
  177. package/libx/_runtime/remote/utils/cloudSdkProvider.js +0 -3
  178. package/libx/_runtime/remote/utils/data.js +0 -1
  179. package/libx/_runtime/sqlite/Service.js +1 -2
  180. package/libx/_runtime/ucl/Service.js +37 -78
  181. package/libx/common/assert/index.js +22 -21
  182. package/libx/common/assert/type-relaxed.js +39 -0
  183. package/libx/common/assert/utils.js +3 -2
  184. package/libx/common/assert/validation.js +3 -8
  185. package/libx/common/utils/index.js +5 -0
  186. package/libx/common/utils/path.js +51 -0
  187. package/libx/odata/ODataAdapter.js +126 -0
  188. package/libx/odata/index.js +15 -2
  189. package/libx/odata/middleware/batch.js +320 -84
  190. package/libx/odata/middleware/body-parser.js +33 -0
  191. package/libx/odata/middleware/create.js +44 -59
  192. package/libx/odata/middleware/delete.js +23 -12
  193. package/libx/odata/middleware/error.js +30 -6
  194. package/libx/odata/middleware/metadata.js +38 -26
  195. package/libx/odata/middleware/operation.js +93 -69
  196. package/libx/odata/middleware/parse.js +6 -8
  197. package/libx/odata/middleware/read.js +117 -93
  198. package/libx/odata/middleware/service-document.js +22 -19
  199. package/libx/odata/middleware/stream.js +54 -56
  200. package/libx/odata/middleware/update.js +79 -87
  201. package/libx/odata/parse/afterburner.js +191 -175
  202. package/libx/odata/parse/cqn2odata.js +5 -5
  203. package/libx/odata/parse/grammar.peggy +27 -20
  204. package/libx/odata/parse/multipartToJson.js +17 -9
  205. package/libx/odata/parse/parser.js +1 -1
  206. package/libx/odata/utils/etag.js +14 -6
  207. package/libx/odata/utils/index.js +84 -12
  208. package/libx/odata/utils/metadata.js +161 -0
  209. package/libx/odata/utils/postProcess.js +89 -0
  210. package/libx/odata/utils/readAfterWrite.js +134 -17
  211. package/libx/odata/utils/result.js +36 -142
  212. package/libx/outbox/index.js +4 -3
  213. package/libx/rest/RestAdapter.js +115 -182
  214. package/libx/rest/middleware/create.js +28 -24
  215. package/libx/rest/middleware/delete.js +7 -10
  216. package/libx/rest/middleware/error.js +26 -16
  217. package/libx/rest/middleware/operation.js +48 -41
  218. package/libx/rest/middleware/parse.js +128 -126
  219. package/libx/rest/middleware/read.js +20 -27
  220. package/libx/rest/middleware/update.js +26 -31
  221. package/package.json +17 -8
  222. package/server.js +4 -2
  223. package/apis/cds.d.ts +0 -3
  224. package/apis/core.d.ts +0 -21
  225. package/apis/cqn.d.ts +0 -18
  226. package/apis/csn.d.ts +0 -21
  227. package/apis/events.d.ts +0 -18
  228. package/apis/internal/inference.d.ts +0 -18
  229. package/apis/linked.d.ts +0 -18
  230. package/apis/log.d.ts +0 -20
  231. package/apis/models.d.ts +0 -18
  232. package/apis/ql.d.ts +0 -18
  233. package/apis/reflect.d.ts +0 -32
  234. package/apis/server.d.ts +0 -18
  235. package/apis/services.d.ts +0 -22
  236. package/bin/cds-serve.js +0 -56
  237. package/lib/compile/to/gql.js +0 -15
  238. package/lib/srv/protocols/_legacy.js +0 -44
  239. package/lib/utils/jest.js +0 -43
  240. package/libx/_runtime/auth/index.js +0 -193
  241. package/libx/_runtime/auth/strategies/JWT.js +0 -37
  242. package/libx/_runtime/auth/strategies/basic.js +0 -20
  243. package/libx/_runtime/auth/strategies/dummy.js +0 -14
  244. package/libx/_runtime/auth/strategies/ias-auth.js +0 -1
  245. package/libx/_runtime/auth/strategies/mock.js +0 -77
  246. package/libx/_runtime/auth/strategies/xssecUtils.js +0 -93
  247. package/libx/_runtime/auth/strategies/xsuaa.js +0 -38
  248. package/libx/_runtime/common/perf/index.js +0 -19
  249. package/libx/_runtime/common/utils/ensureIEEE754.js +0 -29
  250. package/libx/_runtime/fiori/draft.js +0 -2
  251. package/libx/_runtime/fiori/generic/activate.js +0 -190
  252. package/libx/_runtime/fiori/generic/before.js +0 -201
  253. package/libx/_runtime/fiori/generic/cancel.js +0 -19
  254. package/libx/_runtime/fiori/generic/delete.js +0 -21
  255. package/libx/_runtime/fiori/generic/edit.js +0 -157
  256. package/libx/_runtime/fiori/generic/index.js +0 -25
  257. package/libx/_runtime/fiori/generic/new.js +0 -82
  258. package/libx/_runtime/fiori/generic/patch.js +0 -101
  259. package/libx/_runtime/fiori/generic/prepare.js +0 -57
  260. package/libx/_runtime/fiori/generic/read.js +0 -1340
  261. package/libx/_runtime/fiori/generic/readOverDraft.js +0 -146
  262. package/libx/_runtime/fiori/utils/csn.js +0 -13
  263. package/libx/_runtime/fiori/utils/delete.js +0 -114
  264. package/libx/_runtime/fiori/utils/handler.js +0 -264
  265. package/libx/_runtime/fiori/utils/lockInfo.js +0 -27
  266. package/libx/_runtime/fiori/utils/req.js +0 -23
  267. package/libx/_runtime/fiori/utils/stream.js +0 -36
  268. package/libx/_runtime/fiori/utils/where.js +0 -254
  269. package/libx/_runtime/index.js +0 -22
  270. package/libx/odata/utils/handler.js +0 -120
  271. package/libx/odata/utils/metaInfo.js +0 -410
  272. package/libx/odata/utils/path.js +0 -75
  273. package/libx/rest/RestRequest.js +0 -32
  274. package/libx/rest/index.js +0 -3
  275. package/libx/rest/readme.md +0 -1
  276. /package/libx/common/assert/{type.js → type-strict.js} +0 -0
@@ -1,13 +1,14 @@
1
1
  const cds = require('../cds'),
2
2
  { Object_keys } = cds.utils
3
+
3
4
  const { getTransition } = require('../common/utils/resolveView')
4
- const { getKeyData } = require('./utils/where')
5
5
 
6
6
  const { getPageSize, commonGenericPaging } = require('../common/generic/paging')
7
7
  const { handler: commonGenericSorting } = require('../common/generic/sorting')
8
8
  const { addEtagColumns } = require('../common/utils/etag')
9
9
 
10
10
  const { calculateLocationHeader } = require('../../odata/utils')
11
+ const { handleStreamProperties } = require('../common/utils/streamProp')
11
12
 
12
13
  const LOG = cds.log('fiori|drafts')
13
14
  const original = Symbol('original')
@@ -17,17 +18,22 @@ const AGGREGATION_FUNCTIONS = ['sum', 'min', 'max', 'avg', 'count']
17
18
  const calcTimeMs = timeout => {
18
19
  const match = timeout.match(/^([0-9]+)(w|d|h|hrs|min)$/)
19
20
  if (!match) return
21
+
20
22
  const [, val, t] = match
21
23
  switch (t) {
22
24
  case 'w':
23
25
  return val * 1000 * 3600 * 24 * 7
26
+
24
27
  case 'd':
25
28
  return val * 1000 * 3600 * 24
29
+
26
30
  case 'h':
27
31
  case 'hrs':
28
32
  return val * 1000 * 3600
33
+
29
34
  case 'min':
30
35
  return val * 1000 * 60
36
+
31
37
  default:
32
38
  return val
33
39
  }
@@ -64,12 +70,6 @@ const LOCK_TIMEOUT = {
64
70
  get value() {
65
71
  let timeout_ms = _config_to_ms('draft_lock_timeout', '15min')
66
72
 
67
- const deprecated = cds.env.drafts?.cancellationTimeout // in min
68
- if (deprecated) {
69
- // in order to still support legacy use cases for tests, e. g. 0.000001
70
- timeout_ms = deprecated * 1000 * 60
71
- }
72
-
73
73
  Object.defineProperty(LOCK_TIMEOUT, 'value', { value: timeout_ms })
74
74
  return timeout_ms
75
75
  }
@@ -78,7 +78,7 @@ const LOCK_TIMEOUT = {
78
78
  const reject_bypassed_draft = req => {
79
79
  const message =
80
80
  !cds.profiles?.includes('production') &&
81
- '`cds.env.fiori.bypass_draft` must be enabled or the entity must be annotated with `@odata.draft.bypass` to support the directly modification of active instances.'
81
+ '`cds.env.fiori.bypass_draft` must be enabled or the entity must be annotated with `@odata.draft.bypass` to support direct modifications of active instances.'
82
82
  return req.reject({ code: 501, statusCode: 501, message })
83
83
  }
84
84
 
@@ -107,6 +107,34 @@ const DRAFT_ADMIN_ELEMENTS = [
107
107
  const numericCollator = { numeric: true }
108
108
  const emptyObject = {}
109
109
 
110
+ const _isKeyValue = (i, keys, where) => {
111
+ if (!where[i].ref || !keys.includes(where[i].ref[0])) {
112
+ return false
113
+ }
114
+
115
+ return where[i + 1] === '=' && 'val' in where[i + 2]
116
+ }
117
+
118
+ const _getKeyData = (keys, where) => {
119
+ if (!where) {
120
+ return {}
121
+ }
122
+
123
+ const data = {}
124
+ let i = 0
125
+
126
+ while (where[i]) {
127
+ if (_isKeyValue(i, keys, where)) {
128
+ data[where[i].ref[0]] = where[i + 2].val
129
+ i = i + 3
130
+ } else {
131
+ i++
132
+ }
133
+ }
134
+
135
+ return data
136
+ }
137
+
110
138
  const _fillIsActiveEntity = (row, IsActiveEntity, target) => {
111
139
  if (target.drafts) row.IsActiveEntity = IsActiveEntity
112
140
  for (const key in target.associations) {
@@ -131,7 +159,7 @@ const _filterResultSet = (resultSet, limit, offset) => {
131
159
  return pageResultSet
132
160
  }
133
161
 
134
- /// It's important to wait for the completion of all promises, otherwise a rollback might happen too soon
162
+ // It's important to wait for the completion of all promises, otherwise a rollback might happen too soon
135
163
  const _promiseAll = async array => {
136
164
  const results = await Promise.allSettled(array)
137
165
  const firstRejected = results.find(response => response.status === 'rejected')
@@ -178,31 +206,36 @@ const _redirectRefToActives = (ref, model) => {
178
206
  return [root.id ? { ...root, id: active.name } : active.name, ...tail]
179
207
  }
180
208
 
181
- let lastCheckMap = new Map()
209
+ const lastCheckMap = new Map()
182
210
  const _cleanUpOldDrafts = async (service, tenant) => {
183
211
  if (!DEL_TIMEOUT.value) return
184
212
 
185
- const invalDate = new Date(Date.now() - DEL_TIMEOUT.value).toISOString()
213
+ const expiryDate = new Date(Date.now() - DEL_TIMEOUT.value).toISOString()
186
214
  const interval = DEL_TIMEOUT.value / 2
187
215
  const lastCheck = lastCheckMap.get(tenant)
188
216
 
189
217
  if (lastCheck && Date.now() - lastCheck < Number(interval)) return
190
218
 
191
219
  cds.spawn({ tenant, user: cds.User.privileged }, async () => {
192
- let invalDrafts = await SELECT.from('DRAFT.DraftAdministrativeData', ['DraftUUID']).where(
220
+ const expiredDrafts = await SELECT.from('DRAFT.DraftAdministrativeData', ['DraftUUID']).where(
193
221
  `LastChangeDateTime <`,
194
- invalDate
222
+ expiryDate
195
223
  )
196
- if (!invalDrafts.length) return
197
- invalDrafts = invalDrafts.map(el => el.DraftUUID)
224
+
225
+ if (!expiredDrafts.length) return
226
+
227
+ const expiredDraftsIds = expiredDrafts.map(el => el.DraftUUID)
198
228
  const cqns = []
229
+
199
230
  for (let name in service.model.definitions) {
200
231
  const target = service.model.definitions[name]
201
- if (target.drafts && target['@Common.DraftRoot.ActivationAction'])
202
- cqns.push(DELETE.from(target.drafts).where(`DraftAdministrativeData_DraftUUID IN`, invalDrafts))
232
+ if (target.drafts && target['@Common.DraftRoot.ActivationAction']) {
233
+ cqns.push(DELETE.from(target.drafts).where(`DraftAdministrativeData_DraftUUID IN`, expiredDraftsIds))
234
+ }
203
235
  }
204
- cqns.push(DELETE.from('DRAFT.DraftAdministrativeData').where(`DraftUUID IN`, invalDrafts))
205
- await _promiseAll(cqns)
236
+
237
+ cqns.push(DELETE.from('DRAFT.DraftAdministrativeData').where(`DraftUUID IN`, expiredDraftsIds))
238
+ return await _promiseAll(cqns)
206
239
  })
207
240
 
208
241
  lastCheckMap.set(tenant, Date.now())
@@ -210,7 +243,6 @@ const _cleanUpOldDrafts = async (service, tenant) => {
210
243
 
211
244
  const h = cds.ApplicationService.prototype.handle
212
245
 
213
- /* eslint-disable complexity */
214
246
  cds.ApplicationService.prototype.handle = async function (req) {
215
247
  const handle = h.bind(this)
216
248
 
@@ -327,9 +359,14 @@ cds.ApplicationService.prototype.handle = async function (req) {
327
359
 
328
360
  if (req.event === 'draftEdit') req.event = 'EDIT'
329
361
 
330
- if (req.event === 'NEW' || req.event === 'CANCEL' || req.event === 'draftPrepare') {
362
+ if (
363
+ req.event === 'NEW' ||
364
+ req.event === 'CANCEL' ||
365
+ req.event === 'draftPrepare' ||
366
+ (req.event === 'CREATE' && req.target._isDraftEnabled)
367
+ ) {
331
368
  if (req.event === 'draftPrepare' && draftParams.IsActiveEntity) req.reject({ code: 400, statusCode: 400 })
332
- if (req.event === 'NEW' && req.data?.IsActiveEntity === true) {
369
+ if ((req.event === 'NEW' || req.event === 'CREATE') && req.data?.IsActiveEntity === true) {
333
370
  if (!cds.env.fiori.bypass_draft && !req.target['@odata.draft.bypass']) return reject_bypassed_draft(req)
334
371
  const containsDraftRoot =
335
372
  this.model.definitions[query.INSERT.into?.ref?.[0]?.id || query.INSERT.into?.ref?.[0] || query.INSERT.into][
@@ -364,17 +401,33 @@ cds.ApplicationService.prototype.handle = async function (req) {
364
401
 
365
402
  const cqn = INSERT.into(query.INSERT.into).entries(data)
366
403
  await run(cqn, { event: 'CREATE' })
367
- return { ...data, IsActiveEntity: true }
404
+ const result = { ...data, IsActiveEntity: true }
405
+ req.data = result //> make keys available via req.data (as with normal crud)
406
+ return result
368
407
  }
369
408
  req.target = req.target.drafts
370
409
 
371
410
  if (query.INSERT?.into) {
372
411
  if (typeof query.INSERT.into === 'string') query.INSERT.into = req.target.name
373
412
  else if (query.INSERT.into.ref) query.INSERT.into.ref = _redirectRefToDrafts(query.INSERT.into.ref, this.model)
374
- } else if (query.DELETE?.from?.ref) query.DELETE.from.ref = _redirectRefToDrafts(query.DELETE.from.ref, this.model)
375
- else if (query.SELECT?.from?.ref) query.SELECT.from.ref = _redirectRefToDrafts(query.SELECT.from.ref, this.model)
413
+ } else if (query.DELETE?.from?.ref) {
414
+ query.DELETE.from.ref = _redirectRefToDrafts(query.DELETE.from.ref, this.model)
415
+ } else if (query.SELECT?.from?.ref) {
416
+ query.SELECT.from.ref = _redirectRefToDrafts(query.SELECT.from.ref, this.model)
417
+ }
418
+
376
419
  const _req = _newReq(req, query, draftParams, { event: req.event })
420
+
421
+ if (
422
+ (req.event === 'NEW' || req.event === 'CREATE') &&
423
+ draftParams.IsActiveEntity === false &&
424
+ !_req.target.isDraft
425
+ ) {
426
+ req.reject({ code: 403, statusCode: 403, message: 'ACTIVE_MODIFICATION_VIA_DRAFT' })
427
+ }
428
+
377
429
  const result = await handle(_req)
430
+ req.data = result //> make keys available via req.data (as with normal crud)
378
431
  return result
379
432
  }
380
433
 
@@ -422,7 +475,7 @@ cds.ApplicationService.prototype.handle = async function (req) {
422
475
  }
423
476
 
424
477
  const targetDraft = req.target.drafts
425
- const cols = expandStarStar(targetDraft)
478
+ const cols = expandStarStar(targetDraft, true)
426
479
 
427
480
  // Use `run` (since also etags might need to be checked)
428
481
  // REVISIT: Find a better approach (`etag` as part of CQN?)
@@ -447,25 +500,13 @@ cds.ApplicationService.prototype.handle = async function (req) {
447
500
  args: [res.DraftAdministrativeData?.InProcessByUser]
448
501
  })
449
502
  }
503
+
450
504
  const DraftAdministrativeData_DraftUUID = res.DraftAdministrativeData_DraftUUID
451
505
  delete res.DraftAdministrativeData_DraftUUID
452
506
  delete res.DraftAdministrativeData
453
507
  const HasActiveEntity = res.HasActiveEntity
454
508
  delete res.HasActiveEntity
455
509
 
456
- if (cds.env.features.cds_assert) {
457
- const assertOptions = { path: [req.target.actions[req.event]['@cds.odata.bindingparameter.name'] || 'in'] }
458
- const errs = cds.assert(res, req.target, assertOptions)
459
- if (errs) {
460
- if (errs.length === 1) throw Object.assign(errs[0], { '@Common.numericSeverity': 4 })
461
- throw Object.assign(new Error('MULTIPLE_ERRORS'), {
462
- statusCode: 400,
463
- details: errs,
464
- '@Common.numericSeverity': 4 //> TODO: should not be needed here
465
- })
466
- }
467
- }
468
-
469
510
  // First run the handlers as they might need access to DraftAdministrativeData or the draft entities
470
511
  const result = await run(
471
512
  HasActiveEntity
@@ -490,7 +531,11 @@ cds.ApplicationService.prototype.handle = async function (req) {
490
531
  }
491
532
 
492
533
  if (cds.env.features.odata_new_adapter) {
493
- const read_result = await _readAfterDraftAction.bind(this)({ req, payload: res, action: 'draftActivate' })
534
+ const read_result = await _readAfterDraftAction.bind(this)({
535
+ req,
536
+ payload: res,
537
+ action: 'draftActivate'
538
+ })
494
539
  req.res.set(
495
540
  'location',
496
541
  '../' + calculateLocationHeader(req.target, this, read_result || { ...res, IsActiveEntity: true })
@@ -517,11 +562,12 @@ cds.ApplicationService.prototype.handle = async function (req) {
517
562
  return result
518
563
  }
519
564
 
520
- if (req.event === 'PATCH') {
565
+ if (req.event === 'PATCH' || (req.event === 'UPDATE' && req.target.drafts)) {
521
566
  if (!('IsActiveEntity' in draftParams)) req.reject({ code: 501, statusCode: 501 })
522
567
 
523
568
  if (draftParams.IsActiveEntity === false) {
524
569
  LOG.debug('patch draft')
570
+
525
571
  if (req.target?.name.endsWith('DraftAdministrativeData')) req.reject({ code: 405, statusCode: 405 })
526
572
  const draftsRef = _redirectRefToDrafts(query.UPDATE.entity.ref, this.model)
527
573
  const res = await SELECT.one.from({ ref: draftsRef }).columns('DraftAdministrativeData_DraftUUID', {
@@ -570,6 +616,10 @@ cds.ApplicationService.prototype.handle = async function (req) {
570
616
  return req.data
571
617
  }
572
618
 
619
+ if (req.event === 'CREATE' && draftParams.IsActiveEntity === false && !req.target.isDraft) {
620
+ req.reject({ code: 403, statusCode: 403, message: 'ACTIVE_MODIFICATION_VIA_DRAFT' })
621
+ }
622
+
573
623
  req.query = query
574
624
 
575
625
  return handle(req)
@@ -604,6 +654,7 @@ const _requested = (result, query) => {
604
654
  const Read = {
605
655
  onlyActives: async function (run, query, { ignoreDrafts } = {}) {
606
656
  LOG.debug('List Editing Status: Only Active')
657
+
607
658
  // DraftAdministrativeData is only accessible via drafts
608
659
  if (_isCount(query)) return run(query)
609
660
  if (query._target.name.endsWith('.DraftAdministrativeData')) return run(query._drafts)
@@ -626,7 +677,7 @@ const Read = {
626
677
  else {
627
678
  try {
628
679
  drafts = await Read.complementaryDrafts(query, actives)
629
- } catch (e) {
680
+ } catch {
630
681
  drafts = []
631
682
  }
632
683
  }
@@ -646,6 +697,7 @@ const Read = {
646
697
 
647
698
  unchanged: async function (run, query) {
648
699
  LOG.debug('List Editing Status: Unchanged')
700
+
649
701
  const draftsQuery = query._drafts
650
702
  if (!draftsQuery) throw new Error('Invalid draft request')
651
703
  draftsQuery.SELECT.count = undefined
@@ -697,6 +749,7 @@ const Read = {
697
749
 
698
750
  all: async function (run, query) {
699
751
  LOG.debug('List Editing Status: All')
752
+
700
753
  if (!query._drafts) return []
701
754
 
702
755
  query._drafts.SELECT.count = false
@@ -890,11 +943,13 @@ const Read = {
890
943
 
891
944
  unsavedChangesByAnotherUser: async function (run, query) {
892
945
  LOG.debug('List Editing Status: Unsaved Changes by Another User')
946
+
893
947
  return Read.activesFromDrafts(run, query, { isLocked: false })
894
948
  },
895
949
 
896
950
  lockedByAnotherUser: async function (run, query) {
897
951
  LOG.debug('List Editing Status: Locked by Another User')
952
+
898
953
  return Read.activesFromDrafts(run, query, { isLocked: true })
899
954
  },
900
955
 
@@ -904,10 +959,19 @@ const Read = {
904
959
  const keys = entity_keys(target)
905
960
  const dataArray = data ? (Array.isArray(data) ? data : [data]) : []
906
961
  if (not && !dataArray.length) return []
907
- const left = { list: keys.map(k => ({ ref: [k] })) }
908
- const op = not ? ['not', 'in'] : ['in']
909
- const right = { list: dataArray.map(r => ({ list: keys.map(k => ({ val: r[k] })) })) }
910
- return [left, ...op, right]
962
+ if (keys.length === 1) {
963
+ // For single keys, make it nicer (without unnecessary lists)
964
+ const key = keys[0]
965
+ const left = { ref: [key] }
966
+ const op = not ? ['not', 'in'] : ['in']
967
+ const right = { list: dataArray.map(r => ({ val: r[key] })) }
968
+ return [left, ...op, right]
969
+ } else {
970
+ const left = { list: keys.map(k => ({ ref: [k] })) }
971
+ const op = not ? ['not', 'in'] : ['in']
972
+ const right = { list: dataArray.map(r => ({ list: keys.map(k => ({ val: r[k] })) })) }
973
+ return [left, ...op, right]
974
+ }
911
975
  },
912
976
 
913
977
  complementaryDrafts: (query, _actives) => {
@@ -1008,6 +1072,7 @@ function _cleansed(query, model) {
1008
1072
  const getDrafts = () => {
1009
1073
  const draftsQuery = _cleanseQuery(query, {}, model) // could just clone `q` but the latter is ruined by database layer
1010
1074
  draftsQuery._target = undefined
1075
+ if (!draftsQuery.SELECT.from.ref) return // invalid draft request
1011
1076
  const [root, ...tail] = draftsQuery.SELECT.from.ref
1012
1077
  const draft = model.definitions[root.id || root].drafts
1013
1078
  if (!draft) return
@@ -1187,12 +1252,14 @@ function _cleansed(query, model) {
1187
1252
  }
1188
1253
 
1189
1254
  // This function is better defined on DB layer
1190
- function expandStarStar(target, recursion = new Map()) {
1255
+ function expandStarStar(target, draftActivate, recursion = new Map()) {
1191
1256
  const MAX_RECURSION_DEPTH = (cds.env.features.recursion_depth && Number(cds.env.features.recursion_depth)) || 4
1192
1257
  const columns = []
1193
1258
  for (const el in target.elements) {
1194
1259
  const element = target.elements[el]
1195
- if (!element.isAssociation && !DRAFT_ELEMENTS.has(el) && !element['@odata.draft.skip']) columns.push({ ref: [el] })
1260
+ const skip_managed = draftActivate && (element['@cds.on.insert'] || element['@cds.on.update'])
1261
+ if (!skip_managed && !element.isAssociation && !DRAFT_ELEMENTS.has(el) && !element['@odata.draft.skip'])
1262
+ columns.push({ ref: [el] })
1196
1263
  if (!element.isComposition || element._target['@odata.draft.enabled'] === false) continue // happens for texts if not @fiori.draft.enabled
1197
1264
  const _key = target.name + ':' + el
1198
1265
  let cache = recursion.get(_key)
@@ -1204,7 +1271,7 @@ function expandStarStar(target, recursion = new Map()) {
1204
1271
  recursion.set(_key, cache)
1205
1272
  }
1206
1273
  if (cache >= MAX_RECURSION_DEPTH) return
1207
- const expand = expandStarStar(element._target, recursion)
1274
+ const expand = expandStarStar(element._target, draftActivate, recursion)
1208
1275
  if (expand) columns.push({ ref: [el], expand })
1209
1276
  }
1210
1277
  return columns
@@ -1212,6 +1279,7 @@ function expandStarStar(target, recursion = new Map()) {
1212
1279
 
1213
1280
  async function onNew(req) {
1214
1281
  LOG.debug('new draft')
1282
+
1215
1283
  if (req.target.actives['@Capabilities.InsertRestrictions.Insertable'] === false || req.target.actives['@readonly'])
1216
1284
  req.reject({ code: 405, statusCode: 405 })
1217
1285
  const isDirectAccess = typeof req.query.INSERT.into === 'string' || req.query.INSERT.into.ref?.length === 1
@@ -1284,7 +1352,11 @@ async function onNew(req) {
1284
1352
  const draftCQN = INSERT.into(req.target).entries(draftData)
1285
1353
 
1286
1354
  await _promiseAll([adminDataCQN, this.run(draftCQN)])
1287
- req._.readAfterWrite = true
1355
+
1356
+ // flag to trigger read after write in legacy odata adapter
1357
+ if (req.constructor.name in { ODataRequest: 1 }) req._.readAfterWrite = true
1358
+ if (req.protocol?.match(/odata/)) req._.readAfterWrite = true //> REVISIT for noah
1359
+
1288
1360
  return { ...draftData, IsActiveEntity: false }
1289
1361
  }
1290
1362
 
@@ -1354,7 +1426,7 @@ async function onEdit(req) {
1354
1426
  // concurrently.
1355
1427
  if (this._datasource === cds.db) {
1356
1428
  const keys = entity_keys(req.target)
1357
- const keyData = getKeyData(keys, req.query.SELECT.from.ref[0].where)
1429
+ const keyData = _getKeyData(keys, req.query.SELECT.from.ref[0].where)
1358
1430
  const rootWhere = keys.reduce((res, key) => {
1359
1431
  res[key] = keyData[key]
1360
1432
  return res
@@ -1382,7 +1454,7 @@ async function onEdit(req) {
1382
1454
 
1383
1455
  try {
1384
1456
  await this.run(activeLockCQN)
1385
- } catch (e) {
1457
+ } catch {
1386
1458
  const draft = await this.run(existingDraft)
1387
1459
  if (draft) req.reject({ code: 409, statusCode: 409, message: 'DRAFT_ALREADY_EXISTS' })
1388
1460
  req.reject({ code: 409, statusCode: 409, message: 'ENTITY_LOCKED' })
@@ -1457,7 +1529,11 @@ async function onEdit(req) {
1457
1529
  }
1458
1530
 
1459
1531
  if (cds.env.features.odata_new_adapter) {
1460
- const read_result = await _readAfterDraftAction.bind(this)({ req, payload: res, action: 'draftEdit' })
1532
+ const read_result = await _readAfterDraftAction.bind(this)({
1533
+ req,
1534
+ payload: res,
1535
+ action: 'draftEdit'
1536
+ })
1461
1537
  req.res.set(
1462
1538
  'location',
1463
1539
  '../' + calculateLocationHeader(req.target, this, read_result || { ...res, IsActiveEntity: false })
@@ -1470,6 +1546,7 @@ async function onEdit(req) {
1470
1546
 
1471
1547
  async function onCancel(req) {
1472
1548
  LOG.debug('delete draft')
1549
+
1473
1550
  const activeRef = _redirectRefToActives(req.query.DELETE.from.ref, this.model)
1474
1551
  const draftParams = req.query[DRAFT_PARAMS]
1475
1552
 
@@ -1479,7 +1556,7 @@ async function onCancel(req) {
1479
1556
  'DraftAdministrativeData_DraftUUID',
1480
1557
  { ref: ['DraftAdministrativeData'], expand: [_inProcessByUserXpr(_lock.shiftedNow)] }
1481
1558
  ])
1482
- if (req._etagValidationClause) draftQuery.where(req._etagValidationClause)
1559
+ if (req._etagValidationClause && draftParams.IsActiveEntity === false) draftQuery.where(req._etagValidationClause)
1483
1560
  // do not add InProcessByUser restriction
1484
1561
  const draft = await draftQuery
1485
1562
  if (draftParams.IsActiveEntity === false && !draft) req.reject(req._etagValidationType ? 412 : 404)
@@ -1488,7 +1565,10 @@ async function onCancel(req) {
1488
1565
  if (processByUser && processByUser !== cds.context.user.id)
1489
1566
  req.reject({ code: 403, statusCode: 403, message: 'DRAFT_LOCKED_BY_ANOTHER_USER', args: [processByUser] })
1490
1567
  }
1491
- const queries = !draft ? [] : [this.run(DELETE.from({ ref: req.query.DELETE.from.ref }), req.data)]
1568
+ const draftDeleteQuery = DELETE.from({ ref: req.query.DELETE.from.ref })
1569
+ const queries = !draft
1570
+ ? []
1571
+ : [draftParams.IsActiveEntity === false ? this.run(draftDeleteQuery, req.data) : draftDeleteQuery]
1492
1572
  if (draft && req.target['@Common.DraftRoot.ActivationAction'])
1493
1573
  // only for draft root
1494
1574
  queries.push(
@@ -1504,13 +1584,14 @@ async function onCancel(req) {
1504
1584
  })
1505
1585
  .where({ DraftUUID: draft.DraftAdministrativeData_DraftUUID })
1506
1586
  )
1507
- if (draftParams.IsActiveEntity) queries.push(this.run(DELETE.from({ ref: activeRef })))
1587
+ if (draftParams.IsActiveEntity !== false) queries.push(this.run(DELETE.from({ ref: activeRef })))
1508
1588
  await _promiseAll(queries)
1509
1589
  return req.data
1510
1590
  }
1511
1591
 
1512
1592
  async function onPrepare(req) {
1513
1593
  LOG.debug('prepare draft')
1594
+
1514
1595
  const draftParams = req.query[DRAFT_PARAMS]
1515
1596
  if (req.query.SELECT.from.ref.length > 1 || draftParams.IsActiveEntity !== false) {
1516
1597
  req.reject({
@@ -1565,6 +1646,7 @@ const _readAfterDraftAction = async function ({ req, payload, action }) {
1565
1646
  })
1566
1647
  // also ensure selection of etag columns
1567
1648
  addEtagColumns(read.SELECT.columns, entity)
1649
+ handleStreamProperties(entity, read.SELECT.columns, this.model)
1568
1650
  }
1569
1651
 
1570
1652
  try {
@@ -122,7 +122,6 @@ class HanaDatabase extends DatabaseService {
122
122
  /*
123
123
  * connection
124
124
  */
125
- // eslint-disable-next-line complexity
126
125
  async acquire(arg) {
127
126
  const tenant = arg && (typeof arg === 'string' ? arg : arg.tenant)
128
127
  const dbc = await pool.acquire(tenant, this)
@@ -137,7 +137,7 @@ const _getHanaDriver = name => {
137
137
  let packageJson
138
138
  try {
139
139
  packageJson = require(cds.root + '/package.json')
140
- } catch (e) {
140
+ } catch {
141
141
  LOG._debug && LOG.debug(`Could not find package.json. Trying to lookup hana driver automatically.`)
142
142
  name = 'hdb'
143
143
  }
@@ -1,9 +1,8 @@
1
1
  const dynatrace = {}
2
2
  try {
3
- // eslint-disable-next-line cds/no-missing-dependencies -- needs to be added by app dev
4
3
  dynatrace.sdk = require('@dynatrace/oneagent-sdk')
5
4
  dynatrace.api = dynatrace.sdk.createInstance()
6
- } catch (err) {
5
+ } catch {
7
6
  // If module was not required, do not do anything
8
7
  }
9
8
 
@@ -22,7 +22,6 @@ async function credentials4(tenant, db) {
22
22
  if (!credentials) throw new Error('No database credentials provided')
23
23
 
24
24
  if (cds.requires.multitenancy) {
25
- // eslint-disable-next-line cds/no-missing-dependencies
26
25
  const res = await require('@sap/cds-mtxs/lib').xt.serviceManager.get(tenant, { disableCache })
27
26
  return _getMassagedCreds(res.credentials)
28
27
  }
@@ -67,11 +66,6 @@ const _getPoolConfig = function () {
67
66
 
68
67
  // defaults
69
68
  if (!poolConfig) {
70
- if (process.env.NODE_ENV === 'production') {
71
- mergedConfig.acquireTimeoutMillis = 1000
72
- } else {
73
- mergedConfig.acquireTimeoutMillis = 10 * 1000
74
- }
75
69
  mergedConfig.softIdleTimeoutMillis = 30 * 1000
76
70
  mergedConfig.idleTimeoutMillis = 30 * 1000
77
71
  }
@@ -101,28 +95,24 @@ async function pool4(tenant, db) {
101
95
  LOG._info && LOG.info('effective pool configuration:', config)
102
96
  const p = pool.createPool(factory4(creds, tenant), config)
103
97
  const INVALID_CREDENTIALS_WARNING = `Could not establish connection for tenant "${tenant}". Existing pool will be drained.`
104
- const INVALID_CREDENTIALS_ERROR = new Error(
105
- `Create is blocked for tenant "${tenant}" due to invalid credentials.`
106
- )
98
+ const INVALID_CREDENTIALS_ERROR = `Create is blocked for tenant "${tenant}" due to invalid credentials.`
99
+ const _create = () =>
100
+ new Promise((_, reject) =>
101
+ setTimeout(() => reject(new Error(INVALID_CREDENTIALS_ERROR)), config.acquireTimeoutMillis)
102
+ )
107
103
 
108
104
  // The error listener for `factoryCreateError` is registered to detect failed connection attempts.
109
- // If it fails due to invalid credentials, we delete the current pool from the pools map and overwrite the
110
- // pool factory create function.
111
- // The background is that the generic pool will keep trying to establish a connection by invoking the factory
112
- // create function until the `acquireTimeoutMillis` is reached.
105
+ // If it fails due to invalid credentials, we delete the current pool from the pools map and overwrite the pool factory create function.
106
+ // The background is that the generic pool will keep trying to establish a connection by invoking the factory create function until the `acquireTimeoutMillis` is reached.
113
107
  // This leads to numerous connection attempts for a single request, even when the credentials are invalid.
114
108
  // Due to the deletion in the map, subsequent requests will retrieve the credentials again.
115
- p.on('factoryCreateError', async function (err) {
109
+ p.on('factoryCreateError', function (err) {
116
110
  if (err._connectError) {
117
111
  LOG._warn && LOG.warn(INVALID_CREDENTIALS_WARNING)
118
112
  pools.delete(tenant)
119
- if (p._factory && p._factory.create) {
120
- // reject after 100 ms to not block CPU completely
121
- p._factory.create = () =>
122
- new Promise((resolve, reject) => setTimeout(() => reject(INVALID_CREDENTIALS_ERROR), 100))
123
- }
124
- await p.drain()
125
- await p.clear()
113
+ if (p._factory?.create) p._factory.create = _create
114
+ // shutdown
115
+ p.drain().then(p.clear.bind(p)) //> no need to await
126
116
  }
127
117
  })
128
118
 
@@ -9,7 +9,6 @@ const STREAM_PLACEHOLDER = '[<stream>]'
9
9
  const _loadStreamExtensionIfNeeded = () => {
10
10
  const hana = require('./driver')
11
11
  if (hana.name !== 'hdb') {
12
- // eslint-disable-next-line cds/no-missing-dependencies -- needs to be added by app dev
13
12
  const extension = require('@sap/hana-client/extension/Stream.js')
14
13
  return isDynatraceEnabled() ? dynatraceStreamingExtension(extension) : extension
15
14
  }
@@ -1,5 +1,4 @@
1
1
  const cds = require('../../cds.js')
2
- // eslint-disable-next-line cds/no-missing-dependencies -- needs to be added by app dev
3
2
  const ClientAmqp = require('@sap/xb-msg-amqp-v100').Client
4
3
  const { connect, disconnect } = require('./connections')
5
4
 
@@ -39,7 +39,7 @@ const authorizedRequest = ({ method, uri, path, oa2, tenant, dataObj, headers, t
39
39
  let body
40
40
  try {
41
41
  body = res.headers && res.headers['content-type'] === 'application/json' ? JSON.parse(chunks) : chunks
42
- } catch (e) {
42
+ } catch {
43
43
  // There are some cases (e.g. ReadinessCheck) where the content type is 'application/json'
44
44
  // but the chunks are not valid JSON.
45
45
  body = chunks
@@ -1,7 +1,7 @@
1
1
  const _JSONorString = string => {
2
2
  try {
3
3
  return JSON.parse(string)
4
- } catch (e) {
4
+ } catch {
5
5
  return string
6
6
  }
7
7
  }
@@ -15,7 +15,7 @@ const getTenantInfo = async tenant => {
15
15
  try {
16
16
  await tx.rollback()
17
17
  throw e
18
- } catch (_) {
18
+ } catch {
19
19
  throw e
20
20
  }
21
21
  }