@sap/cds 5.8.2 → 5.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (252) hide show
  1. package/CHANGELOG.md +214 -78
  2. package/app/fiori/preview.js +16 -11
  3. package/app/fiori/routes.js +3 -0
  4. package/app/index.js +1 -1
  5. package/bin/build/buildTaskFactory.js +3 -3
  6. package/bin/build/buildTaskProviderFactory.js +1 -1
  7. package/bin/build/constants.js +1 -1
  8. package/bin/build/provider/buildTaskHandlerEdmx.js +12 -7
  9. package/bin/build/provider/buildTaskHandlerInternal.js +1 -1
  10. package/bin/build/provider/buildTaskProviderInternal.js +8 -2
  11. package/bin/build/provider/hana/2migration.js +27 -24
  12. package/bin/build/provider/hana/index.js +17 -18
  13. package/bin/build/provider/hana/migrationtable.js +9 -10
  14. package/bin/build/provider/java-cf/index.js +4 -5
  15. package/bin/build/provider/node-cf/index.js +99 -6
  16. package/bin/cds.js +20 -17
  17. package/bin/deploy/to-hana/cfUtil.js +16 -19
  18. package/bin/deploy/to-hana/hana.js +7 -24
  19. package/bin/deploy/to-hana/hdiDeployUtil.js +8 -4
  20. package/bin/mtx/in-cds.js +2 -2
  21. package/bin/serve.js +12 -5
  22. package/bin/utils/modules.js +7 -0
  23. package/bin/version.js +56 -3
  24. package/lib/compile/cdsc.js +26 -3
  25. package/lib/compile/etc/_localized.js +36 -25
  26. package/lib/compile/etc/csv.js +8 -8
  27. package/lib/compile/for/drafts.js +9 -0
  28. package/lib/compile/for/java.js +16 -0
  29. package/lib/compile/for/nodejs.js +12 -0
  30. package/lib/compile/for/odata.js +1 -1
  31. package/lib/compile/index.js +3 -0
  32. package/lib/compile/minify.js +16 -2
  33. package/lib/compile/parse.js +2 -2
  34. package/lib/compile/resolve.js +35 -18
  35. package/lib/compile/to/json.js +3 -1
  36. package/lib/compile/to/sql.js +2 -2
  37. package/lib/compile/to/srvinfo.js +4 -2
  38. package/lib/connect/index.js +1 -1
  39. package/lib/core/entities.js +15 -14
  40. package/lib/core/index.js +39 -36
  41. package/lib/core/reflect.js +4 -2
  42. package/lib/deploy.js +114 -127
  43. package/lib/env/defaults.js +1 -0
  44. package/lib/env/index.js +165 -165
  45. package/lib/env/presets.js +1 -0
  46. package/lib/env/requires.js +120 -49
  47. package/lib/index.js +1 -0
  48. package/lib/log/format/kibana.js +2 -2
  49. package/lib/ql/SELECT.js +10 -0
  50. package/lib/ql/parse.js +1 -0
  51. package/lib/req/cds-context.js +4 -1
  52. package/lib/req/context.js +50 -56
  53. package/lib/req/event.js +1 -6
  54. package/lib/req/locale.js +6 -5
  55. package/lib/req/request.js +2 -0
  56. package/lib/req/user.js +7 -5
  57. package/lib/serve/Service-api.js +10 -7
  58. package/lib/serve/Service-dispatch.js +9 -11
  59. package/lib/serve/Service-methods.js +30 -41
  60. package/lib/serve/Transaction.js +10 -7
  61. package/lib/serve/adapters.js +7 -5
  62. package/lib/serve/index.js +24 -12
  63. package/lib/utils/data.js +1 -1
  64. package/lib/utils/index.js +27 -30
  65. package/lib/utils/resources/index.js +101 -0
  66. package/lib/utils/resources/tar.js +71 -0
  67. package/lib/utils/resources/utils.js +11 -0
  68. package/libx/_runtime/audit/Service.js +36 -39
  69. package/libx/_runtime/audit/generic/personal/access.js +3 -4
  70. package/libx/_runtime/audit/generic/personal/modification.js +3 -4
  71. package/libx/_runtime/audit/utils/v2.js +1 -2
  72. package/libx/_runtime/auth/index.js +126 -84
  73. package/libx/_runtime/auth/strategies/JWT.js +12 -19
  74. package/libx/_runtime/auth/strategies/dummy.js +1 -5
  75. package/libx/_runtime/auth/strategies/dwc.js +11 -9
  76. package/libx/_runtime/auth/strategies/mock.js +0 -4
  77. package/libx/_runtime/auth/strategies/{utils/xssec.js → xssecUtils.js} +7 -4
  78. package/libx/_runtime/auth/strategies/xsuaa.js +12 -19
  79. package/libx/_runtime/auth/utils.js +22 -1
  80. package/libx/_runtime/cds-services/adapter/odata-v4/Dispatcher.js +104 -98
  81. package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +2 -2
  82. package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +1 -1
  83. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/action.js +13 -0
  84. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/language.js +2 -8
  85. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +4 -29
  86. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +2 -1
  87. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +3 -2
  88. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +2 -2
  89. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +4 -6
  90. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/expandToCQN.js +24 -21
  91. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/index.js +8 -2
  92. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/UriHelper.js +1 -1
  93. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/DeserializerFactory.js +2 -0
  94. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/ResourceJsonDeserializer.js +5 -6
  95. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/invocation/DispatcherCommand.js +2 -6
  96. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/utils/UriHelper.js +4 -1
  97. package/libx/_runtime/cds-services/adapter/odata-v4/to.js +1 -12
  98. package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +33 -9
  99. package/libx/_runtime/cds-services/adapter/odata-v4/utils/dispatcherUtils.js +50 -0
  100. package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +2 -2
  101. package/libx/_runtime/cds-services/adapter/odata-v4/utils/request.js +10 -3
  102. package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +9 -11
  103. package/libx/_runtime/cds-services/adapter/rest/RestRequest.js +6 -3
  104. package/libx/_runtime/cds-services/adapter/rest/handlers/operation.js +4 -2
  105. package/libx/_runtime/cds-services/adapter/rest/rest-to-cqn/utils.js +1 -1
  106. package/libx/_runtime/cds-services/adapter/rest/utils/binary.js +1 -1
  107. package/libx/_runtime/cds-services/adapter/rest/utils/key-value-utils.js +2 -3
  108. package/libx/_runtime/cds-services/adapter/rest/utils/parse-url.js +6 -4
  109. package/libx/_runtime/cds-services/adapter/rest/utils/result.js +1 -0
  110. package/libx/_runtime/cds-services/adapter/rest/utils/validation-checks.js +8 -5
  111. package/libx/_runtime/cds-services/services/Service.js +40 -0
  112. package/libx/_runtime/cds-services/services/utils/columns.js +4 -3
  113. package/libx/_runtime/cds-services/services/utils/compareJson.js +4 -4
  114. package/libx/_runtime/cds-services/services/utils/differ.js +3 -3
  115. package/libx/_runtime/cds-services/services/utils/handlerUtils.js +4 -4
  116. package/libx/_runtime/cds-services/services/utils/restrictions.js +78 -0
  117. package/libx/_runtime/cds-services/util/assert.js +20 -14
  118. package/libx/_runtime/cds.js +9 -1
  119. package/libx/_runtime/common/aspects/any.js +5 -0
  120. package/libx/_runtime/common/aspects/entity.js +25 -7
  121. package/libx/_runtime/common/aspects/utils.js +2 -2
  122. package/libx/_runtime/common/composition/data.js +6 -0
  123. package/libx/_runtime/common/composition/insert.js +3 -2
  124. package/libx/_runtime/common/composition/tree.js +4 -10
  125. package/libx/_runtime/common/composition/update.js +4 -4
  126. package/libx/_runtime/common/constants/draft.js +29 -26
  127. package/libx/_runtime/common/error/constants.js +2 -2
  128. package/libx/_runtime/common/error/frontend.js +7 -15
  129. package/libx/_runtime/common/generic/auth/capabilities.js +59 -0
  130. package/libx/_runtime/common/generic/auth/constants.js +20 -0
  131. package/libx/_runtime/common/generic/auth/expand.js +54 -0
  132. package/libx/_runtime/common/generic/auth/index.js +32 -0
  133. package/libx/_runtime/common/generic/auth/insertOnly.js +15 -0
  134. package/libx/_runtime/common/generic/auth/readOnly.js +26 -0
  135. package/libx/_runtime/common/generic/auth/requires.js +34 -0
  136. package/libx/_runtime/common/generic/auth/restrict.js +296 -0
  137. package/libx/_runtime/common/generic/auth/utils.js +213 -0
  138. package/libx/_runtime/common/generic/crud.js +14 -10
  139. package/libx/_runtime/common/generic/etag.js +1 -1
  140. package/libx/_runtime/common/generic/input.js +35 -35
  141. package/libx/_runtime/common/generic/sorting.js +2 -3
  142. package/libx/_runtime/common/generic/temporal.js +2 -2
  143. package/libx/_runtime/common/i18n/index.js +2 -31
  144. package/libx/_runtime/common/i18n/messages.properties +1 -1
  145. package/libx/_runtime/common/toggles/handler.js +21 -0
  146. package/libx/_runtime/common/utils/copy.js +10 -1
  147. package/libx/_runtime/common/utils/cqn2cqn4sql.js +100 -29
  148. package/libx/_runtime/common/utils/csn.js +63 -1
  149. package/libx/_runtime/common/utils/dollar.js +10 -1
  150. package/libx/_runtime/common/utils/draft.js +46 -7
  151. package/libx/_runtime/common/utils/entityFromCqn.js +13 -9
  152. package/libx/_runtime/common/utils/extensibilityUtils.js +18 -0
  153. package/libx/_runtime/common/utils/foreignKeyPropagations.js +88 -104
  154. package/libx/_runtime/common/utils/generateOnCond.js +9 -6
  155. package/libx/_runtime/common/utils/quotingStyles.js +2 -0
  156. package/libx/_runtime/common/utils/resolveStructured.js +25 -9
  157. package/libx/_runtime/common/utils/resolveView.js +4 -1
  158. package/libx/_runtime/common/utils/rewriteAsterisks.js +3 -16
  159. package/libx/_runtime/common/utils/structured.js +33 -37
  160. package/libx/_runtime/common/utils/template.js +17 -8
  161. package/libx/_runtime/common/utils/templateProcessor.js +28 -28
  162. package/libx/_runtime/db/data-conversion/post-processing.js +118 -417
  163. package/libx/_runtime/db/expand/expandCQNToJoin.js +45 -41
  164. package/libx/_runtime/db/expand/rawToExpanded.js +29 -8
  165. package/libx/_runtime/db/generic/index.js +1 -3
  166. package/libx/_runtime/db/generic/input.js +5 -10
  167. package/libx/_runtime/db/generic/rewrite.js +5 -2
  168. package/libx/_runtime/db/generic/structured.js +2 -2
  169. package/libx/_runtime/db/query/delete.js +2 -2
  170. package/libx/_runtime/db/query/insert.js +1 -1
  171. package/libx/_runtime/db/query/update.js +9 -14
  172. package/libx/_runtime/db/sql-builder/CreateBuilder.js +4 -3
  173. package/libx/_runtime/db/sql-builder/InsertBuilder.js +14 -1
  174. package/libx/_runtime/db/sql-builder/SelectBuilder.js +3 -2
  175. package/libx/_runtime/db/sql-builder/dataTypes.js +3 -3
  176. package/libx/_runtime/db/utils/columns.js +3 -3
  177. package/libx/_runtime/db/utils/normalizeTimeData.js +2 -2
  178. package/libx/_runtime/db/utils/propagateForeignKeys.js +6 -2
  179. package/libx/_runtime/extensibility/mps/index.js +5 -0
  180. package/libx/_runtime/extensibility/mps/service.js +111 -0
  181. package/libx/_runtime/extensibility/mps/tar.js +42 -0
  182. package/libx/_runtime/extensibility/mps/utils.js +11 -0
  183. package/libx/_runtime/{fiori → extensibility}/uiflex/handler/transformREAD.js +0 -0
  184. package/libx/_runtime/{fiori → extensibility}/uiflex/handler/transformRESULT.js +17 -5
  185. package/libx/_runtime/{fiori → extensibility}/uiflex/handler/transformWRITE.js +1 -0
  186. package/libx/_runtime/extensibility/uiflex/index.js +54 -0
  187. package/libx/_runtime/extensibility/uiflex/service.js +276 -0
  188. package/libx/_runtime/{fiori → extensibility}/uiflex/utils.js +22 -7
  189. package/libx/_runtime/fiori/generic/activate.js +2 -2
  190. package/libx/_runtime/fiori/generic/before.js +4 -4
  191. package/libx/_runtime/fiori/generic/new.js +3 -3
  192. package/libx/_runtime/fiori/generic/patch.js +1 -1
  193. package/libx/_runtime/fiori/generic/read.js +58 -66
  194. package/libx/_runtime/fiori/generic/readOverDraft.js +71 -16
  195. package/libx/_runtime/fiori/utils/handler.js +6 -13
  196. package/libx/_runtime/fiori/utils/where.js +6 -5
  197. package/libx/_runtime/hana/Service.js +4 -10
  198. package/libx/_runtime/hana/customBuilder/CustomSelectBuilder.js +2 -2
  199. package/libx/_runtime/hana/driver.js +2 -2
  200. package/libx/_runtime/hana/execute.js +29 -75
  201. package/libx/_runtime/hana/pool.js +1 -1
  202. package/libx/_runtime/hana/streaming.js +2 -1
  203. package/libx/_runtime/index.js +6 -6
  204. package/libx/_runtime/messaging/AMQPWebhookMessaging.js +5 -21
  205. package/libx/_runtime/messaging/Outbox.js +2 -2
  206. package/libx/_runtime/messaging/common-utils/AMQPClient.js +4 -14
  207. package/libx/_runtime/messaging/common-utils/connections.js +5 -7
  208. package/libx/_runtime/messaging/common-utils/normalizeIncomingMessage.js +30 -0
  209. package/libx/_runtime/messaging/enterprise-messaging-shared.js +2 -1
  210. package/libx/_runtime/messaging/enterprise-messaging-utils/EMManagement.js +36 -30
  211. package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +19 -12
  212. package/libx/_runtime/messaging/enterprise-messaging.js +8 -8
  213. package/libx/_runtime/messaging/file-based.js +5 -5
  214. package/libx/_runtime/messaging/message-queuing.js +14 -12
  215. package/libx/_runtime/messaging/outbox/utils.js +18 -19
  216. package/libx/_runtime/messaging/redis-messaging.js +91 -0
  217. package/libx/_runtime/messaging/service.js +8 -6
  218. package/libx/_runtime/remote/Service.js +44 -8
  219. package/libx/_runtime/remote/utils/client.js +25 -13
  220. package/libx/_runtime/remote/utils/data.js +11 -11
  221. package/libx/_runtime/sqlite/Service.js +6 -9
  222. package/libx/_runtime/sqlite/customBuilder/CustomFunctionBuilder.js +5 -2
  223. package/libx/_runtime/types/api.js +10 -2
  224. package/libx/common/utils/ucsn.js +109 -0
  225. package/libx/gql/resolvers/crud/create.js +6 -1
  226. package/libx/gql/resolvers/crud/delete.js +6 -1
  227. package/libx/gql/resolvers/crud/read.js +6 -1
  228. package/libx/gql/resolvers/crud/update.js +9 -1
  229. package/libx/gql/resolvers/parse/ast2cqn/columns.js +3 -1
  230. package/libx/gql/schema/typeDefMap.js +2 -2
  231. package/libx/odata/afterburner.js +110 -16
  232. package/libx/odata/grammar.pegjs +9 -1
  233. package/libx/odata/parseToCqn.js +39 -0
  234. package/libx/odata/parser.js +1 -1
  235. package/libx/rest/RestAdapter.js +9 -1
  236. package/libx/rest/middleware/input.js +54 -0
  237. package/libx/rest/middleware/operation.js +14 -1
  238. package/libx/rest/middleware/parse.js +11 -7
  239. package/package.json +1 -1
  240. package/server.js +34 -19
  241. package/srv/audit-log.cds +2 -2
  242. package/srv/flex.cds +8 -2
  243. package/srv/flex.js +1 -1
  244. package/srv/mps.cds +23 -0
  245. package/srv/mps.js +1 -0
  246. package/libx/_runtime/auth/strategies/utils/uaa.js +0 -21
  247. package/libx/_runtime/common/generic/auth.js +0 -874
  248. package/libx/_runtime/common/toggles/alpha.js +0 -43
  249. package/libx/_runtime/db/generic/arrayed.js +0 -33
  250. package/libx/_runtime/fiori/uiflex/index.js +0 -35
  251. package/libx/_runtime/fiori/uiflex/service.js +0 -150
  252. package/libx/rest/utils/data.js +0 -60
