@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.
- package/CHANGELOG.md +214 -78
- package/app/fiori/preview.js +16 -11
- package/app/fiori/routes.js +3 -0
- package/app/index.js +1 -1
- package/bin/build/buildTaskFactory.js +3 -3
- package/bin/build/buildTaskProviderFactory.js +1 -1
- package/bin/build/constants.js +1 -1
- package/bin/build/provider/buildTaskHandlerEdmx.js +12 -7
- package/bin/build/provider/buildTaskHandlerInternal.js +1 -1
- package/bin/build/provider/buildTaskProviderInternal.js +8 -2
- package/bin/build/provider/hana/2migration.js +27 -24
- package/bin/build/provider/hana/index.js +17 -18
- package/bin/build/provider/hana/migrationtable.js +9 -10
- package/bin/build/provider/java-cf/index.js +4 -5
- package/bin/build/provider/node-cf/index.js +99 -6
- package/bin/cds.js +20 -17
- package/bin/deploy/to-hana/cfUtil.js +16 -19
- package/bin/deploy/to-hana/hana.js +7 -24
- package/bin/deploy/to-hana/hdiDeployUtil.js +8 -4
- package/bin/mtx/in-cds.js +2 -2
- package/bin/serve.js +12 -5
- package/bin/utils/modules.js +7 -0
- package/bin/version.js +56 -3
- package/lib/compile/cdsc.js +26 -3
- package/lib/compile/etc/_localized.js +36 -25
- package/lib/compile/etc/csv.js +8 -8
- package/lib/compile/for/drafts.js +9 -0
- package/lib/compile/for/java.js +16 -0
- package/lib/compile/for/nodejs.js +12 -0
- package/lib/compile/for/odata.js +1 -1
- package/lib/compile/index.js +3 -0
- package/lib/compile/minify.js +16 -2
- package/lib/compile/parse.js +2 -2
- package/lib/compile/resolve.js +35 -18
- package/lib/compile/to/json.js +3 -1
- package/lib/compile/to/sql.js +2 -2
- package/lib/compile/to/srvinfo.js +4 -2
- package/lib/connect/index.js +1 -1
- package/lib/core/entities.js +15 -14
- package/lib/core/index.js +39 -36
- package/lib/core/reflect.js +4 -2
- package/lib/deploy.js +114 -127
- package/lib/env/defaults.js +1 -0
- package/lib/env/index.js +165 -165
- package/lib/env/presets.js +1 -0
- package/lib/env/requires.js +120 -49
- package/lib/index.js +1 -0
- package/lib/log/format/kibana.js +2 -2
- package/lib/ql/SELECT.js +10 -0
- package/lib/ql/parse.js +1 -0
- package/lib/req/cds-context.js +4 -1
- package/lib/req/context.js +50 -56
- package/lib/req/event.js +1 -6
- package/lib/req/locale.js +6 -5
- package/lib/req/request.js +2 -0
- package/lib/req/user.js +7 -5
- package/lib/serve/Service-api.js +10 -7
- package/lib/serve/Service-dispatch.js +9 -11
- package/lib/serve/Service-methods.js +30 -41
- package/lib/serve/Transaction.js +10 -7
- package/lib/serve/adapters.js +7 -5
- package/lib/serve/index.js +24 -12
- package/lib/utils/data.js +1 -1
- package/lib/utils/index.js +27 -30
- package/lib/utils/resources/index.js +101 -0
- package/lib/utils/resources/tar.js +71 -0
- package/lib/utils/resources/utils.js +11 -0
- package/libx/_runtime/audit/Service.js +36 -39
- package/libx/_runtime/audit/generic/personal/access.js +3 -4
- package/libx/_runtime/audit/generic/personal/modification.js +3 -4
- package/libx/_runtime/audit/utils/v2.js +1 -2
- package/libx/_runtime/auth/index.js +126 -84
- package/libx/_runtime/auth/strategies/JWT.js +12 -19
- package/libx/_runtime/auth/strategies/dummy.js +1 -5
- package/libx/_runtime/auth/strategies/dwc.js +11 -9
- package/libx/_runtime/auth/strategies/mock.js +0 -4
- package/libx/_runtime/auth/strategies/{utils/xssec.js → xssecUtils.js} +7 -4
- package/libx/_runtime/auth/strategies/xsuaa.js +12 -19
- package/libx/_runtime/auth/utils.js +22 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/Dispatcher.js +104 -98
- package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +2 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/action.js +13 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/language.js +2 -8
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +4 -29
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +2 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +3 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +2 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +4 -6
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/expandToCQN.js +24 -21
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/index.js +8 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/UriHelper.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/DeserializerFactory.js +2 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/ResourceJsonDeserializer.js +5 -6
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/invocation/DispatcherCommand.js +2 -6
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/utils/UriHelper.js +4 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/to.js +1 -12
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +33 -9
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/dispatcherUtils.js +50 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +2 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/request.js +10 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +9 -11
- package/libx/_runtime/cds-services/adapter/rest/RestRequest.js +6 -3
- package/libx/_runtime/cds-services/adapter/rest/handlers/operation.js +4 -2
- package/libx/_runtime/cds-services/adapter/rest/rest-to-cqn/utils.js +1 -1
- package/libx/_runtime/cds-services/adapter/rest/utils/binary.js +1 -1
- package/libx/_runtime/cds-services/adapter/rest/utils/key-value-utils.js +2 -3
- package/libx/_runtime/cds-services/adapter/rest/utils/parse-url.js +6 -4
- package/libx/_runtime/cds-services/adapter/rest/utils/result.js +1 -0
- package/libx/_runtime/cds-services/adapter/rest/utils/validation-checks.js +8 -5
- package/libx/_runtime/cds-services/services/Service.js +40 -0
- package/libx/_runtime/cds-services/services/utils/columns.js +4 -3
- package/libx/_runtime/cds-services/services/utils/compareJson.js +4 -4
- package/libx/_runtime/cds-services/services/utils/differ.js +3 -3
- package/libx/_runtime/cds-services/services/utils/handlerUtils.js +4 -4
- package/libx/_runtime/cds-services/services/utils/restrictions.js +78 -0
- package/libx/_runtime/cds-services/util/assert.js +20 -14
- package/libx/_runtime/cds.js +9 -1
- package/libx/_runtime/common/aspects/any.js +5 -0
- package/libx/_runtime/common/aspects/entity.js +25 -7
- package/libx/_runtime/common/aspects/utils.js +2 -2
- package/libx/_runtime/common/composition/data.js +6 -0
- package/libx/_runtime/common/composition/insert.js +3 -2
- package/libx/_runtime/common/composition/tree.js +4 -10
- package/libx/_runtime/common/composition/update.js +4 -4
- package/libx/_runtime/common/constants/draft.js +29 -26
- package/libx/_runtime/common/error/constants.js +2 -2
- package/libx/_runtime/common/error/frontend.js +7 -15
- package/libx/_runtime/common/generic/auth/capabilities.js +59 -0
- package/libx/_runtime/common/generic/auth/constants.js +20 -0
- package/libx/_runtime/common/generic/auth/expand.js +54 -0
- package/libx/_runtime/common/generic/auth/index.js +32 -0
- package/libx/_runtime/common/generic/auth/insertOnly.js +15 -0
- package/libx/_runtime/common/generic/auth/readOnly.js +26 -0
- package/libx/_runtime/common/generic/auth/requires.js +34 -0
- package/libx/_runtime/common/generic/auth/restrict.js +296 -0
- package/libx/_runtime/common/generic/auth/utils.js +213 -0
- package/libx/_runtime/common/generic/crud.js +14 -10
- package/libx/_runtime/common/generic/etag.js +1 -1
- package/libx/_runtime/common/generic/input.js +35 -35
- package/libx/_runtime/common/generic/sorting.js +2 -3
- package/libx/_runtime/common/generic/temporal.js +2 -2
- package/libx/_runtime/common/i18n/index.js +2 -31
- package/libx/_runtime/common/i18n/messages.properties +1 -1
- package/libx/_runtime/common/toggles/handler.js +21 -0
- package/libx/_runtime/common/utils/copy.js +10 -1
- package/libx/_runtime/common/utils/cqn2cqn4sql.js +100 -29
- package/libx/_runtime/common/utils/csn.js +63 -1
- package/libx/_runtime/common/utils/dollar.js +10 -1
- package/libx/_runtime/common/utils/draft.js +46 -7
- package/libx/_runtime/common/utils/entityFromCqn.js +13 -9
- package/libx/_runtime/common/utils/extensibilityUtils.js +18 -0
- package/libx/_runtime/common/utils/foreignKeyPropagations.js +88 -104
- package/libx/_runtime/common/utils/generateOnCond.js +9 -6
- package/libx/_runtime/common/utils/quotingStyles.js +2 -0
- package/libx/_runtime/common/utils/resolveStructured.js +25 -9
- package/libx/_runtime/common/utils/resolveView.js +4 -1
- package/libx/_runtime/common/utils/rewriteAsterisks.js +3 -16
- package/libx/_runtime/common/utils/structured.js +33 -37
- package/libx/_runtime/common/utils/template.js +17 -8
- package/libx/_runtime/common/utils/templateProcessor.js +28 -28
- package/libx/_runtime/db/data-conversion/post-processing.js +118 -417
- package/libx/_runtime/db/expand/expandCQNToJoin.js +45 -41
- package/libx/_runtime/db/expand/rawToExpanded.js +29 -8
- package/libx/_runtime/db/generic/index.js +1 -3
- package/libx/_runtime/db/generic/input.js +5 -10
- package/libx/_runtime/db/generic/rewrite.js +5 -2
- package/libx/_runtime/db/generic/structured.js +2 -2
- package/libx/_runtime/db/query/delete.js +2 -2
- package/libx/_runtime/db/query/insert.js +1 -1
- package/libx/_runtime/db/query/update.js +9 -14
- package/libx/_runtime/db/sql-builder/CreateBuilder.js +4 -3
- package/libx/_runtime/db/sql-builder/InsertBuilder.js +14 -1
- package/libx/_runtime/db/sql-builder/SelectBuilder.js +3 -2
- package/libx/_runtime/db/sql-builder/dataTypes.js +3 -3
- package/libx/_runtime/db/utils/columns.js +3 -3
- package/libx/_runtime/db/utils/normalizeTimeData.js +2 -2
- package/libx/_runtime/db/utils/propagateForeignKeys.js +6 -2
- package/libx/_runtime/extensibility/mps/index.js +5 -0
- package/libx/_runtime/extensibility/mps/service.js +111 -0
- package/libx/_runtime/extensibility/mps/tar.js +42 -0
- package/libx/_runtime/extensibility/mps/utils.js +11 -0
- package/libx/_runtime/{fiori → extensibility}/uiflex/handler/transformREAD.js +0 -0
- package/libx/_runtime/{fiori → extensibility}/uiflex/handler/transformRESULT.js +17 -5
- package/libx/_runtime/{fiori → extensibility}/uiflex/handler/transformWRITE.js +1 -0
- package/libx/_runtime/extensibility/uiflex/index.js +54 -0
- package/libx/_runtime/extensibility/uiflex/service.js +276 -0
- package/libx/_runtime/{fiori → extensibility}/uiflex/utils.js +22 -7
- package/libx/_runtime/fiori/generic/activate.js +2 -2
- package/libx/_runtime/fiori/generic/before.js +4 -4
- package/libx/_runtime/fiori/generic/new.js +3 -3
- package/libx/_runtime/fiori/generic/patch.js +1 -1
- package/libx/_runtime/fiori/generic/read.js +58 -66
- package/libx/_runtime/fiori/generic/readOverDraft.js +71 -16
- package/libx/_runtime/fiori/utils/handler.js +6 -13
- package/libx/_runtime/fiori/utils/where.js +6 -5
- package/libx/_runtime/hana/Service.js +4 -10
- package/libx/_runtime/hana/customBuilder/CustomSelectBuilder.js +2 -2
- package/libx/_runtime/hana/driver.js +2 -2
- package/libx/_runtime/hana/execute.js +29 -75
- package/libx/_runtime/hana/pool.js +1 -1
- package/libx/_runtime/hana/streaming.js +2 -1
- package/libx/_runtime/index.js +6 -6
- package/libx/_runtime/messaging/AMQPWebhookMessaging.js +5 -21
- package/libx/_runtime/messaging/Outbox.js +2 -2
- package/libx/_runtime/messaging/common-utils/AMQPClient.js +4 -14
- package/libx/_runtime/messaging/common-utils/connections.js +5 -7
- package/libx/_runtime/messaging/common-utils/normalizeIncomingMessage.js +30 -0
- package/libx/_runtime/messaging/enterprise-messaging-shared.js +2 -1
- package/libx/_runtime/messaging/enterprise-messaging-utils/EMManagement.js +36 -30
- package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +19 -12
- package/libx/_runtime/messaging/enterprise-messaging.js +8 -8
- package/libx/_runtime/messaging/file-based.js +5 -5
- package/libx/_runtime/messaging/message-queuing.js +14 -12
- package/libx/_runtime/messaging/outbox/utils.js +18 -19
- package/libx/_runtime/messaging/redis-messaging.js +91 -0
- package/libx/_runtime/messaging/service.js +8 -6
- package/libx/_runtime/remote/Service.js +44 -8
- package/libx/_runtime/remote/utils/client.js +25 -13
- package/libx/_runtime/remote/utils/data.js +11 -11
- package/libx/_runtime/sqlite/Service.js +6 -9
- package/libx/_runtime/sqlite/customBuilder/CustomFunctionBuilder.js +5 -2
- package/libx/_runtime/types/api.js +10 -2
- package/libx/common/utils/ucsn.js +109 -0
- package/libx/gql/resolvers/crud/create.js +6 -1
- package/libx/gql/resolvers/crud/delete.js +6 -1
- package/libx/gql/resolvers/crud/read.js +6 -1
- package/libx/gql/resolvers/crud/update.js +9 -1
- package/libx/gql/resolvers/parse/ast2cqn/columns.js +3 -1
- package/libx/gql/schema/typeDefMap.js +2 -2
- package/libx/odata/afterburner.js +110 -16
- package/libx/odata/grammar.pegjs +9 -1
- package/libx/odata/parseToCqn.js +39 -0
- package/libx/odata/parser.js +1 -1
- package/libx/rest/RestAdapter.js +9 -1
- package/libx/rest/middleware/input.js +54 -0
- package/libx/rest/middleware/operation.js +14 -1
- package/libx/rest/middleware/parse.js +11 -7
- package/package.json +1 -1
- package/server.js +34 -19
- package/srv/audit-log.cds +2 -2
- package/srv/flex.cds +8 -2
- package/srv/flex.js +1 -1
- package/srv/mps.cds +23 -0
- package/srv/mps.js +1 -0
- package/libx/_runtime/auth/strategies/utils/uaa.js +0 -21
- package/libx/_runtime/common/generic/auth.js +0 -874
- package/libx/_runtime/common/toggles/alpha.js +0 -43
- package/libx/_runtime/db/generic/arrayed.js +0 -33
- package/libx/_runtime/fiori/uiflex/index.js +0 -35
- package/libx/_runtime/fiori/uiflex/service.js +0 -150
- package/libx/rest/utils/data.js +0 -60
|
@@ -1,50 +1,7 @@
|
|
|
1
|
-
const
|
|
2
|
-
|
|
3
|
-
const {
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Check if the value is a function or reference to private function.
|
|
7
|
-
* Return if any of the cases are true.
|
|
8
|
-
*
|
|
9
|
-
* @param {string|Function} fn -
|
|
10
|
-
* @returns {Function}
|
|
11
|
-
* @throws Error if no valid parameter fn provided
|
|
12
|
-
* @private
|
|
13
|
-
*/
|
|
14
|
-
const _getMethod = fn => {
|
|
15
|
-
if (typeof fn === 'function') {
|
|
16
|
-
return fn
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
throw new Error(`Method "${fn}" does not exist.`)
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Get the entity name from CQN and check if it exists at CSN.
|
|
24
|
-
*
|
|
25
|
-
* @param {object} csn - Reflected CSN
|
|
26
|
-
* @param {string} from - Entity name
|
|
27
|
-
* @returns {string|undefined}
|
|
28
|
-
* @private
|
|
29
|
-
*/
|
|
30
|
-
const _getEntityName = (csn, from) => {
|
|
31
|
-
if (!from.ref || typeof csn !== 'object') {
|
|
32
|
-
return
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
let entityName = from.ref[0].id ? from.ref[0].id : from.ref[0]
|
|
36
|
-
|
|
37
|
-
if (csn.definitions && csn.definitions[entityName]) {
|
|
38
|
-
return entityName
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// REVISIT: Find better solution
|
|
42
|
-
entityName = entityName.replace(/_drafts$/i, '')
|
|
43
|
-
|
|
44
|
-
if (csn.definitions && csn.definitions[entityName]) {
|
|
45
|
-
return entityName
|
|
46
|
-
}
|
|
47
|
-
}
|
|
1
|
+
const { getEntityNameFromCQN, traverseFroms } = require('../../common/utils/entityFromCqn')
|
|
2
|
+
const { ensureNoDraftsSuffix } = require('../../common/utils/draft')
|
|
3
|
+
const { proxifyIfFlattened } = require('../../../common/utils/ucsn')
|
|
4
|
+
const cds = require('../../../../lib')
|
|
48
5
|
|
|
49
6
|
const _refs = (refs, as) => {
|
|
50
7
|
const arr = []
|
|
@@ -90,114 +47,135 @@ const _extractRefs = (from, as) => {
|
|
|
90
47
|
return [ref]
|
|
91
48
|
}
|
|
92
49
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
// ambiguous cases will lead to SQL syntax errors anyway, so no need for a check
|
|
102
|
-
elements.set(key, convertFunction)
|
|
103
|
-
if (includeAlias && alias) {
|
|
104
|
-
elements.set(`${alias}_${key}`, convertFunction)
|
|
50
|
+
const _getCastFunction = ({ type }) => {
|
|
51
|
+
switch (type) {
|
|
52
|
+
case 'cds.Boolean':
|
|
53
|
+
return Boolean
|
|
54
|
+
case 'cds.Integer':
|
|
55
|
+
return Number
|
|
56
|
+
default:
|
|
57
|
+
return String
|
|
105
58
|
}
|
|
106
59
|
}
|
|
107
60
|
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const _addMapperFunction4struct = (elements, toService, parent, struct, alias, includeAlias) => {
|
|
113
|
-
for (const k in struct.elements) {
|
|
114
|
-
const current = struct.elements[k]
|
|
115
|
-
if (current._isStructured) {
|
|
116
|
-
_addMapperFunction4struct(elements, toService, `${parent}_${k}`, current, alias, includeAlias)
|
|
117
|
-
} else {
|
|
118
|
-
_addMapperFunction(elements, toService, `${parent}_${k}`, current.type, alias, includeAlias)
|
|
119
|
-
}
|
|
61
|
+
const _structElement = (definition, structPath) => {
|
|
62
|
+
if (definition.elements) {
|
|
63
|
+
return _structElement(definition.elements[structPath[0]], structPath.slice(1))
|
|
120
64
|
}
|
|
121
|
-
}
|
|
122
65
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
*
|
|
126
|
-
* @param {Map} toService - Mapping instructions for data conversions based on CDS data types
|
|
127
|
-
* @param {object} csn - Reflected CSN
|
|
128
|
-
* @param {object} cqn - CQN that is used to query the DB.
|
|
129
|
-
* @returns {Map<any, any>}
|
|
130
|
-
* @private
|
|
131
|
-
*/
|
|
132
|
-
const _getElementCombinations = (toService, csn, cqn, includeAlias = false) => {
|
|
133
|
-
const elements = new Map()
|
|
66
|
+
return definition
|
|
67
|
+
}
|
|
134
68
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
const entityName = _getEntityName(csn, from)
|
|
69
|
+
const _getNestedElement = (entity, key) => {
|
|
70
|
+
if (entity.elements[key]) return entity.elements[key]
|
|
138
71
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
}
|
|
72
|
+
const structPath = entity._flat2struct[key]
|
|
73
|
+
if (!structPath) return
|
|
142
74
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
const element = entity.elements[key]
|
|
146
|
-
if (element._isStructured) {
|
|
147
|
-
_addMapperFunction4struct(elements, toService, key, element, from.as, includeAlias)
|
|
148
|
-
} else {
|
|
149
|
-
if ('SET' in cqn.SELECT.from) {
|
|
150
|
-
_addMapperFunction(elements, toService, key, element.type, cqn.SELECT.from.as, includeAlias)
|
|
151
|
-
} else {
|
|
152
|
-
_addMapperFunction(elements, toService, key, element.type, from.as, includeAlias)
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
75
|
+
return _structElement(entity, structPath)
|
|
76
|
+
}
|
|
157
77
|
|
|
158
|
-
|
|
78
|
+
const _structure = csnEntity => (value, key, row, unaliasedKey) => {
|
|
79
|
+
proxifyIfFlattened(csnEntity, row)
|
|
80
|
+
const effectiveKey = unaliasedKey || key
|
|
81
|
+
delete row[effectiveKey]
|
|
82
|
+
row[effectiveKey] = value
|
|
159
83
|
}
|
|
160
84
|
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
85
|
+
const _addConverter = (mapper, name, converter) => {
|
|
86
|
+
if (mapper.has(name)) {
|
|
87
|
+
const oldConverter = mapper.get(name)
|
|
88
|
+
mapper.set(name, (val, key, row, unaliasedKey) => {
|
|
89
|
+
oldConverter(val, key, row, unaliasedKey)
|
|
90
|
+
converter(row[unaliasedKey || key], key, row, unaliasedKey)
|
|
91
|
+
})
|
|
92
|
+
} else {
|
|
93
|
+
mapper.set(name, converter)
|
|
169
94
|
}
|
|
170
95
|
}
|
|
171
96
|
|
|
172
97
|
/**
|
|
173
98
|
* Get a map of to be converted elements and their conversion functions.
|
|
174
99
|
*
|
|
175
|
-
* @param {Map}
|
|
100
|
+
* @param {Map} conversionMap - Mapping instructions for data conversions based on CDS data types
|
|
176
101
|
* @param {object} csn - Reflected CSN
|
|
177
102
|
* @param {object} cqn - CQN that is used to query the DB.
|
|
178
103
|
* @returns {Map<any, any>}
|
|
179
104
|
* @private
|
|
180
105
|
*/
|
|
181
|
-
|
|
182
|
-
|
|
106
|
+
// eslint-disable-next-line complexity
|
|
107
|
+
const _getMapperForListedElements = (conversionMap, csn, cqn) => {
|
|
183
108
|
const mapper = new Map()
|
|
184
109
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
const
|
|
110
|
+
const alias2entity = {}
|
|
111
|
+
if (cqn.SELECT.from.args) {
|
|
112
|
+
for (const each of cqn.SELECT.from.args) {
|
|
113
|
+
const { entityName, alias } = getEntityNameFromCQN(each)
|
|
114
|
+
let as = each.as || alias
|
|
115
|
+
if (as) as = ensureNoDraftsSuffix(as) // > in comp2one, the alias gets suffixed with "_drafts"
|
|
116
|
+
alias2entity[as] =
|
|
117
|
+
csn.definitions[ensureNoDraftsSuffix(entityName)] || csn.definitions[entityName.replace(/\.drafts$/, '')]
|
|
118
|
+
}
|
|
119
|
+
// additionally, for deeply nested args, find pairs of single-element ref + as and build alias to entity mapping
|
|
120
|
+
const ref2as = []
|
|
121
|
+
traverseFroms(cqn.SELECT.from, from => ref2as.push({ ref: from.ref, as: from.as }))
|
|
122
|
+
for (const each of ref2as) {
|
|
123
|
+
alias2entity[each.as] =
|
|
124
|
+
csn.definitions[ensureNoDraftsSuffix(each.ref[0])] || csn.definitions[each.ref[0].replace(/\.drafts$/, '')]
|
|
125
|
+
}
|
|
126
|
+
} else {
|
|
127
|
+
const { entityName } = getEntityNameFromCQN(cqn)
|
|
128
|
+
alias2entity[0] = csn.definitions[ensureNoDraftsSuffix(entityName)]
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
for (const col of cqn.SELECT.columns) {
|
|
132
|
+
if (col.cast) {
|
|
133
|
+
const name = col.as ? col.as : col.ref[col.ref.length - 1]
|
|
134
|
+
_addConverter(mapper, name, (val, key, row, unaliasedKey) => {
|
|
135
|
+
row[unaliasedKey || key] = _getCastFunction(col.cast)(val)
|
|
136
|
+
})
|
|
137
|
+
continue
|
|
138
|
+
}
|
|
139
|
+
if (col.ref) {
|
|
140
|
+
const name = col.ref[col.ref.length - 1]
|
|
141
|
+
|
|
142
|
+
const entity =
|
|
143
|
+
col.ref.length > 1
|
|
144
|
+
? alias2entity[col.ref[0]] || alias2entity[0]
|
|
145
|
+
: alias2entity[0] || alias2entity[getEntityNameFromCQN(cqn).alias]
|
|
146
|
+
if (!entity) {
|
|
147
|
+
// REVISIT: should not be necessary, but HasActiveEntity is not always prefixed with alias
|
|
148
|
+
if (col.ref.length === 1 && col.ref[0] === 'HasActiveEntity')
|
|
149
|
+
_addConverter(mapper, col.as ? col.as : name, (val, key, row, unaliasedKey) => {
|
|
150
|
+
row[unaliasedKey || key] = conversionMap.get('cds.Boolean')(val)
|
|
151
|
+
})
|
|
152
|
+
continue
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const element = _getNestedElement(entity, name)
|
|
156
|
+
if (!element) continue
|
|
157
|
+
|
|
158
|
+
// REVISIT: _type is undefined for cds.hana.CLOB etc.
|
|
159
|
+
const type = element._type || element.type
|
|
160
|
+
if (conversionMap.has(type)) {
|
|
161
|
+
_addConverter(mapper, col.as ? col.as : name, (val, key, row, unaliasedKey) => {
|
|
162
|
+
row[unaliasedKey || key] = conversionMap.get(type)(val)
|
|
163
|
+
})
|
|
164
|
+
} else if (element.items) {
|
|
165
|
+
_addConverter(mapper, col.as ? col.as : name, (val, key, row, unaliasedKey) => {
|
|
166
|
+
const effectiveKey = unaliasedKey || key
|
|
167
|
+
row[effectiveKey] = JSON.parse(val)
|
|
168
|
+
}) // > arrayed elements
|
|
169
|
+
}
|
|
189
170
|
|
|
190
|
-
if (
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
mapper.set(name || element.ref[element.ref.length - 1], elements.get(element.ref.join('_')))
|
|
171
|
+
if (
|
|
172
|
+
cds.env.features.ucsn_struct_conversion &&
|
|
173
|
+
element.parent &&
|
|
174
|
+
element.parent._isStructured &&
|
|
175
|
+
!element._isStructured
|
|
176
|
+
) {
|
|
177
|
+
_addConverter(mapper, col.as ? col.as : name, _structure(entity))
|
|
198
178
|
}
|
|
199
|
-
} else if (element.as && element.cast) {
|
|
200
|
-
mapper.set(element.as, _getCastFunction(element.cast))
|
|
201
179
|
}
|
|
202
180
|
}
|
|
203
181
|
|
|
@@ -207,143 +185,20 @@ const _getMapperForListedElements = (toService, csn, cqn) => {
|
|
|
207
185
|
/**
|
|
208
186
|
* Based on CSN and CQN get a map on how to map the result.
|
|
209
187
|
*
|
|
210
|
-
* @param {Map}
|
|
188
|
+
* @param {Map} conversionMap - Mapping instructions for data conversions based on CDS data types
|
|
211
189
|
* @param {object} csn - Reflected CSN
|
|
212
190
|
* @param {object} cqn - CQN that is used to query the DB.
|
|
213
191
|
* @returns {Map<any, any>}
|
|
214
192
|
* @private
|
|
215
193
|
*/
|
|
216
|
-
const getPostProcessMapper = (
|
|
217
|
-
|
|
218
|
-
if (!Object.prototype.hasOwnProperty.call(cqn, 'SELECT')) {
|
|
219
|
-
return new Map()
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
if (Array.isArray(cqn.SELECT.columns) && cqn.SELECT.columns.length !== 0 && !cqn.SELECT.columns.includes('*')) {
|
|
223
|
-
return _getMapperForListedElements(toService, csn, cqn)
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// No element/column specified
|
|
227
|
-
return _getElementCombinations(toService, csn, cqn)
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
const _getCombineStructureConvert = (structure, columnName, propName, fn) => {
|
|
231
|
-
const length = structure.length
|
|
232
|
-
|
|
233
|
-
return row => {
|
|
234
|
-
if (row[columnName] === undefined) {
|
|
235
|
-
return
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
if (!row[structure[0]]) {
|
|
239
|
-
row[structure[0]] = {}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
let subObj = row[structure[0]]
|
|
243
|
-
|
|
244
|
-
for (let i = 1; i < length; i++) {
|
|
245
|
-
subObj = subObj[structure[i]] = {}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
subObj[propName] = fn ? fn(row[columnName]) : row[columnName]
|
|
249
|
-
|
|
250
|
-
delete row[columnName]
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
const _getCombineRenameConvert = (columnName, propName, fn) => {
|
|
255
|
-
return row => {
|
|
256
|
-
if (row[columnName] === undefined) {
|
|
257
|
-
return
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
row[propName] = fn ? fn(row[columnName]) : row[columnName]
|
|
261
|
-
delete row[columnName]
|
|
262
|
-
}
|
|
194
|
+
const getPostProcessMapper = (conversionMap, csn = {}, cqn = {}) => {
|
|
195
|
+
return cqn.SELECT.columns ? _getMapperForListedElements(conversionMap, csn, cqn) : new Map()
|
|
263
196
|
}
|
|
264
197
|
|
|
265
|
-
const
|
|
266
|
-
return row => {
|
|
267
|
-
row[columnName] = fn(row[columnName])
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
const _getRemoveMapper = (mapper, propName) => {
|
|
272
|
-
if (mapper) {
|
|
273
|
-
const fn = mapper.get(propName)
|
|
274
|
-
mapper.delete(propName)
|
|
275
|
-
|
|
276
|
-
return fn
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
const _propertyMapper = (dataMapper, propertyMapper, objStructMapper, mapper) => {
|
|
281
|
-
if (!propertyMapper) {
|
|
282
|
-
return
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
for (const [columnName, propName] of propertyMapper.entries()) {
|
|
286
|
-
const fn = _getRemoveMapper(dataMapper, propName)
|
|
287
|
-
const structure = _getRemoveMapper(objStructMapper, propName)
|
|
288
|
-
|
|
289
|
-
mapper.push(
|
|
290
|
-
structure
|
|
291
|
-
? _getCombineStructureConvert(structure, columnName, propName, fn)
|
|
292
|
-
: _getCombineRenameConvert(columnName, propName, fn)
|
|
293
|
-
)
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
const _objStructMapper = (dataMapper, propertyMapper, objStructMapper, mapper) => {
|
|
298
|
-
if (!objStructMapper) {
|
|
299
|
-
return
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
for (const [propName, structure] of objStructMapper.entries()) {
|
|
303
|
-
mapper.push(_getCombineStructureConvert(structure, propName, propName, _getRemoveMapper(dataMapper, propName)))
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
const _dataMapper = (dataMapper, propertyMapper, objStructMapper, mapper) => {
|
|
308
|
-
if (!dataMapper) {
|
|
309
|
-
return
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
for (const [columnName, converter] of dataMapper.entries()) {
|
|
313
|
-
mapper.push(_getConvert(columnName, converter))
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
/**
|
|
318
|
-
* Generate the mapper per row up front, so that we do not have to iterate over possibly three mappers
|
|
319
|
-
*
|
|
320
|
-
* @param dataMapper
|
|
321
|
-
* @param propertyMapper
|
|
322
|
-
* @param objStructMapper
|
|
323
|
-
* @returns {Array}
|
|
324
|
-
* @private
|
|
325
|
-
*/
|
|
326
|
-
const _combineMappers = (dataMapper, propertyMapper, objStructMapper) => {
|
|
327
|
-
const mapper = []
|
|
328
|
-
|
|
329
|
-
// Technical names + optionally structure and/or type conversions
|
|
330
|
-
_propertyMapper(dataMapper, propertyMapper, objStructMapper, mapper)
|
|
331
|
-
|
|
332
|
-
// Deep structures + optionally type conversions
|
|
333
|
-
_objStructMapper(dataMapper, propertyMapper, objStructMapper, mapper)
|
|
334
|
-
|
|
335
|
-
// type conversion
|
|
336
|
-
_dataMapper(dataMapper, propertyMapper, objStructMapper, mapper)
|
|
337
|
-
|
|
338
|
-
return mapper
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
const _processRow = (mapper, mapperCount, row) => {
|
|
342
|
-
// REVISIT: when is this the case?
|
|
198
|
+
const _processRow = (mapper, row) => {
|
|
343
199
|
if (!row) return
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
mapper[i](row)
|
|
200
|
+
for (const [columnName, converter] of mapper.entries()) {
|
|
201
|
+
converter(row[columnName], columnName, row)
|
|
347
202
|
}
|
|
348
203
|
}
|
|
349
204
|
|
|
@@ -351,179 +206,25 @@ const _processRow = (mapper, mapperCount, row) => {
|
|
|
351
206
|
* Post process the result as given by the db driver.
|
|
352
207
|
*
|
|
353
208
|
* @param {*} result - The result as returned by the db driver.
|
|
354
|
-
* @param {Map}
|
|
209
|
+
* @param {Map} mapper - Instructions, how to transform.
|
|
355
210
|
* @param {Map} propertyMapper - Instructions, how to rename properties.
|
|
356
211
|
* @param {Map} objStructMapper - Instructions, how to rename properties.
|
|
357
212
|
* @returns {*}
|
|
358
213
|
* @private
|
|
359
214
|
*/
|
|
360
|
-
const postProcess = (result,
|
|
361
|
-
|
|
362
|
-
const mapperCount = mapper.length
|
|
363
|
-
|
|
364
|
-
if (mapperCount === 0) {
|
|
365
|
-
return result
|
|
366
|
-
}
|
|
215
|
+
const postProcess = (result, mapper = new Map()) => {
|
|
216
|
+
if (mapper.size === 0) return result
|
|
367
217
|
|
|
368
|
-
if (Array.isArray(result))
|
|
369
|
-
|
|
370
|
-
_processRow(mapper, mapperCount, result[i])
|
|
371
|
-
}
|
|
372
|
-
} else {
|
|
373
|
-
_processRow(mapper, mapperCount, result)
|
|
374
|
-
}
|
|
218
|
+
if (Array.isArray(result)) for (const each of result) _processRow(mapper, each)
|
|
219
|
+
else _processRow(mapper, result)
|
|
375
220
|
|
|
376
221
|
return result
|
|
377
222
|
}
|
|
378
223
|
|
|
379
|
-
const _checkExpressionsAmbiguousNaming = (csn, entity, element) => {
|
|
380
|
-
if (!entity.as || !Array.isArray(element.ref)) {
|
|
381
|
-
return
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
if (
|
|
385
|
-
entity.as === element.ref[0] &&
|
|
386
|
-
csn.definitions[entity.ref[0]] &&
|
|
387
|
-
csn.definitions[entity.ref[0]].elements[element.ref[1]] &&
|
|
388
|
-
csn.definitions[entity.ref[0]].elements[element.ref[0]] &&
|
|
389
|
-
csn.definitions[entity.ref[0]].elements[element.ref[0]].isAssociation
|
|
390
|
-
) {
|
|
391
|
-
throw new Error(`Ambiguous entity property and alias name: "${entity.as}"`)
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
const _checkColumnsAmbiguousNaming = (csn, entity, columns) => {
|
|
396
|
-
for (const element of columns) {
|
|
397
|
-
_checkExpressionsAmbiguousNaming(csn, entity, element)
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
const _checkJoinAmbiguousNaming = (csn, select) => {
|
|
402
|
-
for (const subSelect of select.from.args) {
|
|
403
|
-
if (Array.isArray(select.columns)) {
|
|
404
|
-
_checkColumnsAmbiguousNaming(csn, subSelect, select.columns)
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
const _checkSelectAmbiguousNaming = (csn, select) => {
|
|
410
|
-
if (Array.isArray(select.columns)) {
|
|
411
|
-
_checkColumnsAmbiguousNaming(csn, select.from, select.columns)
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
const _checkRecursiveSelectAmbiguousNaming = (csn, select) => {
|
|
416
|
-
if (select.from.SELECT) {
|
|
417
|
-
_checkRecursiveSelectAmbiguousNaming(csn, select.from.SELECT)
|
|
418
|
-
} else if (select.from.join) {
|
|
419
|
-
_checkJoinAmbiguousNaming(csn, select)
|
|
420
|
-
} else if (select.from.as) {
|
|
421
|
-
// Check innermost select statement
|
|
422
|
-
_checkSelectAmbiguousNaming(csn, select)
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
const getStructMapper = (csn, cqn, propertyMapper) => {
|
|
427
|
-
if (csn && cqn.SELECT) {
|
|
428
|
-
_checkRecursiveSelectAmbiguousNaming(csn, cqn.SELECT)
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
// REVISIT still needed?
|
|
432
|
-
|
|
433
|
-
return new Map()
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
const _addToMap = (map, key) => {
|
|
437
|
-
const allUpperKey = key.toUpperCase()
|
|
438
|
-
|
|
439
|
-
if (key === allUpperKey) {
|
|
440
|
-
return
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
map.set(allUpperKey, key)
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
const _addColumn = (map, from, element) => {
|
|
447
|
-
_addToMap(map, element)
|
|
448
|
-
|
|
449
|
-
if (from.ref[0] && from.ref[0].id) {
|
|
450
|
-
_addToMap(map, `${from.ref[0].id}.${element}`)
|
|
451
|
-
} else {
|
|
452
|
-
if (from.ref) {
|
|
453
|
-
_addToMap(map, `${from.ref.join('.')}.${element}`)
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
if (from.as) {
|
|
458
|
-
_addToMap(map, `${from.as}.${element}`)
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
const _addAssociationToMap = (map, from, element) => {
|
|
463
|
-
const assocs = element.keys ? element.keys.map(key => `${element.name}_${key.ref[0]}`) : []
|
|
464
|
-
for (const assocName of assocs) {
|
|
465
|
-
_addColumn(map, from, assocName)
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
const _addComplexTypeToMap = (map, from, name, element) => {
|
|
470
|
-
for (const complexName in element.elements) {
|
|
471
|
-
_addColumn(map, from, `${name}_${complexName}`)
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
const _getKeyMapForAllElements = (csn, cqn) => {
|
|
476
|
-
const map = new Map()
|
|
477
|
-
|
|
478
|
-
// Get list of available and relevant entities as defined by from
|
|
479
|
-
for (const from of _extractRefs(cqn.SELECT.from)) {
|
|
480
|
-
const entityName = _getEntityName(csn, from)
|
|
481
|
-
|
|
482
|
-
if (!entityName) {
|
|
483
|
-
continue
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
for (const name in csn.definitions[entityName].elements) {
|
|
487
|
-
const element = csn.definitions[entityName].elements[name]
|
|
488
|
-
|
|
489
|
-
if (element.isAssociation) {
|
|
490
|
-
_addAssociationToMap(map, from, element)
|
|
491
|
-
} else if (element._isStructured) {
|
|
492
|
-
_addComplexTypeToMap(map, from, name, element)
|
|
493
|
-
} else {
|
|
494
|
-
_addColumn(map, from, name)
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
return map
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
/**
|
|
503
|
-
* Provide a map with to be renamed properties.
|
|
504
|
-
*
|
|
505
|
-
* @param {object} csn - Reflected CSN
|
|
506
|
-
* @param {object} cqn - CQN that is used to query the DB.
|
|
507
|
-
* @returns {Map<any, any>}
|
|
508
|
-
*/
|
|
509
|
-
const getPropertyMapper = (csn, cqn) => {
|
|
510
|
-
if (
|
|
511
|
-
cds.env.sql.names === 'plain' &&
|
|
512
|
-
cqn.SELECT &&
|
|
513
|
-
(cqn.SELECT.columns === undefined || (cqn.SELECT.columns && cqn.SELECT.columns.includes('*')))
|
|
514
|
-
) {
|
|
515
|
-
return _getKeyMapForAllElements(csn, cqn)
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
return new Map()
|
|
519
|
-
}
|
|
520
|
-
|
|
521
224
|
/*
|
|
522
225
|
* this module is required by cds-pg. -> in case of incompatible changes, we should let them know.
|
|
523
226
|
*/
|
|
524
227
|
module.exports = {
|
|
525
|
-
getPropertyMapper,
|
|
526
228
|
getPostProcessMapper,
|
|
527
|
-
getStructMapper,
|
|
528
229
|
postProcess
|
|
529
230
|
}
|