@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
|
@@ -6,6 +6,7 @@ const AbstractError = commons.errors.AbstractError
|
|
|
6
6
|
const UriSyntaxError = commons.errors.UriSyntaxError
|
|
7
7
|
const IllegalArgumentError = commons.errors.IllegalArgumentError
|
|
8
8
|
const NotImplementedError = commons.errors.NotImplementedError
|
|
9
|
+
const EdmPrimitiveTypeKind = require('../../odata-commons/edm/EdmPrimitiveTypeKind')
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* UriHelper has utility methods for reading and constructing URIs.
|
|
@@ -103,7 +104,9 @@ class UriHelper {
|
|
|
103
104
|
for (const key of keys) {
|
|
104
105
|
url = url ? url + ',' : ''
|
|
105
106
|
if (keys.length > 1) url += encodeURIComponent(key.name) + '='
|
|
106
|
-
url +=
|
|
107
|
+
url += key.type === EdmPrimitiveTypeKind.Binary
|
|
108
|
+
? CommonsUriHelper.toUriLiteral(key.value, key.type)
|
|
109
|
+
: encodeURIComponent(CommonsUriHelper.toUriLiteral(key.value, key.type))
|
|
107
110
|
}
|
|
108
111
|
return '(' + url + ')'
|
|
109
112
|
}
|
|
@@ -1,18 +1,7 @@
|
|
|
1
|
-
const cds = require('../../../cds')
|
|
2
|
-
|
|
3
|
-
const OData = require('./OData')
|
|
4
1
|
const Dispatcher = require('./Dispatcher')
|
|
5
2
|
|
|
6
|
-
const { alias2ref } = require('../../../common/utils/csn')
|
|
7
|
-
|
|
8
3
|
const to = service => {
|
|
9
|
-
|
|
10
|
-
alias2ref(service, edm)
|
|
11
|
-
|
|
12
|
-
const odata = new OData(edm, service.model, service.options)
|
|
13
|
-
odata.addCDSServiceToChannel(service)
|
|
14
|
-
|
|
15
|
-
return new Dispatcher(odata).getService()
|
|
4
|
+
return new Dispatcher(service).getService()
|
|
16
5
|
}
|
|
17
6
|
|
|
18
7
|
module.exports = to
|
|
@@ -4,7 +4,8 @@ const {
|
|
|
4
4
|
|
|
5
5
|
const { findCsnTargetFor } = require('../../../../common/utils/csn')
|
|
6
6
|
const { isStreaming } = require('./stream')
|
|
7
|
-
const {
|
|
7
|
+
const { convertStructured } = require('../../../../../common/utils/ucsn')
|
|
8
|
+
const { deepCopy } = require('../../../../common/utils/copy')
|
|
8
9
|
|
|
9
10
|
const _isFunctionInvocation = req =>
|
|
10
11
|
req.getUriInfo().getLastSegment().getFunction || req.getUriInfo().getLastSegment().getFunctionImport
|
|
@@ -146,7 +147,7 @@ const _addForeignKeys = (service, req, data) => {
|
|
|
146
147
|
}
|
|
147
148
|
}
|
|
148
149
|
|
|
149
|
-
const _getFunctionParameters = (lastSegment, keyValues) => {
|
|
150
|
+
const _getFunctionParameters = (lastSegment, keyValues, service, target) => {
|
|
150
151
|
const functionParameters = lastSegment.getFunctionParameters()
|
|
151
152
|
const paramValues = _getParamData(functionParameters)
|
|
152
153
|
|
|
@@ -154,18 +155,41 @@ const _getFunctionParameters = (lastSegment, keyValues) => {
|
|
|
154
155
|
for (const key in keyValues) {
|
|
155
156
|
paramValues[key] = keyValues[key]
|
|
156
157
|
}
|
|
158
|
+
if (lastSegment.getKind() === 'BOUND.FUNCTION') {
|
|
159
|
+
const targetFunction = target && target.actions && target.actions[lastSegment.getFunction().getName()]
|
|
160
|
+
if (!targetFunction.params) return {}
|
|
161
|
+
convertStructured(service, targetFunction, paramValues)
|
|
162
|
+
} else if (lastSegment.getKind() === 'FUNCTION.IMPORT') {
|
|
163
|
+
const { namespace, name } = lastSegment.getFunctionImport().getFullQualifiedName()
|
|
164
|
+
const targetFunction = service.model && service.model.definitions[`${namespace}.${name}`]
|
|
165
|
+
if (!targetFunction.params) return {}
|
|
166
|
+
convertStructured(service, targetFunction, paramValues)
|
|
167
|
+
}
|
|
157
168
|
return paramValues
|
|
158
169
|
}
|
|
159
170
|
|
|
160
|
-
const _getCopiedData = (odataReq, streaming, lastSegment) => {
|
|
171
|
+
const _getCopiedData = (odataReq, streaming, lastSegment, service, target) => {
|
|
161
172
|
let data = odataReq.getBody() || {}
|
|
162
173
|
|
|
163
174
|
if (streaming || lastSegment.getKind() === 'PRIMITIVE.PROPERTY') {
|
|
164
|
-
|
|
165
|
-
return data
|
|
175
|
+
return { [lastSegment.getProperty().getName()]: data }
|
|
166
176
|
}
|
|
167
177
|
|
|
168
|
-
|
|
178
|
+
data = deepCopy(data)
|
|
179
|
+
|
|
180
|
+
if (lastSegment.getKind() === 'BOUND.ACTION') {
|
|
181
|
+
const targetAction = target.actions && target.actions[lastSegment.getAction().getName()]
|
|
182
|
+
if (!targetAction || !targetAction.params) return {}
|
|
183
|
+
convertStructured(service, targetAction, data)
|
|
184
|
+
} else if (lastSegment.getKind() === 'ACTION.IMPORT') {
|
|
185
|
+
const { namespace, name } = lastSegment.getActionImport().getFullQualifiedName()
|
|
186
|
+
const targetAction = service.model && service.model.definitions[`${namespace}.${name}`]
|
|
187
|
+
if (!targetAction || !targetAction.params) return {}
|
|
188
|
+
convertStructured(service, targetAction, data)
|
|
189
|
+
} else {
|
|
190
|
+
convertStructured(service, target, data)
|
|
191
|
+
}
|
|
192
|
+
return data
|
|
169
193
|
}
|
|
170
194
|
|
|
171
195
|
/**
|
|
@@ -181,7 +205,7 @@ const _getCopiedData = (odataReq, streaming, lastSegment) => {
|
|
|
181
205
|
* @returns {object | Array}
|
|
182
206
|
* @private
|
|
183
207
|
*/
|
|
184
|
-
const getData = (component, odataReq, service) => {
|
|
208
|
+
const getData = (component, odataReq, service, target) => {
|
|
185
209
|
const segments = odataReq.getUriInfo().getPathSegments()
|
|
186
210
|
const lastSegment = odataReq.getUriInfo().getLastSegment()
|
|
187
211
|
const streaming = isStreaming(segments)
|
|
@@ -189,7 +213,7 @@ const getData = (component, odataReq, service) => {
|
|
|
189
213
|
const keyValues = _getParamData(keyPredicates)
|
|
190
214
|
|
|
191
215
|
if (component === DATA_READ_HANDLER && _isFunctionInvocation(odataReq)) {
|
|
192
|
-
return _getFunctionParameters(lastSegment, keyValues)
|
|
216
|
+
return _getFunctionParameters(lastSegment, keyValues, service, target)
|
|
193
217
|
}
|
|
194
218
|
|
|
195
219
|
if (component === DATA_DELETE_HANDLER || component === DATA_READ_HANDLER) {
|
|
@@ -200,7 +224,7 @@ const getData = (component, odataReq, service) => {
|
|
|
200
224
|
}
|
|
201
225
|
|
|
202
226
|
// copy so that original payload is preserved
|
|
203
|
-
const data = _getCopiedData(odataReq, streaming, lastSegment)
|
|
227
|
+
const data = _getCopiedData(odataReq, streaming, lastSegment, service, target)
|
|
204
228
|
|
|
205
229
|
// Only to be done for post via navigation
|
|
206
230
|
if (
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const cds = require('../../../../cds')
|
|
2
|
+
const OData = require('../OData')
|
|
3
|
+
|
|
4
|
+
const { alias2ref } = require('../../../../common/utils/csn')
|
|
5
|
+
const { BASE_TENANT } = require('../../../../common/utils/extensibilityUtils')
|
|
6
|
+
|
|
7
|
+
const SYSTEM_SERVICES = ['cds_r.ExtensibilityService', 'cds_r.ModelProviderService']
|
|
8
|
+
|
|
9
|
+
function createOdataService(service) {
|
|
10
|
+
const name = (service.definition && service.definition.name) || service.name
|
|
11
|
+
const edm = cds.compile.to.edm(service.model, { service: name })
|
|
12
|
+
alias2ref(service, edm)
|
|
13
|
+
|
|
14
|
+
const odataService = new OData(edm, service.model, service.options)
|
|
15
|
+
odataService.addCDSServiceToChannel(service)
|
|
16
|
+
|
|
17
|
+
return odataService
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function createNewService(name, csn, defaultOptions) {
|
|
21
|
+
const options = Object.assign({}, defaultOptions, { reflectedModel: csn })
|
|
22
|
+
|
|
23
|
+
const service = new cds.ApplicationService(name, csn, options)
|
|
24
|
+
await service.init()
|
|
25
|
+
if (options.impl) service.impl(options.impl)
|
|
26
|
+
|
|
27
|
+
return createOdataService(service)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const getModelHash = (tenant, features) => {
|
|
31
|
+
if (!features) features = []
|
|
32
|
+
|
|
33
|
+
let hash
|
|
34
|
+
if (cds.requires.multitenancy && tenant) {
|
|
35
|
+
hash = tenant
|
|
36
|
+
} else {
|
|
37
|
+
hash = BASE_TENANT
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
hash += ':' + features.join(';')
|
|
41
|
+
|
|
42
|
+
return hash
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
module.exports = {
|
|
46
|
+
SYSTEM_SERVICES,
|
|
47
|
+
createOdataService,
|
|
48
|
+
createNewService,
|
|
49
|
+
getModelHash
|
|
50
|
+
}
|
|
@@ -2,13 +2,13 @@ const cds = require('../../../../cds')
|
|
|
2
2
|
const { SELECT } = cds.ql
|
|
3
3
|
|
|
4
4
|
const { getDeepSelect } = require('../../../services/utils/handlerUtils')
|
|
5
|
-
const {
|
|
5
|
+
const { DRAFT_COLUMNS_MAP } = require('../../../../common/constants/draft')
|
|
6
6
|
const { filterKeys } = require('../../../../fiori/utils/handler')
|
|
7
7
|
|
|
8
8
|
const _getColumns = target => {
|
|
9
9
|
const columns = []
|
|
10
10
|
for (const k in target.elements) {
|
|
11
|
-
if (!target.elements[k].isAssociation && !
|
|
11
|
+
if (!target.elements[k].isAssociation && !(k in DRAFT_COLUMNS_MAP)) columns.push(k)
|
|
12
12
|
}
|
|
13
13
|
return columns
|
|
14
14
|
}
|
|
@@ -9,7 +9,15 @@ const {
|
|
|
9
9
|
const getError = require('../../../../common/error')
|
|
10
10
|
|
|
11
11
|
const _unboundActionsAndFunctions = ['ACTION.IMPORT', 'FUNCTION.IMPORT']
|
|
12
|
+
const _unboundCustomOperationKinds = _unboundActionsAndFunctions.reduce((acc, cur) => {
|
|
13
|
+
acc[cur] = 1
|
|
14
|
+
return acc
|
|
15
|
+
}, {})
|
|
12
16
|
const _actionsAndFunctions = [..._unboundActionsAndFunctions, 'BOUND.ACTION', 'BOUND.FUNCTION']
|
|
17
|
+
const _boundCustomOperationKinds = _actionsAndFunctions.reduce((acc, cur) => {
|
|
18
|
+
acc[cur] = 1
|
|
19
|
+
return acc
|
|
20
|
+
}, {})
|
|
13
21
|
|
|
14
22
|
/**
|
|
15
23
|
* Checks if a custom operation was requested.
|
|
@@ -20,10 +28,9 @@ const _actionsAndFunctions = [..._unboundActionsAndFunctions, 'BOUND.ACTION', 'B
|
|
|
20
28
|
* @private
|
|
21
29
|
*/
|
|
22
30
|
const isCustomOperation = (pathSegments, includingBound = true) => {
|
|
23
|
-
const customOperationKinds = includingBound ? _actionsAndFunctions : _unboundActionsAndFunctions
|
|
24
31
|
const kind = pathSegments[pathSegments.length - 1].getKind()
|
|
25
|
-
|
|
26
|
-
if (
|
|
32
|
+
const kinds = includingBound ? _boundCustomOperationKinds : _unboundCustomOperationKinds
|
|
33
|
+
if (kind in kinds) {
|
|
27
34
|
return kind
|
|
28
35
|
}
|
|
29
36
|
}
|
|
@@ -118,7 +118,7 @@ const convertDecimal = (row, key, options) => {
|
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
const addAssociationToRow = (row, foreignKey, foreignKeyElement) => {
|
|
121
|
-
const assocName = foreignKeyElement
|
|
121
|
+
const assocName = foreignKeyElement._foreignKey4
|
|
122
122
|
const assoc = foreignKeyElement.parent.elements[assocName]
|
|
123
123
|
|
|
124
124
|
if (!row[assocName]) {
|
|
@@ -128,7 +128,8 @@ const addAssociationToRow = (row, foreignKey, foreignKeyElement) => {
|
|
|
128
128
|
const keyOfAssociatedEntity = foreignKey.replace(`${assocName}_`, '')
|
|
129
129
|
|
|
130
130
|
// REVISIT: structured keys, see xtests in structured-x4
|
|
131
|
-
|
|
131
|
+
const assocTargetKey = assoc._target.keys[keyOfAssociatedEntity]
|
|
132
|
+
if (assocTargetKey && assocTargetKey._foreignKey4) {
|
|
132
133
|
// assoc as key
|
|
133
134
|
row[assocName][keyOfAssociatedEntity] = row[foreignKey]
|
|
134
135
|
delete row[foreignKey]
|
|
@@ -173,7 +174,7 @@ const _processCategory = (category, processArgs, req, options, previousResult) =
|
|
|
173
174
|
if (options.decimals && row[key]) convertDecimal(row, key, options)
|
|
174
175
|
break
|
|
175
176
|
|
|
176
|
-
case '
|
|
177
|
+
case 'foreignKey':
|
|
177
178
|
addAssociationToRow(row, key, element)
|
|
178
179
|
break
|
|
179
180
|
|
|
@@ -221,13 +222,13 @@ const _isContainedOrBackLink = element =>
|
|
|
221
222
|
(element._isContained || (element._anchor && element._anchor._isContained))
|
|
222
223
|
|
|
223
224
|
const _assocs = (element, target) => {
|
|
224
|
-
const assocName = element
|
|
225
|
+
const assocName = element._foreignKey4
|
|
225
226
|
const assoc = assocName && target.elements[assocName]
|
|
226
227
|
|
|
227
228
|
if (cds.env.effective.odata.refs) {
|
|
228
229
|
// expand assoc keys except of up_ backlinks
|
|
229
|
-
if (
|
|
230
|
-
return ['
|
|
230
|
+
if (assoc && !_isUpAssoc(assoc)) {
|
|
231
|
+
return ['foreignKey']
|
|
231
232
|
}
|
|
232
233
|
|
|
233
234
|
if (element['@odata.containment.ignore']) {
|
|
@@ -247,7 +248,7 @@ const _pick = options => (element, target, parent) => {
|
|
|
247
248
|
|
|
248
249
|
if (element['@odata.etag']) categories.push('@odata.etag')
|
|
249
250
|
|
|
250
|
-
if (element.
|
|
251
|
+
if (element._type === 'cds.Decimal') categories.push('@cds.Decimal')
|
|
251
252
|
|
|
252
253
|
categories.push(..._assocs(element, target))
|
|
253
254
|
|
|
@@ -320,10 +321,7 @@ const postProcess = (req, res, service, result, previousResult) => {
|
|
|
320
321
|
const args = {
|
|
321
322
|
processFn,
|
|
322
323
|
row,
|
|
323
|
-
template
|
|
324
|
-
pathOptions: {
|
|
325
|
-
includeKeyValues: false
|
|
326
|
-
}
|
|
324
|
+
template
|
|
327
325
|
}
|
|
328
326
|
|
|
329
327
|
templateProcessor(args)
|
|
@@ -19,15 +19,18 @@ class RestRequest extends cds.Request {
|
|
|
19
19
|
constructor(parsed, data, req, res, service) {
|
|
20
20
|
const { event, target } = parsed
|
|
21
21
|
|
|
22
|
+
// for functions, data is in params (if provided)
|
|
23
|
+
if (parsed.kind === 'function' && parsed.params) data = parsed.params
|
|
24
|
+
|
|
22
25
|
/*
|
|
23
26
|
* query
|
|
24
27
|
*/
|
|
25
28
|
const query = restToCqn(parsed, data, req, service)
|
|
26
29
|
|
|
27
30
|
/*
|
|
28
|
-
* method,
|
|
31
|
+
* method, headers
|
|
29
32
|
*/
|
|
30
|
-
const { method,
|
|
33
|
+
const { method, headers } = req
|
|
31
34
|
|
|
32
35
|
/*
|
|
33
36
|
* super
|
|
@@ -37,7 +40,7 @@ class RestRequest extends cds.Request {
|
|
|
37
40
|
const _model = service.model
|
|
38
41
|
// REVISIT: public API for query options (express style req.query already in use)?
|
|
39
42
|
const _queryOptions = req.query
|
|
40
|
-
super({ event, target, data, query, user, method,
|
|
43
|
+
super({ event, target, data, query, user, method, headers, req, res, _model, _queryOptions })
|
|
41
44
|
|
|
42
45
|
// REVISIT: validate associations for deep insert
|
|
43
46
|
flattenDeepToOneAssociations(this, this.model)
|
|
@@ -53,8 +53,10 @@ module.exports = service => {
|
|
|
53
53
|
if (err) next(err)
|
|
54
54
|
else {
|
|
55
55
|
// only set status if not yet modified
|
|
56
|
-
|
|
57
|
-
restRes.
|
|
56
|
+
const { statusCode } = restRes
|
|
57
|
+
if (statusCode === 200 && status) restRes.status(status)
|
|
58
|
+
if (body === undefined) restRes.status(statusCode === 200 ? 204 : statusCode).end()
|
|
59
|
+
else restRes.send(toRestResult(body))
|
|
58
60
|
}
|
|
59
61
|
}
|
|
60
62
|
}
|
|
@@ -22,7 +22,7 @@ const createCqlString = (target, key, keyValue) => {
|
|
|
22
22
|
let keyString = ''
|
|
23
23
|
|
|
24
24
|
if (keyValue !== undefined) {
|
|
25
|
-
keyString = `[${key}=${_convertKeyForCompiler(keyValue, target.keys[key].
|
|
25
|
+
keyString = `[${key}=${_convertKeyForCompiler(keyValue, target.keys[key]._type)}]`
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
return `${target.name}${keyString}`
|
|
@@ -2,7 +2,7 @@ const _isKeyTypeBinary = (entity, key) => {
|
|
|
2
2
|
return (
|
|
3
3
|
entity.elements &&
|
|
4
4
|
entity.elements[key] &&
|
|
5
|
-
(entity.elements[key].
|
|
5
|
+
(entity.elements[key]._type === 'cds.Binary' || entity.elements[key]._type === 'cds.LargeBinary')
|
|
6
6
|
)
|
|
7
7
|
}
|
|
8
8
|
|
|
@@ -22,10 +22,9 @@ const getConvertedValue = (type, value) => {
|
|
|
22
22
|
|
|
23
23
|
module.exports = {
|
|
24
24
|
getKeyValuePair: (entity, value) => {
|
|
25
|
+
if (value === undefined) return {}
|
|
25
26
|
const key = _keyFromEntity(entity)
|
|
26
|
-
return {
|
|
27
|
-
[key.name]: getConvertedValue(key.type, value)
|
|
28
|
-
}
|
|
27
|
+
return { [key.name]: getConvertedValue(key._type, value) }
|
|
29
28
|
},
|
|
30
29
|
getConvertedValue
|
|
31
30
|
}
|
|
@@ -19,7 +19,9 @@ const _normalizeAndSplitUrl = req => {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
const _enrichCustomOperation = (csnElement, customOperationName) => {
|
|
22
|
-
|
|
22
|
+
const obj = { name: customOperationName }
|
|
23
|
+
Object.setPrototypeOf(obj, csnElement)
|
|
24
|
+
return obj
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
const _initializeParsed = event => {
|
|
@@ -93,9 +95,9 @@ const _validateAndConvertParamValues = (csnElement, params = {}) => {
|
|
|
93
95
|
if (!csnElementParam) {
|
|
94
96
|
throw getError(400, 'INVALID_PARAMETER', [param])
|
|
95
97
|
}
|
|
96
|
-
const convertedParam = getConvertedValue(csnElementParam.
|
|
98
|
+
const convertedParam = getConvertedValue(csnElementParam._type, params[param])
|
|
97
99
|
if (Number.isNaN(convertedParam)) {
|
|
98
|
-
throw getError(400, 'INVALID_PARAMETER_VALUE_TYPE', [param, csnElementParam.
|
|
100
|
+
throw getError(400, 'INVALID_PARAMETER_VALUE_TYPE', [param, csnElementParam._type])
|
|
99
101
|
}
|
|
100
102
|
params[param] = convertedParam
|
|
101
103
|
}
|
|
@@ -123,7 +125,7 @@ const _setConvenienceProperties = parsed => {
|
|
|
123
125
|
parsed.isCollection = false
|
|
124
126
|
} else if (lastElement.kind === 'entity') {
|
|
125
127
|
parsed.isCollection = true
|
|
126
|
-
} else if (lastElement.
|
|
128
|
+
} else if (lastElement.isAssociation) {
|
|
127
129
|
parsed.isCollection = true
|
|
128
130
|
} else {
|
|
129
131
|
parsed.operation = lastElement
|
|
@@ -84,14 +84,11 @@ const validateReturnType = (operation, data) => {
|
|
|
84
84
|
// in case of inline return type: { elements: ... } and no explicit name of return type
|
|
85
85
|
const returnType = operation.returns.items ? operation.returns.items : operation.returns
|
|
86
86
|
|
|
87
|
-
if (typeof data === 'undefined')
|
|
88
|
-
const { kind, name } = operation
|
|
89
|
-
// REVISIT: use i18n
|
|
90
|
-
throw getError(`'undefined' is invalid according to return type definition of custom ${kind} '${name}'.`)
|
|
91
|
-
}
|
|
87
|
+
if (typeof data === 'undefined') return true
|
|
92
88
|
|
|
93
89
|
let checkResult
|
|
94
90
|
|
|
91
|
+
// .type of action/function behaves different to .type of other csn elements
|
|
95
92
|
// Return type contains primitives
|
|
96
93
|
if (cds.builtin.types[returnType.type]) {
|
|
97
94
|
const check = CDS_TYPE_CHECKS[returnType.type]
|
|
@@ -100,6 +97,12 @@ const validateReturnType = (operation, data) => {
|
|
|
100
97
|
? _checkArray(returnType.type, check, data)
|
|
101
98
|
: _checkSingle(returnType.type, check, data)
|
|
102
99
|
} else {
|
|
100
|
+
if (typeof data !== 'object') {
|
|
101
|
+
throw new Error(
|
|
102
|
+
`Invalid scalar value ${typeof data === 'string' ? `"${data}"` : data} for return type "${returnType.type}"`
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
|
|
103
106
|
// Only check complex objects, ignore non-modelled data
|
|
104
107
|
data = (Array.isArray(data) ? data : [data]).filter(entry => typeof entry === 'object' && !Array.isArray(entry))
|
|
105
108
|
|
|
@@ -7,6 +7,11 @@ const { postProcess } = require('../../common/utils/postProcessing')
|
|
|
7
7
|
|
|
8
8
|
const _isSimpleCqnQuery = q => typeof q === 'object' && q !== null && !Array.isArray(q) && Object.keys(q).length > 0
|
|
9
9
|
|
|
10
|
+
// for getRestrictions()
|
|
11
|
+
const { getNormalizedRestrictions, getApplicableRestrictions } = require('./utils/restrictions')
|
|
12
|
+
const WRITE_EVENTS = { CREATE: 1, NEW: 1, UPDATE: 1, PATCH: 1, DELETE: 1, CANCEL: 1, EDIT: 1 }
|
|
13
|
+
const CRUD = Object.assign({ READ: 1 }, WRITE_EVENTS)
|
|
14
|
+
|
|
10
15
|
/**
|
|
11
16
|
* Generic Service Event Handler.
|
|
12
17
|
*/
|
|
@@ -108,6 +113,41 @@ class ApplicationService extends cds.Service {
|
|
|
108
113
|
}
|
|
109
114
|
}
|
|
110
115
|
|
|
116
|
+
/**
|
|
117
|
+
* Returns the applicable restrictions for the current request as follows:
|
|
118
|
+
* - null: unrestricted access
|
|
119
|
+
* - []: no access
|
|
120
|
+
* - [{ grant: '...', to: ['...'], where: '...' }, ...]: applicable restrictions with grant normalized to strings,
|
|
121
|
+
* i.e., grant: ['CREATE', 'UPDATE'] in model becomes [{ grant: 'CREATE' }, { grant: 'UPDATE' }]
|
|
122
|
+
* - Promise resovling to any of the above (needed for CAS overrides)
|
|
123
|
+
*
|
|
124
|
+
* @param {object} definition - then csn definition of an entity or an (un)bound action or function
|
|
125
|
+
* @param {string} event - the event name
|
|
126
|
+
* @param {import('../../../../lib/req/user')} user - the current user
|
|
127
|
+
* @returns {Promise | Array | null}
|
|
128
|
+
*/
|
|
129
|
+
getRestrictions(definition, event, user) {
|
|
130
|
+
let restrictions = getNormalizedRestrictions(definition, this.model.definitions, event)
|
|
131
|
+
if ((!restrictions || !restrictions.length) && (event in CRUD || !definition.parent)) {
|
|
132
|
+
// > unrestricted entity or unbound
|
|
133
|
+
return null
|
|
134
|
+
}
|
|
135
|
+
if (event in CRUD && restrictions.every(r => r.grant !== '*' && !(r.grant in CRUD))) {
|
|
136
|
+
// > only bounds are restricted
|
|
137
|
+
return null
|
|
138
|
+
}
|
|
139
|
+
if (!(event in CRUD) && (!restrictions || !restrictions.length) && definition.parent) {
|
|
140
|
+
// > bound without own restrictions -> get from parent
|
|
141
|
+
restrictions = getNormalizedRestrictions(definition.parent, this.model.definitions, event)
|
|
142
|
+
if (!restrictions || !restrictions.length) {
|
|
143
|
+
// > unrestricted bound
|
|
144
|
+
return null
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// return the applicable restrictions (grant and to fit to request and user)
|
|
148
|
+
return getApplicableRestrictions(restrictions, event, user)
|
|
149
|
+
}
|
|
150
|
+
|
|
111
151
|
// Overload .handle in order to resolve projections up to a definition that is known by the remote service instance.
|
|
112
152
|
// Result is post processed according to the inverse projection in order to reflect the correct result of the original query.
|
|
113
153
|
async handle(req) {
|
|
@@ -2,8 +2,9 @@ const cds = require('../../../cds')
|
|
|
2
2
|
// requesting logger without module on purpose!
|
|
3
3
|
const LOG = cds.log()
|
|
4
4
|
|
|
5
|
-
const {
|
|
5
|
+
const { DRAFT_COLUMNS_UNION_MAP } = require('../../../common/constants/draft')
|
|
6
6
|
|
|
7
|
+
// REVISIT: Can we combine that with db/utils/columns.js?
|
|
7
8
|
/**
|
|
8
9
|
* This method gets all columns for an entity.
|
|
9
10
|
* It includes the generated foreign keys from managed associations, structured elements and complex and custom types.
|
|
@@ -30,7 +31,7 @@ const getColumns = (
|
|
|
30
31
|
if (element.isAssociation) continue
|
|
31
32
|
if (filterVirtual && element.virtual) continue
|
|
32
33
|
if (removeIgnore && element['@cds.api.ignore']) continue
|
|
33
|
-
if (skipDraft &&
|
|
34
|
+
if (skipDraft && each in DRAFT_COLUMNS_UNION_MAP) continue
|
|
34
35
|
if (keysOnly && !element.key) continue
|
|
35
36
|
columns.push(onlyNames ? each : element)
|
|
36
37
|
}
|
|
@@ -82,7 +83,7 @@ const getSearchableColumns = entity => {
|
|
|
82
83
|
// - The @cds.search annotation is provided, the column name is not included, and the column
|
|
83
84
|
// is typed as string.
|
|
84
85
|
// - The @cds.search annotation is not provided, and the column is typed as string
|
|
85
|
-
return annotatedColumnValue === undefined && column.
|
|
86
|
+
return annotatedColumnValue === undefined && column._type === defaultSearchableType
|
|
86
87
|
})
|
|
87
88
|
|
|
88
89
|
// if the @cds.search annotation is provided -->
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const { DRAFT_COLUMNS_MAP } = require('../../../common/constants/draft')
|
|
2
2
|
|
|
3
3
|
const _deepEqual = (val1, val2) => {
|
|
4
4
|
if (val1 && typeof val1 === 'object' && val2 && typeof val2 === 'object') {
|
|
@@ -19,7 +19,7 @@ const _getIdxCorrespondingEntryWithSameKeys = (source, entry, keys) =>
|
|
|
19
19
|
source.findIndex(sourceEntry => keys.every(key => _deepEqual(sourceEntry[key], entry[key])))
|
|
20
20
|
|
|
21
21
|
const _getKeysOfEntity = entity =>
|
|
22
|
-
Object.keys(entity.keys).filter(key => !
|
|
22
|
+
Object.keys(entity.keys).filter(key => !(key in DRAFT_COLUMNS_MAP) && !entity.elements[key].isAssociation)
|
|
23
23
|
|
|
24
24
|
const _getCompositionsOfEntity = entity => Object.keys(entity.elements).filter(e => entity.elements[e].isComposition)
|
|
25
25
|
|
|
@@ -29,7 +29,7 @@ const _createToBeDeletedEntries = (oldEntry, entity, keys, compositions) => {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
for (const prop in oldEntry) {
|
|
32
|
-
if (
|
|
32
|
+
if (prop in DRAFT_COLUMNS_MAP) {
|
|
33
33
|
continue
|
|
34
34
|
}
|
|
35
35
|
if (keys.includes(prop)) {
|
|
@@ -162,7 +162,7 @@ const _iteratePropsInNewEntry = (newEntry, keys, result, oldEntry, entity) => {
|
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
// if value did not change --> ignored
|
|
165
|
-
if (newEntry[prop] === (oldEntry && oldEntry[prop]) ||
|
|
165
|
+
if (newEntry[prop] === (oldEntry && oldEntry[prop]) || prop in DRAFT_COLUMNS_MAP) {
|
|
166
166
|
continue
|
|
167
167
|
}
|
|
168
168
|
|
|
@@ -6,7 +6,7 @@ const { compareJson } = require('./compareJson')
|
|
|
6
6
|
const { selectDeepUpdateData } = require('../../../common/composition')
|
|
7
7
|
const { ensureDraftsSuffix } = require('../../../fiori/utils/handler')
|
|
8
8
|
|
|
9
|
-
const {
|
|
9
|
+
const { DRAFT_COLUMNS_MAP } = require('../../../common/constants/draft')
|
|
10
10
|
const { cqn2cqn4sql, convertPathExpressionToWhere } = require('../../../common/utils/cqn2cqn4sql')
|
|
11
11
|
const { revertData } = require('../../../common/utils/resolveView')
|
|
12
12
|
const { removeIsActiveEntityRecursively } = require('../../../fiori/utils/where')
|
|
@@ -25,7 +25,7 @@ module.exports = class {
|
|
|
25
25
|
ref: [element.name],
|
|
26
26
|
expand: this._createSelectColumnsForDelete(element._target)
|
|
27
27
|
})
|
|
28
|
-
} else if (!element._isAssociationStrict && !
|
|
28
|
+
} else if (!element._isAssociationStrict && !(element.name in DRAFT_COLUMNS_MAP)) {
|
|
29
29
|
columns.push({ ref: [element.name] })
|
|
30
30
|
}
|
|
31
31
|
}
|
|
@@ -58,7 +58,7 @@ module.exports = class {
|
|
|
58
58
|
} catch (e) {
|
|
59
59
|
// NOTE: unofficial compat flag!
|
|
60
60
|
if (cds.env.features.throw_diff_error !== false) throw e
|
|
61
|
-
else LOG.
|
|
61
|
+
else LOG.error('Unable to calculate diff due to error: ' + e.message, e)
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
const newQuery = cqn2cqn4sql(req.query, this._srv.model)
|
|
@@ -3,7 +3,7 @@ const { SELECT } = cds.ql
|
|
|
3
3
|
|
|
4
4
|
const { processDeep } = require('../../util/dataProcessUtils')
|
|
5
5
|
|
|
6
|
-
const {
|
|
6
|
+
const { DRAFT_COLUMNS_MAP } = require('../../../common/constants/draft')
|
|
7
7
|
|
|
8
8
|
const _isAssociationToOneManaged = element => element._isAssociationEffective && element.is2one && !element.on
|
|
9
9
|
|
|
@@ -18,7 +18,7 @@ const _getWheres = (key, data) => {
|
|
|
18
18
|
const allKeysAreProvided = req => {
|
|
19
19
|
const data = req.data && (Array.isArray(req.data) ? req.data : [req.data])
|
|
20
20
|
for (const key of Object.values(req.target.keys || {})) {
|
|
21
|
-
if (key._isAssociationStrict ||
|
|
21
|
+
if (key._isAssociationStrict || key.name in DRAFT_COLUMNS_MAP) {
|
|
22
22
|
continue
|
|
23
23
|
}
|
|
24
24
|
for (const d of data) {
|
|
@@ -53,7 +53,7 @@ const _getSelectCQN = (req, columns) => {
|
|
|
53
53
|
const data = req.data && (Array.isArray(req.data) ? req.data : [req.data])
|
|
54
54
|
|
|
55
55
|
for (const key of Object.values(req.target.keys || {})) {
|
|
56
|
-
if (key._isAssociationStrict ||
|
|
56
|
+
if (key._isAssociationStrict || key.name in DRAFT_COLUMNS_MAP) {
|
|
57
57
|
continue
|
|
58
58
|
}
|
|
59
59
|
|
|
@@ -168,7 +168,7 @@ const getDeepSelect = req => {
|
|
|
168
168
|
const cols = []
|
|
169
169
|
|
|
170
170
|
for (const each in elements) {
|
|
171
|
-
if (
|
|
171
|
+
if (each in DRAFT_COLUMNS_MAP) continue
|
|
172
172
|
const e = elements[each]
|
|
173
173
|
if (!e.isAssociation) cols.push(each)
|
|
174
174
|
else if (e._isCompositionEffective) {
|