@@ -5,7 +5,7 @@ const onDraftActivate = require('./activate')._handler
5
5
  const { isNavigationToMany } = require('../utils/req')
6
6
  const { getKeysCondition } = require('../utils/where')
7
7
  const { removeDraftUUIDIfNecessary, ensureDraftsSuffix } = require('../utils/handler')
8
- const { DRAFT_COLUMNS } = require('../../common/constants/draft')
8
+ const { DRAFT_COLUMNS_MAP } = require('../../common/constants/draft')
9
9
 
10
10
  const _getUpdateDraftAdminCQN = ({ user, timestamp }, draftUUID) => {
11
11
  return UPDATE('DRAFT.DraftAdministrativeData')
@@ -60,7 +60,7 @@ const _handler = async function (req, next) {
60
60
  const elements = req.target.elements
61
61
  for (const column in elements) {
62
62
  const col = elements[column]
63
- if (col.default !== undefined && !DRAFT_COLUMNS.includes(column)) {
63
+ if (col.default !== undefined && !(column in DRAFT_COLUMNS_MAP)) {
64
64
  if ('val' in col.default) req.data[col.name] = col.default.val
65
65
  else if ('ref' in col.default) req.data[col.name] = col.default.ref[0]
66
66
  else req.data[col.name] = col.default
@@ -91,7 +91,7 @@ const _handler = async function (req, next) {
91
91
  req.reject(404)
92
92
  }
93
93
 
94
- removeDraftUUIDIfNecessary(result[0], req)
94
+ removeDraftUUIDIfNecessary(req)(result[0])
95
95
 
96
96
  return result[0]
97
97
  }
@@ -82,7 +82,7 @@ const _handler = async function (req) {
82
82
  await Promise.all([dbtx.run(updateDraftCQN), dbtx.run(updateDraftAdminCQN)])
83
83
  result = await dbtx.run(_getSelectCQN(this.model, req, keysCondition, false))
84
84
  if (result.length === 0) req.reject(404)
85
- removeDraftUUIDIfNecessary(result[0], req)
85
+ removeDraftUUIDIfNecessary(req)(result[0])
86
86
  return result[0]
87
87
  }
88
88
 
@@ -3,7 +3,7 @@ const { SELECT } = cds.ql
3
3
 
4
4
  const { cqn2cqn4sql, convertWhereExists } = require('../../common/utils/cqn2cqn4sql')
5
5
  const { getElementDeep } = require('../../common/utils/csn')
6
- const { DRAFT_COLUMNS, DRAFT_COLUMNS_MAP, SCENARIO } = require('../../common/constants/draft')
6
+ const { DRAFT_COLUMNS_MAP, SCENARIO } = require('../../common/constants/draft')
7
7
  const {
8
8
  addColumnAlias,
9
9
  draftIsLocked,
@@ -786,7 +786,7 @@ const _getOrderByEnrichedColumns = (orderBy, columns, entity) => {
786
786
  // For associations we need to 'materialise' the resulting field, otherwise we cannot access it in an outer SELECT.
787
787
  if (entity && entity.elements[el.ref[0]] && entity.elements[el.ref[0]].isAssociation) {
788
788
  enrichedCol.push({ ref: [...el.ref], as: _poorMansAlias4(el) })
789
- } else if (!DRAFT_COLUMNS.includes(el.ref[el.ref.length - 1]) && !colNames.includes(el.ref[el.ref.length - 1])) {
789
+ } else if (!(el.ref[el.ref.length - 1] in DRAFT_COLUMNS_MAP) && !colNames.includes(el.ref[el.ref.length - 1])) {
790
790
  enrichedCol.push({ ref: [...el.ref] })
791
791
  }
792
792
  }
@@ -844,7 +844,9 @@ const _getUnionCQN = (req, draftName, columns, subSelect, draftWhere, model, ent
844
844
  for (const col of enrichedColumns) {
845
845
  // if we have columns for outer order by that may also be needed for joins, we need to duplicate them
846
846
  const element = getElementDeep(req.target, col.ref)
847
- if (element && element['@odata.foreignKey4']) columns.push({ ref: [...col.ref] })
847
+ if (element && element._foreignKey4) {
848
+ columns.push({ ref: [...col.ref] })
849
+ }
848
850
 
849
851
  col.as = _poorMansAlias4(col)
850
852
  // add alias to outer order by
@@ -1059,8 +1061,7 @@ const _getColumns = ({ query: { SELECT }, target }, model) => {
1059
1061
  return SELECT.columns
1060
1062
  ? SELECT.columns.filter(
1061
1063
  col =>
1062
- (col.ref && !DRAFT_COLUMNS.includes(col.ref[col.ref.length - 1])) ||
1063
- (!col.ref && !DRAFT_COLUMNS.includes(col))
1064
+ (col.ref && !(col.ref[col.ref.length - 1] in DRAFT_COLUMNS_MAP)) || (!col.ref && !(col in DRAFT_COLUMNS_MAP))
1064
1065
  )
1065
1066
  : getColumns(target, { onlyNames: true, removeIgnore: true })
1066
1067
  }
@@ -1100,20 +1101,14 @@ const _adaptSubSelects = ({ SELECT: { from, where } }, scenario) => {
1100
1101
  }
1101
1102
  }
1102
1103
 
1103
- const _calculateDraftAdminColumns = (result, user) => {
1104
- if (
1105
- Object.prototype.hasOwnProperty.call(result, 'DraftIsCreatedByMe') &&
1106
- Object.prototype.hasOwnProperty.call(result, 'CreatedByUser')
1107
- ) {
1104
+ const _calculateDraftAdminColumns = (result, user, deleteLastChangeDateTime) => {
1105
+ if (!result) return
1106
+ if ('InProcessByUser' in result && !draftIsLocked(result.LastChangeDateTime)) result.InProcessByUser = ''
1107
+ if (deleteLastChangeDateTime) delete result.LastChangeDateTime
1108
+ if ('DraftIsCreatedByMe' in result && 'CreatedByUser' in result)
1108
1109
  result.DraftIsCreatedByMe = result.CreatedByUser === user
1109
- }
1110
-
1111
- if (
1112
- Object.prototype.hasOwnProperty.call(result, 'DraftIsProcessedByMe') &&
1113
- Object.prototype.hasOwnProperty.call(result, 'InProcessByUser')
1114
- ) {
1110
+ if ('DraftIsProcessedByMe' in result && 'InProcessByUser' in result)
1115
1111
  result.DraftIsProcessedByMe = result.InProcessByUser === user
1116
- }
1117
1112
  }
1118
1113
 
1119
1114
  const _adaptDraftColumnsForSiblingEntity = (result, isSiblingActive) => {
@@ -1145,30 +1140,6 @@ const _adaptAnnotationAliases = cqn => {
1145
1140
  _collectAliases(cqn.SELECT.from, aliases)
1146
1141
  }
1147
1142
 
1148
- const calculateDraftTimeout = (scenario, result, deleteLastChangeDateTime) => {
1149
- if (scenario === SCENARIO.DRAFT_ADMIN) {
1150
- if (!draftIsLocked(result[0].LastChangeDateTime)) {
1151
- result[0].InProcessByUser = ''
1152
- }
1153
- if (deleteLastChangeDateTime) delete result[0].LastChangeDateTime
1154
-
1155
- return
1156
- }
1157
-
1158
- // non empty result that and DraftAdministrativeData was expanded
1159
- if (result.length && Object.prototype.hasOwnProperty.call(result[0], 'DraftAdministrativeData')) {
1160
- result.forEach(row => {
1161
- if (!row.DraftAdministrativeData) return
1162
- if (Object.prototype.hasOwnProperty.call(row.DraftAdministrativeData, 'InProcessByUser')) {
1163
- if (!draftIsLocked(row.DraftAdministrativeData.LastChangeDateTime)) {
1164
- row.DraftAdministrativeData.InProcessByUser = ''
1165
- }
1166
- }
1167
- if (deleteLastChangeDateTime) delete row.DraftAdministrativeData.LastChangeDateTime
1168
- })
1169
- }
1170
- }
1171
-
1172
1143
  const enhanceQueryForTimeoutIfNeeded = (scenario, columns = []) => {
1173
1144
  if (scenario !== SCENARIO.DRAFT_ADMIN) {
1174
1145
  const draftAdmin = columns.find(col => col.ref && col.ref[col.ref.length - 1] === 'DraftAdministrativeData')
@@ -1212,6 +1183,51 @@ const _adaptDraftAdminExpand = cqn => {
1212
1183
  }
1213
1184
  }
1214
1185
 
1186
+ const _getOriginalColumns = req => {
1187
+ const originalColumns = {}
1188
+ // expanded columns are handled generically in db
1189
+ for (const c of req.query.SELECT.columns) {
1190
+ originalColumns[c.ref ? c.ref[c.ref.length - 1] : c.as || c] = true
1191
+ }
1192
+ return originalColumns
1193
+ }
1194
+
1195
+ const _postProcess = (result, req, cqnScenario, deleteLastChangeDateTime) => {
1196
+ const resultAsArray = Array.isArray(result) ? result : result ? [result] : []
1197
+
1198
+ if (!result || !resultAsArray.length) return result
1199
+
1200
+ if (cqnScenario.scenario === SCENARIO.SIBLING_ENTITY) {
1201
+ if (resultAsArray[0].draftAdmin_inProcessByUser !== req.user.id) return []
1202
+ delete resultAsArray[0].draftAdmin_inProcessByUser
1203
+ _adaptDraftColumnsForSiblingEntity(resultAsArray[0], cqnScenario.isSiblingActive)
1204
+ }
1205
+
1206
+ const removeDraftUUIDIfNecessaryFn = removeDraftUUIDIfNecessary(req)
1207
+ let notRequestedColumns
1208
+ // REVISIT: remove flag cds.env.features.auto_fetch_expand_keys after two month grace period
1209
+ if (!req.query.SELECT._4odata && !cds.env.features.auto_fetch_expand_keys) {
1210
+ const originalColumns = _getOriginalColumns(req)
1211
+ notRequestedColumns = originalColumns && Object.keys(resultAsArray[0]).filter(key => !originalColumns[key])
1212
+ }
1213
+ if (cqnScenario.scenario === SCENARIO.DRAFT_ADMIN) {
1214
+ _calculateDraftAdminColumns(resultAsArray[0], req.user.id, deleteLastChangeDateTime)
1215
+ if (notRequestedColumns) {
1216
+ for (const key of notRequestedColumns) delete resultAsArray[0][key]
1217
+ }
1218
+ } else {
1219
+ for (const row of resultAsArray) {
1220
+ removeDraftUUIDIfNecessaryFn(row)
1221
+ _calculateDraftAdminColumns(row.DraftAdministrativeData, req.user.id, deleteLastChangeDateTime)
1222
+ if (notRequestedColumns) {
1223
+ for (const key of notRequestedColumns) delete row[key]
1224
+ }
1225
+ }
1226
+ }
1227
+
1228
+ return result
1229
+ }
1230
+
1215
1231
  /**
1216
1232
  * Generic Handler for READ requests in the context of draft.
1217
1233
  *
@@ -1274,32 +1290,8 @@ const _handler = async function (req) {
1274
1290
  req.target = this.model.definitions[ensureUnlocalized(req.target.name)]
1275
1291
 
1276
1292
  const result = await cds.tx(req).send({ query: cqnScenario.cqn, target: req.target })
1277
- const resultAsArray = Array.isArray(result) ? result : result ? [result] : []
1278
- removeDraftUUIDIfNecessary(resultAsArray, req)
1279
-
1280
- if (cqnScenario.scenario === SCENARIO.DRAFT_ADMIN) {
1281
- if (!result || (Array.isArray(result) && !result.length)) return result
1282
1293
 
1283
- _calculateDraftAdminColumns(resultAsArray[0], req.user.id)
1284
- }
1285
-
1286
- calculateDraftTimeout(cqnScenario.scenario, resultAsArray, enhancedWithLastChangeDateTime)
1287
-
1288
- if (cqnScenario.scenario === SCENARIO.SIBLING_ENTITY) {
1289
- if (!result || (Array.isArray(result) && !result.length)) return result
1290
- if (resultAsArray[0].draftAdmin_inProcessByUser !== req.user.id) return []
1291
-
1292
- delete resultAsArray[0].draftAdmin_inProcessByUser
1293
- _adaptDraftColumnsForSiblingEntity(resultAsArray[0], cqnScenario.isSiblingActive)
1294
- }
1295
-
1296
- if (resultAsArray.length && Object.prototype.hasOwnProperty.call(resultAsArray[0], 'DraftAdministrativeData')) {
1297
- resultAsArray.forEach(row => {
1298
- row.DraftAdministrativeData && _calculateDraftAdminColumns(row.DraftAdministrativeData, req.user.id)
1299
- })
1300
- }
1301
-
1302
- return result
1294
+ return _postProcess(result, req, cqnScenario, enhancedWithLastChangeDateTime)
1303
1295
  }
1304
1296
 
1305
1297
  module.exports = cds.service.impl(function () {
@@ -3,6 +3,7 @@ const { SELECT } = cds.ql
3
3
  const { getEnrichedCQN, hasDraft, ensureDraftsSuffix } = require('../utils/handler')
4
4
  const { readAndDeleteKeywords } = require('../utils/where')
5
5
  const { cqn2cqn4sql } = require('../../common/utils/cqn2cqn4sql')
6
+ const { isActiveEntityRequested } = require('../../../_runtime/fiori/utils/where')
6
7
 
7
8
  const _modifyCQN = (cqnDraft, where, context) => {
8
9
  const whereDraft = [...where]
@@ -10,9 +11,8 @@ const _modifyCQN = (cqnDraft, where, context) => {
10
11
  cqnDraft.where(whereDraft)
11
12
 
12
13
  if (result && result.value.val === false) {
13
- cqnDraft.SELECT.from.ref[cqnDraft.SELECT.from.ref.length - 1] = ensureDraftsSuffix(
14
- cqnDraft.SELECT.from.ref[cqnDraft.SELECT.from.ref.length - 1]
15
- )
14
+ const fromRef = cqnDraft.SELECT.from.ref
15
+ cqnDraft.SELECT.from.ref[fromRef.length - 1] = ensureDraftsSuffix(fromRef[fromRef.length - 1])
16
16
  }
17
17
 
18
18
  for (let i = 0; i < cqnDraft.SELECT.where.length; i++) {
@@ -33,32 +33,89 @@ const _modifyCQN = (cqnDraft, where, context) => {
33
33
  }
34
34
  }
35
35
 
36
+ const _hasNavToNonDraftEnclosedAssoc = (pathSegments, definitions, excludeAssoc) => {
37
+ if (pathSegments.length < 2) return false
38
+ const entity = definitions[pathSegments[0]]
39
+ const nav = entity.elements[pathSegments[1]]
40
+
41
+ if (nav._isAssociationStrict) {
42
+ if (nav['@odata.draft.enclosed']) return false
43
+ if (excludeAssoc == null) return true
44
+ if (!excludeAssoc(nav)) return true
45
+ }
46
+
47
+ // At this point we know that nav is a composition, so we have to recursively
48
+ // follow the navigation until we reach the end or find an association.
49
+ pathSegments.shift()
50
+ pathSegments[0] = nav.target
51
+ return _hasNavToNonDraftEnclosedAssoc(pathSegments, definitions, excludeAssoc)
52
+ }
53
+
54
+ const _shouldReadOverDraft = (req, definitions) => {
55
+ const SELECT = req.query.SELECT
56
+ const fromRef = SELECT.from.ref
57
+
58
+ if (!fromRef) return false
59
+
60
+ // read over the draft if the navigation target is non-draft-enabled
61
+ if (!req.target._isDraftEnabled) return true
62
+
63
+ // read over the draft only for navigation scenarios
64
+ if (fromRef.length === 1) return false
65
+
66
+ const firstFromRef = fromRef[0]
67
+ const rootEntityName = typeof firstFromRef === 'string' ? firstFromRef : firstFromRef.id
68
+ const rootEntity = definitions[rootEntityName]
69
+
70
+ // read over the draft only if the root entity is draft-enabled and
71
+ // the navigation starts with a draft entity (IsActiveEntity=false)
72
+ if (!!rootEntity._isDraftEnabled && isActiveEntityRequested(firstFromRef.where)) return false
73
+
74
+ // read over the draft if the navigation target is an association and
75
+ // only if it isn't annotated with @odata.draft.enclosed
76
+ const pathSegments = fromRef.map(path => (typeof path === 'string' ? path : path.id))
77
+
78
+ const excludeAssoc = assoc => {
79
+ if (assoc.name === 'DraftAdministrativeData' || assoc.name === 'SiblingEntity') return true
80
+ return false
81
+ }
82
+
83
+ return _hasNavToNonDraftEnclosedAssoc(pathSegments, definitions, excludeAssoc)
84
+ }
85
+
36
86
  /**
37
87
  * Generic Handler for READ requests.
38
88
  *
39
- * @param req
89
+ * @param {import('../../cds-services/adapter/odata-v4/ODataRequest')} req
90
+ * @param next
40
91
  * @returns {Promise<Array>}
41
92
  */
42
- const _handler = async function (req) {
43
- if (req.query.SELECT.limit && req.query.SELECT.limit.rows && req.query.SELECT.limit.rows.val === 0) {
44
- return Promise.resolve([])
45
- }
93
+ const _readOverDraftHandler = async function (req, next) {
94
+ const definitions = this.model.definitions
95
+
96
+ // determine whether the request is handled here (read over draft handler),
97
+ // or whether it is passed to the next registered handler/route
98
+ if (!_shouldReadOverDraft(req, definitions)) return next()
99
+
100
+ const rows = req.query.SELECT.limit && req.query.SELECT.limit.rows
101
+ if (rows && rows.val === 0) return Promise.resolve([])
46
102
 
47
103
  // REVISIT DRAFT HANDLING: cqn2cqn4sql must not be called here
48
- const sqlQuery = cqn2cqn4sql(req.query, this.model, { _4fiori: true })
104
+ const sqlQuery = cqn2cqn4sql(req.query, this.model, { _4db: req.target._isDraftEnabled, _4fiori: true })
105
+
49
106
  if (req.query._streaming) {
50
107
  sqlQuery._streaming = true
51
108
  }
52
109
 
53
- const hasDraftEntity = hasDraft(this.model.definitions, sqlQuery)
110
+ const hasDraftEntity = hasDraft(definitions, sqlQuery)
54
111
 
55
- if (hasDraftEntity && sqlQuery.SELECT.where && sqlQuery.SELECT.where.length !== 0) {
112
+ if (hasDraftEntity && sqlQuery.SELECT.where && sqlQuery.SELECT.where.length > 0) {
56
113
  let cqnDraft = SELECT.from({
57
114
  ref: [...sqlQuery.SELECT.from.ref],
58
115
  as: sqlQuery.SELECT.from.as
59
116
  })
60
- cqnDraft.SELECT.columns = sqlQuery.SELECT.columns
61
117
 
118
+ cqnDraft.SELECT.columns = sqlQuery.SELECT.columns
62
119
  _modifyCQN(cqnDraft, sqlQuery.SELECT.where, req)
63
120
  cqnDraft = getEnrichedCQN(cqnDraft, sqlQuery.SELECT, [])
64
121
  return cds.tx(req).run(cqnDraft)
@@ -67,8 +124,6 @@ const _handler = async function (req) {
67
124
  return cds.tx(req).run(sqlQuery)
68
125
  }
69
126
 
70
- module.exports = cds.service.impl(function () {
71
- for (const entity of Object.values(this.entities).filter(e => !e._isDraftEnabled)) {
72
- this.on('READ', entity, _handler)
73
- }
127
+ module.exports = cds.service.impl(function readOverDraft() {
128
+ this.on('READ', '*', _readOverDraftHandler)
74
129
  })
@@ -4,7 +4,7 @@ const { getColumns } = require('../../cds-services/services/utils/columns')
4
4
  const { ensureNoDraftsSuffix, ensureDraftsSuffix, ensureUnlocalized } = require('../../common/utils/draft')
5
5
  const getTemplate = require('../../common/utils/template')
6
6
 
7
- const { DRAFT_COLUMNS } = require('../../common/constants/draft')
7
+ const { DRAFT_COLUMNS_MAP } = require('../../common/constants/draft')
8
8
 
9
9
  // unofficial config!
10
10
  const MAX_RECURSION_DEPTH = (cds.env.features.recursion_depth && Number(cds.env.features.recursion_depth)) || 2
@@ -157,7 +157,7 @@ const getEnrichedCQN = (cqn, select, draftWhere, scenarioAlias, addLimitOrder =
157
157
  const _aliasRef = (ref, alias) => {
158
158
  const newRef = [...ref]
159
159
  // we skip draft columns because they are mostly calculated later on
160
- if (alias && !DRAFT_COLUMNS.includes(ref[ref.length - 1])) {
160
+ if (alias && !(ref[ref.length - 1] in DRAFT_COLUMNS_MAP)) {
161
161
  newRef.unshift(alias)
162
162
  }
163
163
  return newRef
@@ -184,17 +184,10 @@ const setStatusCodeAndHeader = (response, keys, entityName, isActiveEntity) => {
184
184
  response.setHeader('location', `../${entityName}(${keysString},IsActiveEntity=${isActiveEntity})`)
185
185
  }
186
186
 
187
- const removeDraftUUIDIfNecessary = (result, req) => {
188
- if (req._.req && req._.req.headers && req._.req.headers['x-cds-odata-version'] === 'v2') return
189
-
190
- if (Array.isArray(result)) {
191
- for (const row of result) {
192
- delete row.DraftAdministrativeData_DraftUUID
193
- }
194
- } else {
195
- delete result.DraftAdministrativeData_DraftUUID
196
- }
197
- }
187
+ const removeDraftUUIDIfNecessary = req =>
188
+ req._.req && req._.req.headers && req._.req.headers['x-cds-odata-version'] === 'v2'
189
+ ? () => {}
190
+ : result => delete result.DraftAdministrativeData_DraftUUID
198
191
 
199
192
  const isDraftActivateAction = req => {
200
193
  // REVISIT: get rid of getUrlObject
@@ -1,3 +1,5 @@
1
+ const AND_OR = { and: 1, or: 1 }
2
+
1
3
  const _removeMultipleBrackets = (index, whereCondition, isXpr) => {
2
4
  if (isXpr) return index
3
5
 
@@ -20,19 +22,18 @@ const _removeMultipleBrackets = (index, whereCondition, isXpr) => {
20
22
  }
21
23
 
22
24
  const _calculateSpliceArgs = (index, whereCondition, isXpr = false) => {
23
- const AND_OR = ['and', 'or']
24
25
  const len = isXpr ? 1 : 3
25
- if (AND_OR.includes(whereCondition[index - 1])) {
26
+ if (whereCondition[index - 1] in AND_OR) {
26
27
  return { index: index - 1, count: 1 + len }
27
28
  }
28
- if (AND_OR.includes(whereCondition[index + len])) {
29
+ if (whereCondition[index + len] in AND_OR) {
29
30
  return { index: index, count: len + 1 }
30
31
  }
31
32
  if (whereCondition[index - 1] === '(' && whereCondition[index + len] === ')') {
32
- if (AND_OR.includes(whereCondition[index - 2])) {
33
+ if (whereCondition[index - 2] in AND_OR) {
33
34
  return { index: index - 2, count: len + 3 }
34
35
  }
35
- if (AND_OR.includes(whereCondition[index + len + 1])) {
36
+ if (whereCondition[index + len + 1] in AND_OR) {
36
37
  return { index: index - 1, count: len + 3 }
37
38
  }
38
39
 
@@ -107,17 +107,12 @@ class HanaDatabase extends DatabaseService {
107
107
 
108
108
  _registerAfterHandlers() {
109
109
  // REVISIT: after phase runs in parallel -> side effects possible!
110
- const { effective } = cds.env
110
+ const { effective, features } = cds.env
111
111
 
112
- if (effective.odata.structs) {
112
+ if (effective.odata.structs && !features.ucsn_struct_conversion) {
113
113
  // REVISIT: only register for entities that contain structured or navigation to it
114
114
  this.after(['READ'], '*', this._structured)
115
115
  }
116
-
117
- if (effective.odata.version !== 'v2') {
118
- // REVISIT: only register for entities that contain arrayed or navigation to it
119
- this.after(['READ'], '*', this._arrayed)
120
- }
121
116
  }
122
117
 
123
118
  /*
@@ -125,14 +120,13 @@ class HanaDatabase extends DatabaseService {
125
120
  */
126
121
  // eslint-disable-next-line complexity
127
122
  async acquire(arg) {
128
- // REVISIT: remove fallback arg.user.tenant with cds^6
123
+ // REVISIT: remove fallback arg.user.tenant with cds^6 (still needed for cds-mtx)
129
124
  const tenant = (typeof arg === 'string' ? arg : arg.tenant || (arg.user && arg.user.tenant)) || 'anonymous'
130
125
  const dbc = await pool.acquire(tenant, this)
131
126
 
132
127
  if (typeof arg !== 'string') {
133
128
  _setSessionContext(dbc, 'APPLICATIONUSER', arg.user.id || 'ANONYMOUS')
134
- // REVISIT: remove fallback arg.user.locale with cds^6
135
- _setSessionContext(dbc, 'LOCALE', arg.locale || (arg.user && arg.user.locale) || 'en')
129
+ _setSessionContext(dbc, 'LOCALE', arg.locale || 'en')
136
130
  // REVISIT: stable access
137
131
  const validFrom = (arg.context && arg.context._ && arg.context._['VALID-FROM']) || (arg._ && arg._['VALID-FROM'])
138
132
  const validto = (arg.context && arg.context._ && arg.context._['VALID-TO']) || (arg._ && arg._['VALID-TO'])
@@ -48,7 +48,7 @@ class CustomSelectBuilder extends SelectBuilder {
48
48
  select.from.ref &&
49
49
  select.from.ref.length === 1 &&
50
50
  // REVISIT this does not work with join and draft!
51
- this._csn.definitions[select.from.ref[0]]
51
+ this._csn.definitions[select.from.ref[0].id || select.from.ref[0]]
52
52
  // TODO FIXME
53
53
  skip =
54
54
  !select.orderBy ||
@@ -56,7 +56,7 @@ class CustomSelectBuilder extends SelectBuilder {
56
56
  select.orderBy.every(o => {
57
57
  const k = o.ref && o.ref.length === 1 && o.ref[0]
58
58
  const element = (k && entity.elements[k]) || {}
59
- return element.type !== 'cds.String'
59
+ return element._type !== 'cds.String'
60
60
  }))
61
61
  } catch (e) {
62
62
  if (LOG._warn) {
@@ -50,7 +50,7 @@ function _connectHdb(creds, tenant) {
50
50
  if (err) {
51
51
  err = _ensureError(err)
52
52
  err.message = `Could not establish connection for tenant "${tenant}" due to error: ` + err.message
53
- LOG._error && LOG.error(err)
53
+ LOG.error(err)
54
54
 
55
55
  // error on .connect shall lead to pool drain
56
56
  err._connectError = true
@@ -109,7 +109,7 @@ function _connectHanaClient(creds, tenant) {
109
109
  if (err) {
110
110
  err = _ensureError(err)
111
111
  err.message = `Could not establish connection for tenant "${tenant}" due to error: ` + err.message
112
- LOG._error && LOG.error(err)
112
+ LOG.error(err)
113
113
 
114
114
  // error on .connect shall lead to pool drain
115
115
  err._connectError = true
@@ -4,12 +4,7 @@ const LOG = cds.log('hana|db|sql')
4
4
  const { HANA_TYPE_CONVERSION_MAP } = require('./conversion')
5
5
  const CustomBuilder = require('./customBuilder')
6
6
  const { sqlFactory } = require('../db/sql-builder/')
7
- const {
8
- getPostProcessMapper,
9
- getPropertyMapper,
10
- getStructMapper,
11
- postProcess
12
- } = require('../db/data-conversion/post-processing')
7
+ const { getPostProcessMapper, postProcess } = require('../db/data-conversion/post-processing')
13
8
  const { createJoinCQNFromExpanded, hasExpand, rawToExpanded, expandV2 } = require('../db/expand')
14
9
  const {
15
10
  hasStreamInsert,
@@ -35,23 +30,11 @@ function _cqnToSQL(model, query, user, locale, txTimestamp) {
35
30
 
36
31
  const SANITIZE_VALUES = process.env.NODE_ENV === 'production' && cds.env.log.sanitize_values !== false
37
32
 
38
- function _getOutputParameters(stmt) {
39
- const result = {}
40
- const info = stmt.getParameterInfo()
41
- for (let i = 0; i < info.length; i++) {
42
- const param = info[i]
43
- if (param.direction === 2) {
44
- result[param.name] = stmt.getParameterValue(i)
45
- }
46
- }
47
-
48
- return Object.keys(result).length > 0 ? result : undefined
49
- }
50
-
51
33
  const BINARY_TYPES = {
52
34
  12: 'BINARY',
53
35
  13: 'VARBINARY',
54
- 27: 'BLOB'
36
+ 27: 'BLOB',
37
+ 33: 'BSTRING'
55
38
  }
56
39
 
57
40
  function _getBinaries(stmt) {
@@ -147,47 +130,20 @@ function _executeAsPreparedStatement(dbc, sql, values, reject, resolve) {
147
130
  }
148
131
  }
149
132
 
150
- if (cds.env.features.new_call_prodecure) {
151
- // procedure call metadata
152
- let outParameters
153
- const isProcedureCall = _isProcedureCall(sql)
154
- if (isProcedureCall) {
155
- try {
156
- const procedureName = _getProcedureName(sql)
157
- outParameters = await _getProcedureMetadata(procedureName, dbc)
158
- } catch (e) {
159
- LOG._warn && LOG.warn('Unable to fetch procedure metadata due to error:', e)
160
- }
133
+ // procedure call metadata
134
+ let outParameters
135
+ const isProcedureCall = _isProcedureCall(sql)
136
+ if (isProcedureCall) {
137
+ try {
138
+ const procedureName = _getProcedureName(sql)
139
+ outParameters = await _getProcedureMetadata(procedureName, dbc)
140
+ } catch (e) {
141
+ LOG._warn && LOG.warn('Unable to fetch procedure metadata due to error:', e)
161
142
  }
162
-
163
- // on @sap/hana-client, we need to use execQuery in case of calling procedures
164
- stmt[isProcedureCall && dbc.name !== 'hdb' ? 'execQuery' : 'exec'](values, function (err, rows, ...args) {
165
- if (err) {
166
- stmt.drop(() => {})
167
- err.query = sql
168
- if (values) err.values = SANITIZE_VALUES ? ['***'] : values
169
- return reject(err)
170
- }
171
-
172
- let result
173
- if (isProcedureCall) {
174
- result =
175
- dbc.name === 'hdb'
176
- ? _hdbGetResultForProcedure(rows, args, outParameters)
177
- : _hcGetResultForProcedure(stmt, rows, outParameters)
178
- } else {
179
- result = rows
180
- }
181
-
182
- stmt.drop(() => {})
183
-
184
- resolve(result)
185
- })
186
-
187
- return
188
143
  }
189
144
 
190
- stmt.exec(values, function (err, rows, procedureReturn) {
145
+ // on @sap/hana-client, we need to use execQuery in case of calling procedures
146
+ stmt[isProcedureCall && dbc.name !== 'hdb' ? 'execQuery' : 'exec'](values, function (err, rows, ...args) {
191
147
  if (err) {
192
148
  stmt.drop(() => {})
193
149
  err.query = sql
@@ -195,13 +151,19 @@ function _executeAsPreparedStatement(dbc, sql, values, reject, resolve) {
195
151
  return reject(err)
196
152
  }
197
153
 
198
- let result = rows
199
- if (dbc.name !== 'hdb') {
200
- result = _getOutputParameters(stmt) || rows
154
+ let result
155
+ if (isProcedureCall) {
156
+ result =
157
+ dbc.name === 'hdb'
158
+ ? _hdbGetResultForProcedure(rows, args, outParameters)
159
+ : _hcGetResultForProcedure(stmt, rows, outParameters)
160
+ } else {
161
+ result = rows
201
162
  }
202
163
 
203
164
  stmt.drop(() => {})
204
- resolve(procedureReturn || result)
165
+
166
+ resolve(result)
205
167
  })
206
168
  })
207
169
  }
@@ -235,13 +197,13 @@ function _executeSimpleSQL(dbc, sql, values) {
235
197
  })
236
198
  }
237
199
 
238
- function _executeSelectSQL(dbc, sql, values, isOne, postMapper, propertyMapper, objStructMapper) {
200
+ function _executeSelectSQL(dbc, sql, values, isOne, postMapper) {
239
201
  return _executeSimpleSQL(dbc, sql, values).then(result => {
240
202
  if (isOne) {
241
203
  result = result.length > 0 ? result[0] : null
242
204
  }
243
205
 
244
- return postProcess(result, postMapper, propertyMapper, objStructMapper)
206
+ return postProcess(result, postMapper)
245
207
  })
246
208
  }
247
209
 
@@ -272,17 +234,9 @@ function executeSelectCQN(model, dbc, query, user, locale, txTimestamp) {
272
234
  }
273
235
 
274
236
  const { sql, values = [] } = _cqnToSQL(model, query, user, locale, txTimestamp)
275
- const propertyMapper = getPropertyMapper(model, query, true)
276
-
277
- return _executeSelectSQL(
278
- dbc,
279
- sql,
280
- values,
281
- query.SELECT.one,
282
- getPostProcessMapper(HANA_TYPE_CONVERSION_MAP, model, query),
283
- propertyMapper,
284
- getStructMapper(model, query, propertyMapper)
285
- )
237
+ const postProcessMapper = getPostProcessMapper(HANA_TYPE_CONVERSION_MAP, model, query)
238
+
239
+ return _executeSelectSQL(dbc, sql, values, query.SELECT.one, postProcessMapper)
286
240
  }
287
241
 
288
242
  function _getValuesProxy(values) {
@@ -97,7 +97,7 @@ function factory4(creds, tenant) {
97
97
  /*
98
98
  * default generic-pool config
99
99
  */
100
- const defaultConfig = { min: 0, max: 100, testOnBorrow: true }
100
+ const defaultConfig = { min: 0, max: 100, testOnBorrow: true, fifo: false }
101
101
 
102
102
  const _getPoolConfig = function () {
103
103
  const { pool: poolConfig } = cds.env.requires.db
@@ -18,7 +18,8 @@ const streamExtension = _loadStreamExtensionIfNeeded()
18
18
 
19
19
  function hasStreamInsert(insert, model) {
20
20
  if (!model) return true
21
- const into = model.definitions[ensureNoDraftsSuffix(insert.into)]
21
+ const name = insert.into.ref ? insert.into.ref[0] : insert.into
22
+ const into = model.definitions[ensureNoDraftsSuffix(name)]
22
23
  if (!into) return false
23
24
 
24
25
  if (insert.entries && insert.entries.length > 0) {