@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,84 +1,100 @@
|
|
|
1
1
|
const cds = require('../../../cds')
|
|
2
2
|
const LOG = cds.log('odata')
|
|
3
|
+
const { BASE_TENANT, channelName } = require('../../../common/utils/extensibilityUtils')
|
|
3
4
|
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
const { alias2ref } = require('../../../common/utils/csn')
|
|
5
|
+
const { SYSTEM_SERVICES, createOdataService, createNewService, getModelHash } = require('./utils/dispatcherUtils')
|
|
7
6
|
|
|
8
7
|
const { normalizeError } = require('../../../common/error/frontend')
|
|
9
8
|
|
|
10
|
-
function _createNewService(name, csn, defaultOptions) {
|
|
11
|
-
const reflectedModel = cds.linked(cds.compile.for.odata(csn))
|
|
12
|
-
const options = Object.assign({}, defaultOptions, { reflectedModel })
|
|
13
|
-
|
|
14
|
-
const service = new cds.ApplicationService(name, csn, options)
|
|
15
|
-
service.init()
|
|
16
|
-
if (options.impl) service.impl(options.impl)
|
|
17
|
-
service._isExtended = true
|
|
18
|
-
|
|
19
|
-
const edm = cds.compile.to.edm(csn, { service: name })
|
|
20
|
-
alias2ref(service, edm)
|
|
21
|
-
|
|
22
|
-
const odataService = new OData(edm, csn, options)
|
|
23
|
-
odataService.addCDSServiceToChannel(service)
|
|
24
|
-
|
|
25
|
-
return odataService
|
|
26
|
-
}
|
|
27
|
-
|
|
28
9
|
class Dispatcher {
|
|
29
10
|
/**
|
|
30
|
-
* Constructs an Dispatcher for
|
|
31
|
-
* New OData services will be created
|
|
11
|
+
* Constructs an Dispatcher for cds service.
|
|
12
|
+
* New OData services will be created.
|
|
32
13
|
*
|
|
33
|
-
* @param
|
|
14
|
+
* @param service
|
|
34
15
|
*/
|
|
35
|
-
constructor(
|
|
36
|
-
this.
|
|
16
|
+
constructor(service) {
|
|
17
|
+
this._serviceName = service.definition.name
|
|
18
|
+
this._options = service.options
|
|
19
|
+
|
|
20
|
+
this._extMap = new Map()
|
|
21
|
+
this._extMap.set(getModelHash(BASE_TENANT, []), createOdataService(service))
|
|
22
|
+
|
|
23
|
+
if (cds.requires.extensibility && !SYSTEM_SERVICES.includes(this._serviceName)) {
|
|
24
|
+
cds.services['mtx-messaging'].on(channelName(), async msg => {
|
|
25
|
+
const tenant = msg.data.tenant
|
|
26
|
+
const hash = getModelHash(tenant, [])
|
|
27
|
+
for (const entry of this._extMap.entries()) {
|
|
28
|
+
if (entry[0].startsWith(hash)) {
|
|
29
|
+
this._extMap.delete(entry[0])
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (cds._mtxEnabled) {
|
|
36
|
+
cds.mtx.eventEmitter.on(cds.mtx.events.TENANT_UPDATED, async hash => {
|
|
37
|
+
this._extMap.delete(hash)
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async _getService4Tenant(req) {
|
|
43
|
+
// here, req is express' req -> req.tenant not available
|
|
44
|
+
const tenant = req.user && req.user.tenant
|
|
45
|
+
const isExtended = await cds.mtx.isExtended(tenant) // REVISIT: avoid await
|
|
46
|
+
if (!isExtended) return false
|
|
47
|
+
|
|
48
|
+
const csn = await cds.mtx.getCsn(tenant)
|
|
49
|
+
const model = cds.compile.for.nodejs(csn)
|
|
50
|
+
const service = await createNewService(this._serviceName, model, this._options)
|
|
51
|
+
service._cdsService._isExtended = true
|
|
52
|
+
return service
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async _getService4(tenant, features) {
|
|
56
|
+
const csn = await this._mps.getCsn(tenant, features || [], 'nodejs')
|
|
57
|
+
const model = cds.compile.for.nodejs(csn)
|
|
58
|
+
return createNewService(this._serviceName, model, this._options)
|
|
37
59
|
}
|
|
38
60
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
} = req
|
|
61
|
+
async _getService(tenant, features, hash, req) {
|
|
62
|
+
if (cds._mtxEnabled) {
|
|
63
|
+
const service = await this._getService4Tenant(req)
|
|
43
64
|
|
|
44
|
-
|
|
45
|
-
return new Promise(async (resolve, reject) => {
|
|
46
|
-
try {
|
|
47
|
-
const isExtended = await cds.mtx.isExtended(tenant)
|
|
48
|
-
if (!isExtended) return resolve(false)
|
|
65
|
+
if (service) return service
|
|
49
66
|
|
|
50
|
-
|
|
67
|
+
return this._extMap.get(getModelHash(BASE_TENANT, []))
|
|
68
|
+
}
|
|
51
69
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
70
|
+
if (!this._mps) this._mps = await cds.connect.to('cds_r.ModelProviderService')
|
|
71
|
+
const hashBase = getModelHash(BASE_TENANT, features)
|
|
72
|
+
if (tenant && tenant !== BASE_TENANT && hash !== hashBase) {
|
|
73
|
+
const isExtended = cds.requires.extensibility && (await this._mps.isExtended(tenant))
|
|
74
|
+
if (isExtended) {
|
|
75
|
+
return this._getService4(tenant, features)
|
|
76
|
+
} else {
|
|
77
|
+
if (!this._extMap.has(hashBase)) {
|
|
78
|
+
this._extMap.set(hashBase, this._getService4(BASE_TENANT, features))
|
|
79
|
+
}
|
|
80
|
+
return this._extMap.get(hashBase)
|
|
55
81
|
}
|
|
56
|
-
}
|
|
82
|
+
} else {
|
|
83
|
+
return this._getService4(BASE_TENANT, features)
|
|
84
|
+
}
|
|
57
85
|
}
|
|
58
86
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
//
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
* ModelProviderService:
|
|
71
|
-
* action csn(tenant:TenantID, version:String, toggles: array of String) returns CSN;
|
|
72
|
-
* action edmx(tenant:TenantID, version:String, toggles: array of String, service:String, locale:Locale, odataVersion:String) returns XML;
|
|
73
|
-
*/
|
|
74
|
-
const toggles = (req.features && Object.keys(req.features)) || []
|
|
75
|
-
const csn = await this._mps.csn(tenant, 'dummy', toggles)
|
|
76
|
-
|
|
77
|
-
resolve(_createNewService(this._odata._cdsService.definition.name, csn, this._odata._options))
|
|
78
|
-
} catch (e) {
|
|
79
|
-
reject(e)
|
|
80
|
-
}
|
|
81
|
-
})
|
|
87
|
+
async _handleError(err, hash, req, res) {
|
|
88
|
+
if (LOG._error) {
|
|
89
|
+
err.message = 'Unable to get service from service map due to error: ' + err.message
|
|
90
|
+
LOG.error(err)
|
|
91
|
+
}
|
|
92
|
+
// clear map entry
|
|
93
|
+
this._extMap.delete(hash)
|
|
94
|
+
// return 503 to client
|
|
95
|
+
const { error } = normalizeError(Object.assign(err, { statusCode: 503 }), req)
|
|
96
|
+
|
|
97
|
+
return res.status(503).send({ error })
|
|
82
98
|
}
|
|
83
99
|
|
|
84
100
|
/**
|
|
@@ -91,46 +107,36 @@ class Dispatcher {
|
|
|
91
107
|
*/
|
|
92
108
|
async dispatch(req, res) {
|
|
93
109
|
// here, req is express' req -> req.tenant not available
|
|
94
|
-
|
|
95
|
-
// enable mtx, if not done yet
|
|
96
|
-
if (!this._extMap) {
|
|
97
|
-
this._extMap = new Map()
|
|
98
|
-
cds.mtx.eventEmitter.on(cds.mtx.events.TENANT_UPDATED, async hash => {
|
|
99
|
-
this._extMap.delete(hash)
|
|
100
|
-
})
|
|
101
|
-
}
|
|
110
|
+
const tenant = req.user && req.user.tenant
|
|
102
111
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
// add hash to map, if not done yet
|
|
109
|
-
if (!this._extMap.has(hash)) {
|
|
110
|
-
this._extMap.set(hash, alphaToggles ? this._getService4Toggles(req) : this._getService4Tenant(req))
|
|
111
|
-
}
|
|
112
|
+
if (SYSTEM_SERVICES.includes(this._serviceName) || (!tenant && !cds._mpsEnabled)) {
|
|
113
|
+
const service = this._extMap.get(getModelHash(BASE_TENANT, []))
|
|
114
|
+
return service.process(req, res)
|
|
115
|
+
}
|
|
112
116
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
117
|
+
// ensure features is an array (some stakeholders set req.features themselves)
|
|
118
|
+
const features = req.features
|
|
119
|
+
? Array.isArray(req.features)
|
|
120
|
+
? req.features
|
|
121
|
+
: Object.keys(req.features)
|
|
122
|
+
.filter(k => req.features[k])
|
|
123
|
+
.sort()
|
|
124
|
+
: []
|
|
125
|
+
const hash = getModelHash(tenant, features)
|
|
126
|
+
|
|
127
|
+
// set promise into the map to avoid conflicts
|
|
128
|
+
if (!this._extMap.has(hash)) {
|
|
129
|
+
this._extMap.set(hash, this._getService(tenant, features, hash, req))
|
|
130
|
+
}
|
|
128
131
|
|
|
129
|
-
|
|
130
|
-
|
|
132
|
+
let service
|
|
133
|
+
try {
|
|
134
|
+
service = await this._extMap.get(hash)
|
|
135
|
+
} catch (err) {
|
|
136
|
+
return this._handleError(err, hash, req, res)
|
|
131
137
|
}
|
|
132
138
|
|
|
133
|
-
|
|
139
|
+
service.process(req, res)
|
|
134
140
|
}
|
|
135
141
|
|
|
136
142
|
/**
|
|
@@ -84,8 +84,8 @@ const _logger = {
|
|
|
84
84
|
path: () => {},
|
|
85
85
|
info: arg => LOG._info && _log('info', arg),
|
|
86
86
|
warning: arg => LOG._warn && _log('warn', arg),
|
|
87
|
-
error: arg =>
|
|
88
|
-
fatal: arg =>
|
|
87
|
+
error: arg => _log('error', arg),
|
|
88
|
+
fatal: arg => _log('error', arg)
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
/**
|
|
@@ -14,6 +14,12 @@ const { setStatusCodeAndHeader, getKeyProperty } = require('../../../../fiori/ut
|
|
|
14
14
|
const { toODataResult, postProcess } = require('../utils/result')
|
|
15
15
|
const { mergeJson } = require('../../../services/utils/compareJson')
|
|
16
16
|
|
|
17
|
+
const _isAssocOrCompNotLocalized = (reqTarget, el) => {
|
|
18
|
+
return (
|
|
19
|
+
reqTarget.elements[el].isAssociation && (!reqTarget.texts || reqTarget.elements[el].target !== reqTarget.texts.name)
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
17
23
|
const _postProcessDraftActivate = async (req, result, service) => {
|
|
18
24
|
// update req.data (keys needed in readAfterWrite)
|
|
19
25
|
req.data = result
|
|
@@ -25,6 +31,13 @@ const _postProcessDraftActivate = async (req, result, service) => {
|
|
|
25
31
|
result.HasActiveEntity = false
|
|
26
32
|
result.HasDraftEntity = false
|
|
27
33
|
|
|
34
|
+
// remove children from result, excluding localized composition 'text'
|
|
35
|
+
if (!(cds.env.effective.odata.structs || cds.env.features.ucsn_struct_conversion)) {
|
|
36
|
+
for (const k in req.target.elements) {
|
|
37
|
+
if (_isAssocOrCompNotLocalized(req.target, k)) delete result[k]
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
28
41
|
return result
|
|
29
42
|
}
|
|
30
43
|
|
|
@@ -1,13 +1,7 @@
|
|
|
1
|
-
const
|
|
1
|
+
const localeFrom = require('../../../../../../lib/req/locale')
|
|
2
2
|
const { toODataResult } = require('../utils/result')
|
|
3
3
|
|
|
4
4
|
module.exports = (req, res, next) => {
|
|
5
|
-
const
|
|
6
|
-
req: req.getIncomingRequest(),
|
|
7
|
-
odataReq: req
|
|
8
|
-
}
|
|
9
|
-
const user = new cds.User()
|
|
10
|
-
Object.defineProperty(user, '_req', { enumerable: false, value: _.req })
|
|
11
|
-
const locale = user.locale
|
|
5
|
+
const locale = localeFrom(req.getIncomingRequest())
|
|
12
6
|
next(null, toODataResult(locale))
|
|
13
7
|
}
|
|
@@ -2,30 +2,10 @@ const cds = require('../../../../cds')
|
|
|
2
2
|
const LOG = cds.log('odata')
|
|
3
3
|
|
|
4
4
|
const { toODataResult } = require('../utils/result')
|
|
5
|
-
|
|
6
5
|
const { normalizeError } = require('../../../../common/error/frontend')
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const _get4Tenant = async (tenant, locale, service) => {
|
|
11
|
-
if (cds._mtxEnabled && service._isExtended) {
|
|
12
|
-
const edmx = await cds.mtx.getEdmx(tenant, service.name, locale)
|
|
13
|
-
return edmx
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const _get4Toggles = async (tenant, locale, service, req) => {
|
|
18
|
-
if (!_mps) _mps = await cds.connect.to('ModelProviderService')
|
|
19
|
-
|
|
20
|
-
/*
|
|
21
|
-
* ModelProviderService:
|
|
22
|
-
* action csn(tenant:TenantID, version:String, toggles: array of String) returns CSN;
|
|
23
|
-
* action edmx(tenant:TenantID, version:String, toggles: array of String, service:String, locale:Locale, odataVersion:String) returns XML;
|
|
24
|
-
*/
|
|
25
|
-
const toggles = (req.features && Object.keys(req.features)) || []
|
|
26
|
-
const edmx = await _mps.edmx(tenant, 'dummy', toggles, service.name, locale, 'v4')
|
|
27
|
-
|
|
28
|
-
return edmx
|
|
7
|
+
const _getMetadata4Tenant = async (tenant, locale, service) => {
|
|
8
|
+
return await cds.mtx.getEdmx(tenant, service.name, locale)
|
|
29
9
|
}
|
|
30
10
|
|
|
31
11
|
/**
|
|
@@ -37,20 +17,15 @@ const _get4Toggles = async (tenant, locale, service, req) => {
|
|
|
37
17
|
const metadata = service => {
|
|
38
18
|
return async (odataReq, odataRes, next) => {
|
|
39
19
|
const req = odataReq.getIncomingRequest()
|
|
40
|
-
|
|
41
20
|
const tenant = req.user && req.user.tenant
|
|
42
|
-
|
|
43
21
|
// REVISIT: can we take locale from user, or is there some odata special wrt metadata?
|
|
44
22
|
const locale = odataRes.getContract().getLocale()
|
|
45
23
|
|
|
46
24
|
try {
|
|
47
25
|
let edmx
|
|
48
26
|
|
|
49
|
-
if (
|
|
50
|
-
|
|
51
|
-
edmx = alphaToggles
|
|
52
|
-
? await _get4Toggles(tenant, locale, service, req)
|
|
53
|
-
: await _get4Tenant(tenant, locale, service)
|
|
27
|
+
if (cds._mtxEnabled && service._isExtended) {
|
|
28
|
+
edmx = await _getMetadata4Tenant(tenant, locale, service)
|
|
54
29
|
}
|
|
55
30
|
|
|
56
31
|
if (!edmx) {
|
|
@@ -13,6 +13,7 @@ const {
|
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
15
|
} = require('../okra/odata-server')
|
|
16
|
+
const FUNCTION = { [BOUND_FUNCTION]: 1, [FUNCTION_IMPORT]: 1 }
|
|
16
17
|
|
|
17
18
|
const { isCustomOperation } = require('../utils/request')
|
|
18
19
|
const { actionAndFunctionQueries, getActionOrFunctionReturnType } = require('../utils/handlerUtils')
|
|
@@ -31,7 +32,7 @@ const { getSapMessages } = require('../../../../common/error/frontend')
|
|
|
31
32
|
* @returns {boolean} - True if a function is invoked, else false.
|
|
32
33
|
* @private
|
|
33
34
|
*/
|
|
34
|
-
const _isFunction = segments =>
|
|
35
|
+
const _isFunction = segments => segments[segments.length - 1].getKind() in FUNCTION
|
|
35
36
|
|
|
36
37
|
const _selectOrExpandInQueryOptions = queryOptions => {
|
|
37
38
|
return queryOptions && (queryOptions.$select || queryOptions.$expand)
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
const cds = require('../../../../cds')
|
|
2
2
|
|
|
3
|
-
const { UNAUTHORIZED, FORBIDDEN, getRequiresAsArray } = require('../../../../auth/utils')
|
|
3
|
+
const { UNAUTHORIZED, FORBIDDEN, getRequiresAsArray, isRestricted } = require('../../../../auth/utils')
|
|
4
4
|
|
|
5
5
|
module.exports = srv => {
|
|
6
6
|
const requires = getRequiresAsArray(srv.definition)
|
|
7
|
+
const restricted = isRestricted(srv)
|
|
7
8
|
|
|
8
9
|
return (odataReq, odataRes, next) => {
|
|
9
10
|
const req = odataReq.getBatchApplicationData()
|
|
@@ -18,7 +19,7 @@ module.exports = srv => {
|
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
// in case of $batch we need to challenge directly, as the header is not processed if in $batch response body
|
|
21
|
-
if (user && user._challenges &&
|
|
22
|
+
if (path.endsWith('/$batch') && user && user._challenges && restricted) {
|
|
22
23
|
res.set('WWW-Authenticate', user._challenges.join(';'))
|
|
23
24
|
return next(UNAUTHORIZED)
|
|
24
25
|
}
|
|
@@ -23,7 +23,7 @@ const _isUpsertAllowed = target => {
|
|
|
23
23
|
const _infoForeignKeyInParent = (req, odataReq, odataRes, tx) => {
|
|
24
24
|
const info = {}
|
|
25
25
|
// keys not in data
|
|
26
|
-
if (req.target.keys && Object.keys(req.target.keys).some(key =>
|
|
26
|
+
if (req.target.keys && Object.keys(req.target.keys).some(key => key in req.data)) {
|
|
27
27
|
return info
|
|
28
28
|
}
|
|
29
29
|
|
|
@@ -62,7 +62,7 @@ const _create = async (req, odataReq, odataRes, tx) => {
|
|
|
62
62
|
let parentKeyVal, parentUpdateRequired
|
|
63
63
|
if (parentKeyObj.length !== 0 && parentKeyObj[0][key.parentElement.name] !== null) {
|
|
64
64
|
parentKeyVal = parentKeyObj[0][key.parentElement.name]
|
|
65
|
-
} else if (key.childElement.
|
|
65
|
+
} else if (key.childElement.isUUID && key.childElement.key) {
|
|
66
66
|
parentUpdateRequired = true
|
|
67
67
|
parentKeyVal = cds.utils.uuid()
|
|
68
68
|
} else {
|
|
@@ -16,6 +16,8 @@ const _binaryOperatorToCQN = new Map([
|
|
|
16
16
|
[BinaryOperatorKind.LT, '<']
|
|
17
17
|
])
|
|
18
18
|
|
|
19
|
+
const LAMBDA_EXPRESSION = { [ResourceKind.ANY_EXPRESSION]: 1, [ResourceKind.ALL_EXPRESSION]: 1 }
|
|
20
|
+
|
|
19
21
|
class ExpressionToCQN {
|
|
20
22
|
constructor(entity, model, columns = []) {
|
|
21
23
|
this._model = model
|
|
@@ -145,11 +147,7 @@ class ExpressionToCQN {
|
|
|
145
147
|
|
|
146
148
|
_member(expression, operator) {
|
|
147
149
|
const pathSegments = expression.getPathSegments()
|
|
148
|
-
if (
|
|
149
|
-
pathSegments.some(segment =>
|
|
150
|
-
[ResourceKind.ANY_EXPRESSION, ResourceKind.ALL_EXPRESSION].includes(segment.getKind())
|
|
151
|
-
)
|
|
152
|
-
) {
|
|
150
|
+
if (pathSegments.some(segment => segment.getKind() in LAMBDA_EXPRESSION)) {
|
|
153
151
|
return this._lambda(pathSegments, operator)
|
|
154
152
|
}
|
|
155
153
|
|
|
@@ -252,7 +250,7 @@ class ExpressionToCQN {
|
|
|
252
250
|
|
|
253
251
|
// add cds type to right operand for use in _convert
|
|
254
252
|
if (left.ref && left.ref.length === 1 && this._entity && this._entity.elements[left.ref[0]]) {
|
|
255
|
-
expression.getRightOperand()._cdsType = this._entity.elements[left.ref[0]].
|
|
253
|
+
expression.getRightOperand()._cdsType = this._entity.elements[left.ref[0]]._type
|
|
256
254
|
}
|
|
257
255
|
|
|
258
256
|
const right = this.parse(expression.getRightOperand())
|
|
@@ -23,15 +23,14 @@ const getError = require('../../../../common/error')
|
|
|
23
23
|
* @private
|
|
24
24
|
*/
|
|
25
25
|
const _getExpandItem = (isAll, expandItems, name) => {
|
|
26
|
-
if (isAll)
|
|
27
|
-
return null
|
|
28
|
-
}
|
|
26
|
+
if (isAll) return null
|
|
29
27
|
|
|
30
28
|
return expandItems.find(item => {
|
|
31
29
|
const pathSegments = item.getPathSegments()
|
|
32
30
|
if (pathSegments[pathSegments.length - 1].getKind() === 'COUNT') {
|
|
33
31
|
throw getError(501, 'EXPAND_COUNT_UNSUPPORTED')
|
|
34
32
|
}
|
|
33
|
+
|
|
35
34
|
const navigation = pathSegments[pathSegments.length - 1].getNavigationProperty()
|
|
36
35
|
return navigation && navigation.getName() === name
|
|
37
36
|
})
|
|
@@ -44,9 +43,7 @@ const _getExpandItem = (isAll, expandItems, name) => {
|
|
|
44
43
|
* @private
|
|
45
44
|
*/
|
|
46
45
|
const _notSupported = expandItem => {
|
|
47
|
-
if (!expandItem)
|
|
48
|
-
return
|
|
49
|
-
}
|
|
46
|
+
if (!expandItem) return
|
|
50
47
|
|
|
51
48
|
if (expandItem.getOption(QueryOptions.COUNT)) {
|
|
52
49
|
throw getFeatureNotSupportedError(`Expand with query option "${QueryOptions.COUNT}"`)
|
|
@@ -73,24 +70,27 @@ const _getColumnsFromTargetType = (targetType, relatedEntity, all = false) => {
|
|
|
73
70
|
|
|
74
71
|
if (all) {
|
|
75
72
|
return getColumns(relatedEntity, { onlyNames: true, removeIgnore: true, filterDraft: false })
|
|
76
|
-
.filter(
|
|
77
|
-
.map(
|
|
78
|
-
ref: [
|
|
73
|
+
.filter(column => column !== 'DraftAdministrativeData_DraftUUID')
|
|
74
|
+
.map(column => ({
|
|
75
|
+
ref: [column]
|
|
79
76
|
}))
|
|
80
77
|
}
|
|
81
78
|
|
|
82
|
-
|
|
83
|
-
.filter(
|
|
84
|
-
.map(element =>
|
|
85
|
-
|
|
86
|
-
|
|
79
|
+
const columnNames = Object.values(relatedEntity.elements)
|
|
80
|
+
.filter(element => element['@odata.etag'])
|
|
81
|
+
.map(element => element.name)
|
|
82
|
+
|
|
83
|
+
const keyNames = Object.keys(relatedEntity.keys).filter(keyName => {
|
|
84
|
+
const key = relatedEntity.keys[keyName]
|
|
85
|
+
return !key.is2one && !key.is2many
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
columnNames.push(...keyNames)
|
|
89
|
+
return columnNames.map(element => ({ ref: [element] }))
|
|
87
90
|
}
|
|
88
91
|
|
|
89
92
|
const _getInnerSelect = expandItem => {
|
|
90
|
-
if (!expandItem)
|
|
91
|
-
return []
|
|
92
|
-
}
|
|
93
|
-
|
|
93
|
+
if (!expandItem) return []
|
|
94
94
|
return expandItem.getOption(QueryOptions.SELECT) || []
|
|
95
95
|
}
|
|
96
96
|
|
|
@@ -110,6 +110,7 @@ const _getSelectedElements = (expandItem, targetType, relatedEntity, options) =>
|
|
|
110
110
|
targetType.getProperties().forEach((value, key) => {
|
|
111
111
|
if (!relatedEntity.keys[key]) proxy = false
|
|
112
112
|
})
|
|
113
|
+
|
|
113
114
|
if (proxy) {
|
|
114
115
|
return _getColumnsFromTargetType(targetType, relatedEntity)
|
|
115
116
|
}
|
|
@@ -181,9 +182,10 @@ const _getItemCQN = (model, name, navigationProperty, expandItem, options) => {
|
|
|
181
182
|
|
|
182
183
|
// autoexposed entities now used . in csn and _ in edm
|
|
183
184
|
const relatedEntity = findCsnTargetFor(entityName, model, namespace)
|
|
185
|
+
const expand = _getSelectedElements(expandItem, targetType, relatedEntity, options)
|
|
184
186
|
const item = {
|
|
185
187
|
ref: name, // ['structured', 'nested_', nestedAssocToOne] if expand on structured
|
|
186
|
-
expand
|
|
188
|
+
expand
|
|
187
189
|
}
|
|
188
190
|
|
|
189
191
|
item.expand.push(..._getInnerExpandItems(model, expandItem, targetType))
|
|
@@ -203,7 +205,6 @@ const _getItemCQN = (model, name, navigationProperty, expandItem, options) => {
|
|
|
203
205
|
addLimit(item, top != null ? top : null, expandItem.getOption(QueryOptions.SKIP) || 0)
|
|
204
206
|
|
|
205
207
|
_filter(item, expandItem.getOption(QueryOptions.FILTER))
|
|
206
|
-
|
|
207
208
|
return item
|
|
208
209
|
}
|
|
209
210
|
|
|
@@ -237,13 +238,15 @@ const expandToCQN = (model, expandItems, type, options) => {
|
|
|
237
238
|
const expandItem = _getExpandItem(isAll, expandItems, name)
|
|
238
239
|
|
|
239
240
|
if (isAll || expandItem) {
|
|
240
|
-
|
|
241
|
+
const itemCQN = _getItemCQN(model, [name], navigationProperty, expandItem, options)
|
|
242
|
+
allElements.push(itemCQN)
|
|
241
243
|
}
|
|
242
244
|
}
|
|
243
245
|
|
|
244
246
|
// structured
|
|
245
247
|
for (const expandItem of expandItems) {
|
|
246
248
|
const pathSegments = expandItem.getPathSegments()
|
|
249
|
+
|
|
247
250
|
if (pathSegments.length && pathSegments[0].getKind() === 'COMPLEX.PROPERTY') {
|
|
248
251
|
const navigationProperty = _getNavigationProperty(pathSegments)
|
|
249
252
|
|
|
@@ -9,6 +9,7 @@ const readToCQN = require('./readToCQN')
|
|
|
9
9
|
const updateToCQN = require('./updateToCQN')
|
|
10
10
|
const createToCQN = require('./createToCQN')
|
|
11
11
|
const deleteToCQN = require('./deleteToCQN')
|
|
12
|
+
const parseToCqn = require('../../../../../odata/parseToCqn')
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* This method transforms an odata request into a CQN object.
|
|
@@ -22,7 +23,12 @@ const deleteToCQN = require('./deleteToCQN')
|
|
|
22
23
|
* @returns {object} - The CQN object
|
|
23
24
|
*/
|
|
24
25
|
module.exports = (component, service, target, data, odataReq, upsert) => {
|
|
25
|
-
|
|
26
|
+
if (
|
|
27
|
+
cds.env.features.odata_new_parser &&
|
|
28
|
+
!(component in { 'BOUND.ACTION': 1, 'BOUND.FUNCTION': 1, 'FUNCTION.IMPORT': 1, 'ACTION.IMPORT': 1 })
|
|
29
|
+
) {
|
|
30
|
+
return parseToCqn(component, service, target, data, odataReq, upsert)
|
|
31
|
+
}
|
|
26
32
|
|
|
27
33
|
switch (component) {
|
|
28
34
|
case DATA_CREATE_HANDLER:
|
|
@@ -30,7 +36,7 @@ module.exports = (component, service, target, data, odataReq, upsert) => {
|
|
|
30
36
|
case DATA_DELETE_HANDLER:
|
|
31
37
|
return deleteToCQN(service, odataReq)
|
|
32
38
|
case DATA_READ_HANDLER:
|
|
33
|
-
return
|
|
39
|
+
return readToCQN(service, target, odataReq)
|
|
34
40
|
case DATA_UPDATE_HANDLER:
|
|
35
41
|
return updateToCQN(service, data, odataReq)
|
|
36
42
|
case 'BOUND.ACTION':
|
|
@@ -50,7 +50,7 @@ class UriHelper {
|
|
|
50
50
|
if (value === null) return 'null'
|
|
51
51
|
if (edmType === EdmPrimitiveTypeKind.String) return "'" + value.replace(REGEXP_SINGLE_QUOTE, "''") + "'"
|
|
52
52
|
if (edmType === EdmPrimitiveTypeKind.Duration) return "duration'" + value + "'"
|
|
53
|
-
if (edmType === EdmPrimitiveTypeKind.Binary) return "binary'" + value + "'"
|
|
53
|
+
if (edmType === EdmPrimitiveTypeKind.Binary) return "binary'" + value.replace(/\//g, '_').replace(/\+/g, '-') + "'"
|
|
54
54
|
if (edmType.getKind() === EdmTypeKind.DEFINITION) {
|
|
55
55
|
return UriHelper.toUriLiteral(value, edmType.getUnderlyingType())
|
|
56
56
|
}
|
|
@@ -347,12 +347,9 @@ class ResourceJsonDeserializer {
|
|
|
347
347
|
}
|
|
348
348
|
const expectedTypeName =
|
|
349
349
|
expectedType.getKind() === EdmTypeKind.PRIMITIVE ? expectedType.getName() : expectedType.getFullQualifiedName()
|
|
350
|
-
const
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
value.endsWith(isCollection ? ')' : '')
|
|
354
|
-
? value.substring(isCollection ? 12 : 1, value.length - (isCollection ? 1 : 0))
|
|
355
|
-
: null
|
|
350
|
+
const typeNameRegex = isCollection ? /^#?Collection\((.*)\)$/ : /^#?(.*)$/
|
|
351
|
+
const matchedTypeName = typeof value === 'string' && value.match(typeNameRegex)
|
|
352
|
+
const typeName = matchedTypeName && matchedTypeName[1]
|
|
356
353
|
// The type name could be an alias-qualified name; for that case we have to do an EDM look-up.
|
|
357
354
|
const fullQualifiedName =
|
|
358
355
|
typeName && typeName.indexOf('.') > 0 && typeName.lastIndexOf('.') < typeName.length - 1
|
|
@@ -369,6 +366,8 @@ class ResourceJsonDeserializer {
|
|
|
369
366
|
throw new DeserializationError(
|
|
370
367
|
"The value of '" + name + "' must describe correctly the type '" + expectedType.getFullQualifiedName() + "'."
|
|
371
368
|
)
|
|
369
|
+
} else {
|
|
370
|
+
delete structureValue[name]
|
|
372
371
|
}
|
|
373
372
|
} else if (name.endsWith(JsonAnnotations.BIND) && !isDelta) {
|
|
374
373
|
const navigationPropertyName = name.substring(0, name.length - JsonAnnotations.BIND.length)
|
|
@@ -34,11 +34,7 @@ class DispatcherCommand extends Command {
|
|
|
34
34
|
super()
|
|
35
35
|
this._request = request
|
|
36
36
|
this._response = response
|
|
37
|
-
|
|
38
|
-
// dummy cache if alpha_toggles
|
|
39
|
-
if (cds.env.features.alpha_toggles) this._metadataCache = { get: () => {}, set: () => {} }
|
|
40
|
-
else this._metadataCache = metadataCache
|
|
41
|
-
|
|
37
|
+
this._metadataCache = metadataCache
|
|
42
38
|
this._componentManager = componentManager
|
|
43
39
|
this._dispatcher = dispatcher
|
|
44
40
|
this._logger = logger
|
|
@@ -78,7 +74,7 @@ class DispatcherCommand extends Command {
|
|
|
78
74
|
locale,
|
|
79
75
|
result.data.value
|
|
80
76
|
)
|
|
81
|
-
if (!
|
|
77
|
+
if (!this._metadataCache.get(contract.getContentTypeInfo().getMimeType(), locale)) {
|
|
82
78
|
this._logger.info(
|
|
83
79
|
'Metadata size exceeds cache boundary. Use cds option odata.metadataCacheLimit to increase the cache size.'
|
|
84
80
|
)
|