@sap/cds 5.9.6 → 6.0.1
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 +266 -20
- package/apis/services.d.ts +1 -1
- package/app/fiori/preview.js +2 -6
- package/app/index.js +3 -3
- package/bin/build/buildTaskEngine.js +17 -15
- package/bin/build/buildTaskFactory.js +29 -19
- package/bin/build/buildTaskHandler.js +27 -11
- package/bin/build/buildTaskProvider.js +2 -4
- package/bin/build/buildTaskProviderFactory.js +11 -16
- package/bin/build/constants.js +14 -6
- package/bin/build/csv-reader.js +2 -1
- package/bin/build/index.js +12 -18
- package/bin/build/provider/buildTaskHandlerEdmx.js +3 -39
- package/bin/build/provider/buildTaskHandlerFeatureToggles.js +149 -0
- package/bin/build/provider/buildTaskHandlerInternal.js +2 -3
- package/bin/build/provider/buildTaskProviderInternal.js +108 -239
- package/bin/build/provider/fiori/index.js +2 -2
- package/bin/build/provider/hana/2migration.js +11 -11
- package/bin/build/provider/hana/2tabledata.js +3 -3
- package/bin/build/provider/hana/index.js +89 -99
- package/bin/build/provider/hana/migrationtable.js +4 -3
- package/bin/build/provider/java/index.js +101 -0
- package/bin/build/provider/java-cf/index.js +1 -101
- package/bin/build/provider/mtx/index.js +90 -53
- package/bin/build/provider/mtx/resourcesTarBuilder.js +68 -0
- package/bin/build/provider/mtx-sidecar/index.js +80 -0
- package/bin/build/provider/node-cf/index.js +1 -308
- package/bin/build/provider/nodejs/index.js +189 -0
- package/bin/build/util.js +19 -31
- package/bin/cds.js +5 -3
- package/bin/deploy/to-hana/cfUtil.js +31 -6
- package/bin/deploy/to-hana/gitUtil.js +5 -3
- package/bin/deploy/to-hana/hana.js +9 -10
- package/bin/{build → deploy/to-hana}/mtaUtil.js +10 -9
- package/bin/mtx/in-cds.js +19 -7
- package/bin/serve.js +56 -21
- package/bin/utils/log.js +13 -30
- package/bin/version.js +5 -4
- package/common.cds +61 -16
- package/lib/compile/cdsc.js +3 -2
- package/lib/compile/etc/_localized.js +15 -14
- package/lib/compile/for/drafts.js +3 -4
- package/lib/compile/for/java.js +13 -10
- package/lib/compile/for/nodejs.js +8 -8
- package/lib/compile/for/odata.js +7 -12
- package/lib/compile/for/sql.js +5 -6
- package/lib/compile/index.js +5 -4
- package/lib/compile/load.js +9 -11
- package/lib/compile/minify.js +8 -5
- package/lib/compile/parse.js +4 -2
- package/lib/compile/resolve.js +18 -15
- package/lib/compile/to/edm.js +0 -1
- package/lib/compile/to/gql.js +3 -2
- package/lib/compile/to/json.js +24 -17
- package/lib/connect/bindings.js +3 -2
- package/lib/connect/index.js +5 -5
- package/lib/core/classes.js +74 -2
- package/lib/core/entities.js +52 -3
- package/lib/core/reflect.js +2 -1
- package/lib/deploy.js +11 -8
- package/lib/env/defaults.js +4 -3
- package/lib/env/index.js +71 -31
- package/lib/env/presets.js +1 -14
- package/lib/env/requires.js +70 -20
- package/lib/env/serviceBindings.js +147 -0
- package/lib/i18n/localize.js +22 -23
- package/lib/index.js +148 -144
- package/lib/log/errors.js +55 -12
- package/lib/log/format/kibana.js +1 -1
- package/lib/log/index.js +4 -0
- package/lib/ql/SELECT.js +7 -2
- package/lib/ql/Whereable.js +8 -2
- package/lib/ql/index.js +2 -2
- package/lib/req/assert.js +71 -0
- package/lib/req/cds-context.js +38 -70
- package/lib/req/context.js +34 -21
- package/lib/req/request.js +12 -18
- package/lib/req/response.js +6 -2
- package/lib/req/user.js +30 -22
- package/lib/serve/Service-api.js +17 -12
- package/lib/serve/Service-dispatch.js +5 -9
- package/lib/serve/Service-methods.js +4 -3
- package/lib/serve/Transaction.js +24 -21
- package/lib/serve/adapters.js +15 -5
- package/lib/serve/factory.js +23 -20
- package/lib/serve/index.js +51 -54
- package/lib/utils/axios.js +8 -12
- package/lib/utils/index.js +3 -3
- package/lib/utils/resources/index.js +1 -44
- package/lib/utils/resources/tar.js +2 -1
- package/lib/utils/tests.js +13 -15
- package/libx/_runtime/.eslintrc +1 -1
- package/libx/_runtime/audit/Service.js +6 -4
- package/libx/_runtime/audit/generic/personal/access.js +19 -43
- package/libx/_runtime/audit/generic/personal/index.js +40 -34
- package/libx/_runtime/audit/generic/personal/modification.js +11 -9
- package/libx/_runtime/audit/generic/personal/utils.js +13 -6
- package/libx/_runtime/audit/utils/v2.js +6 -3
- package/libx/_runtime/auth/index.js +71 -66
- package/libx/_runtime/auth/strategies/JWT.js +3 -2
- package/libx/_runtime/auth/strategies/mock.js +54 -53
- package/libx/_runtime/auth/strategies/xssecUtils.js +3 -4
- package/libx/_runtime/auth/strategies/xsuaa.js +3 -2
- package/libx/_runtime/auth/utils.js +2 -15
- package/libx/_runtime/cds-services/adapter/odata-v4/Dispatcher.js +128 -42
- package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +6 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +93 -73
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/action.js +10 -45
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/create.js +5 -9
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/error.js +9 -5
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +4 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +60 -53
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +15 -21
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +8 -15
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/expandToCQN.js +29 -41
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/index.js +1 -4
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/readToCQN.js +13 -13
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/selectToCQN.js +0 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/utils.js +24 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/edm/EdmEntityContainer.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/UriHelper.js +4 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/utils/PrimitiveValueDecoder.js +4 -5
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/utils/ValueConverter.js +4 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/validator/ValueValidator.js +5 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/core/ResponseHeaderSetter.js +2 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/invocation/DebugSerializingCommand.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/invocation/PresetResponseHeadersCommand.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/invocation/SerializingCommand.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/invocation/SetResponseHeadersCommand.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/serializer/ContextURLFactory.js +3 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/serializer/ErrorJsonSerializer.js +3 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/serializer/SerializerFactory.js +1 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/serializer/TrustedResourceJsonSerializer.js +3 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +36 -25
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/handlerUtils.js +100 -91
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/metaInfo.js +382 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/oDataConfiguration.js +1 -4
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/omitValues.js +5 -6
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +77 -21
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/request.js +3 -11
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +91 -69
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/stream.js +27 -6
- package/libx/_runtime/cds-services/adapter/rest/utils/validation-checks.js +7 -17
- package/libx/_runtime/cds-services/services/Service.js +17 -76
- package/libx/_runtime/cds-services/services/utils/columns.js +6 -4
- package/libx/_runtime/cds-services/services/utils/compareJson.js +1 -53
- package/libx/_runtime/cds-services/services/utils/differ.js +15 -19
- package/libx/_runtime/cds-services/util/assert.js +107 -34
- package/libx/_runtime/cds.js +1 -31
- package/libx/_runtime/common/aspects/Association.js +40 -54
- package/libx/_runtime/common/aspects/any.js +61 -6
- package/libx/_runtime/common/aspects/entity.js +19 -79
- package/libx/_runtime/common/composition/data.js +2 -2
- package/libx/_runtime/common/composition/delete.js +16 -18
- package/libx/_runtime/common/composition/tree.js +10 -10
- package/libx/_runtime/common/composition/update.js +3 -2
- package/libx/_runtime/common/constants/events.js +15 -0
- package/libx/_runtime/common/error/entry.js +9 -3
- package/libx/_runtime/common/error/frontend.js +13 -19
- package/libx/_runtime/common/error/index.js +8 -3
- package/libx/_runtime/common/generic/auth/capabilities.js +2 -1
- package/libx/_runtime/common/generic/auth/constants.js +1 -4
- package/libx/_runtime/common/generic/auth/requires.js +1 -1
- package/libx/_runtime/common/generic/auth/restrict.js +12 -28
- package/libx/_runtime/common/generic/auth/restrictions.js +12 -4
- package/libx/_runtime/common/generic/auth/utils.js +2 -1
- package/libx/_runtime/common/generic/crud.js +9 -60
- package/libx/_runtime/common/generic/etag.js +41 -7
- package/libx/_runtime/common/generic/input.js +128 -66
- package/libx/_runtime/common/generic/paging.js +9 -3
- package/libx/_runtime/common/generic/put.js +2 -2
- package/libx/_runtime/common/generic/sorting.js +11 -4
- package/libx/_runtime/common/generic/temporal.js +0 -5
- package/libx/_runtime/common/i18n/messages.properties +2 -1
- package/libx/_runtime/common/utils/binary.js +69 -0
- package/libx/_runtime/common/utils/cqn.js +39 -14
- package/libx/_runtime/common/utils/cqn2cqn4sql.js +93 -59
- package/libx/_runtime/common/utils/csn.js +87 -85
- package/libx/_runtime/common/utils/dollar.js +8 -7
- package/libx/_runtime/common/utils/draft.js +1 -1
- package/libx/_runtime/common/utils/foreignKeyPropagations.js +23 -7
- package/libx/_runtime/common/utils/generateOnCond.js +2 -1
- package/libx/_runtime/common/utils/keys.js +30 -13
- package/libx/_runtime/common/utils/postProcessing.js +6 -1
- package/libx/_runtime/common/utils/quotingStyles.js +0 -23
- package/libx/_runtime/common/utils/resolveStructured.js +23 -26
- package/libx/_runtime/common/utils/resolveView.js +4 -1
- package/libx/_runtime/common/utils/rewriteAsterisks.js +3 -0
- package/libx/_runtime/common/utils/search2cqn4sql.js +4 -13
- package/libx/_runtime/common/utils/searchToLike.js +9 -13
- package/libx/_runtime/common/utils/streamProp.js +35 -0
- package/libx/_runtime/common/utils/structured.js +12 -18
- package/libx/_runtime/common/utils/template.js +3 -5
- package/libx/_runtime/common/utils/templateProcessor.js +22 -14
- package/libx/_runtime/common/utils/unionCqnTemplate.js +4 -14
- package/libx/_runtime/db/Service.js +2 -1
- package/libx/_runtime/db/expand/expand-v2.js +2 -2
- package/libx/_runtime/db/expand/expandCQNToJoin.js +7 -6
- package/libx/_runtime/db/generic/input.js +14 -17
- package/libx/_runtime/db/generic/integrity.js +1 -2
- package/libx/_runtime/db/generic/update.js +14 -1
- package/libx/_runtime/db/query/read.js +0 -1
- package/libx/_runtime/db/query/update.js +1 -1
- package/libx/_runtime/db/sql-builder/BaseBuilder.js +1 -1
- package/libx/_runtime/db/sql-builder/ExpressionBuilder.js +5 -31
- package/libx/_runtime/db/sql-builder/InsertBuilder.js +1 -1
- package/libx/_runtime/db/sql-builder/ReferenceBuilder.js +0 -9
- package/libx/_runtime/db/sql-builder/SelectBuilder.js +11 -10
- package/libx/_runtime/db/sql-builder/UpdateBuilder.js +2 -2
- package/libx/_runtime/db/sql-builder/annotations.js +1 -2
- package/libx/_runtime/db/utils/coloredTxCommands.js +5 -0
- package/libx/_runtime/db/utils/columns.js +1 -1
- package/libx/_runtime/db/utils/propagateForeignKeys.js +10 -2
- package/libx/_runtime/extensibility/activate.js +69 -0
- package/libx/_runtime/extensibility/add.js +41 -0
- package/libx/_runtime/extensibility/addExtension.js +68 -0
- package/libx/_runtime/extensibility/defaults.js +39 -0
- package/libx/_runtime/extensibility/{uiflex/handler → handler}/transformREAD.js +0 -0
- package/libx/_runtime/extensibility/{uiflex/handler → handler}/transformRESULT.js +2 -2
- package/libx/_runtime/extensibility/{uiflex/handler → handler}/transformWRITE.js +2 -2
- package/libx/_runtime/extensibility/push.js +61 -0
- package/libx/_runtime/extensibility/service.js +21 -0
- package/libx/_runtime/extensibility/{uiflex/utils.js → utils.js} +39 -3
- package/libx/_runtime/extensibility/validation.js +53 -0
- package/libx/_runtime/extensibility/views.js +12 -0
- package/libx/_runtime/fiori/generic/activate.js +6 -4
- package/libx/_runtime/fiori/generic/before.js +17 -29
- package/libx/_runtime/fiori/generic/cancel.js +2 -4
- package/libx/_runtime/fiori/generic/delete.js +2 -4
- package/libx/_runtime/fiori/generic/edit.js +3 -7
- package/libx/_runtime/fiori/generic/index.js +31 -0
- package/libx/_runtime/fiori/generic/new.js +2 -4
- package/libx/_runtime/fiori/generic/patch.js +4 -8
- package/libx/_runtime/fiori/generic/prepare.js +2 -4
- package/libx/_runtime/fiori/generic/read.js +137 -162
- package/libx/_runtime/fiori/generic/readOverDraft.js +10 -4
- package/libx/_runtime/fiori/utils/handler.js +10 -5
- package/libx/_runtime/fiori/utils/where.js +1 -4
- package/libx/_runtime/hana/Service.js +14 -7
- package/libx/_runtime/hana/customBuilder/CustomSelectBuilder.js +1 -1
- package/libx/_runtime/hana/dynatrace.js +2 -2
- package/libx/_runtime/hana/localized.js +7 -6
- package/libx/_runtime/hana/pool.js +9 -6
- package/libx/_runtime/hana/search.js +2 -3
- package/libx/_runtime/hana/{searchToContains.js → search2Contains.js} +5 -2
- package/libx/_runtime/hana/search2cqn4sql.js +20 -17
- package/libx/_runtime/index.js +2 -6
- package/libx/_runtime/messaging/AMQPWebhookMessaging.js +11 -2
- package/libx/_runtime/messaging/common-utils/AMQPClient.js +4 -3
- package/libx/_runtime/messaging/common-utils/appId.js +9 -0
- package/libx/_runtime/messaging/common-utils/authorizedRequest.js +2 -18
- package/libx/_runtime/messaging/common-utils/connections.js +1 -1
- package/libx/_runtime/messaging/enterprise-messaging-shared.js +2 -2
- package/libx/_runtime/messaging/enterprise-messaging-utils/EMManagement.js +305 -231
- package/libx/_runtime/messaging/enterprise-messaging-utils/cloudEvents.js +2 -2
- package/libx/_runtime/messaging/enterprise-messaging-utils/options-management.js +15 -8
- package/libx/_runtime/messaging/enterprise-messaging-utils/options-messaging.js +57 -14
- package/libx/_runtime/messaging/enterprise-messaging.js +14 -19
- package/libx/_runtime/messaging/file-based.js +2 -1
- package/libx/_runtime/messaging/http-utils/token.js +18 -6
- package/libx/_runtime/messaging/message-queuing-utils/options-management.js +22 -12
- package/libx/_runtime/messaging/message-queuing-utils/options-messaging.js +27 -14
- package/libx/_runtime/messaging/message-queuing.js +138 -85
- package/libx/_runtime/messaging/outbox/utils.js +13 -7
- package/libx/_runtime/messaging/redis-messaging.js +0 -1
- package/libx/_runtime/messaging/service.js +4 -1
- package/libx/_runtime/remote/Service.js +24 -18
- package/libx/_runtime/remote/utils/client.js +84 -46
- package/libx/_runtime/remote/utils/data.js +23 -6
- package/libx/_runtime/sqlite/Service.js +14 -13
- package/libx/_runtime/sqlite/convertAssocToOneManaged.js +2 -0
- package/libx/_runtime/sqlite/customBuilder/CustomSelectBuilder.js +1 -0
- package/libx/_runtime/sqlite/execute.js +3 -9
- package/libx/_runtime/types/api.js +23 -11
- package/libx/common/utils/ucsn.js +15 -9
- package/libx/odata/afterburner.js +109 -29
- package/libx/odata/cqn2odata.js +48 -9
- package/libx/odata/grammar.pegjs +261 -157
- package/libx/odata/index.js +21 -9
- package/libx/odata/parseToCqn.js +8 -5
- package/libx/odata/parser.js +1 -1
- package/libx/odata/utils.js +13 -3
- package/libx/rest/RestAdapter.js +173 -113
- package/libx/rest/RestRequest.js +3 -2
- package/libx/rest/middleware/create.js +8 -6
- package/libx/rest/middleware/delete.js +6 -13
- package/libx/rest/middleware/error.js +1 -1
- package/libx/rest/middleware/input.js +6 -6
- package/libx/rest/middleware/operation.js +8 -3
- package/libx/rest/middleware/parse.js +3 -3
- package/libx/rest/middleware/payload.js +12 -0
- package/libx/rest/middleware/read.js +12 -2
- package/libx/rest/middleware/update.js +3 -3
- package/package.json +4 -6
- package/server.js +3 -44
- package/srv/extensibility-service.cds +56 -0
- package/srv/extensibility-service.js +1 -0
- package/srv/extensions.cds +8 -0
- package/srv/model-provider.cds +59 -0
- package/srv/model-provider.js +163 -0
- package/srv/mtx.cds +2 -0
- package/srv/mtx.js +22 -0
- package/srv/outbox.cds +2 -0
- package/tasks/enterprise-messaging-deploy.js +19 -12
- package/lib/serve/Service-compat.js +0 -36
- package/libx/_runtime/audit/generic/personal/constants.js +0 -4
- package/libx/_runtime/auth/strategies/dwc.js +0 -45
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/dispatcherUtils.js +0 -56
- package/libx/_runtime/cds-services/adapter/rest/Rest.js +0 -183
- package/libx/_runtime/cds-services/adapter/rest/RestRequest.js +0 -67
- package/libx/_runtime/cds-services/adapter/rest/handlers/create.js +0 -82
- package/libx/_runtime/cds-services/adapter/rest/handlers/delete.js +0 -39
- package/libx/_runtime/cds-services/adapter/rest/handlers/operation.js +0 -63
- package/libx/_runtime/cds-services/adapter/rest/handlers/read.js +0 -52
- package/libx/_runtime/cds-services/adapter/rest/handlers/update.js +0 -81
- package/libx/_runtime/cds-services/adapter/rest/rest-to-cqn/index.js +0 -56
- package/libx/_runtime/cds-services/adapter/rest/rest-to-cqn/utils.js +0 -33
- package/libx/_runtime/cds-services/adapter/rest/to.js +0 -8
- package/libx/_runtime/cds-services/adapter/rest/utils/binary.js +0 -50
- package/libx/_runtime/cds-services/adapter/rest/utils/data.js +0 -117
- package/libx/_runtime/cds-services/adapter/rest/utils/header-checks.js +0 -14
- package/libx/_runtime/cds-services/adapter/rest/utils/key-value-utils.js +0 -30
- package/libx/_runtime/cds-services/adapter/rest/utils/parse-url.js +0 -250
- package/libx/_runtime/cds-services/adapter/rest/utils/result.js +0 -26
- package/libx/_runtime/cds-services/services/utils/handlerUtils.js +0 -200
- package/libx/_runtime/common/aspects/utils.js +0 -152
- package/libx/_runtime/common/toggles/handler.js +0 -21
- package/libx/_runtime/common/utils/extensibilityUtils.js +0 -18
- package/libx/_runtime/extensibility/mps/index.js +0 -5
- package/libx/_runtime/extensibility/mps/service.js +0 -111
- package/libx/_runtime/extensibility/mps/tar.js +0 -42
- package/libx/_runtime/extensibility/mps/utils.js +0 -11
- package/libx/_runtime/extensibility/uiflex/index.js +0 -54
- package/libx/_runtime/extensibility/uiflex/service.js +0 -276
- package/libx/_runtime/messaging/common-utils/naming-conventions.js +0 -20
- package/libx/_runtime/remote/utils/client-types.d.ts +0 -7
- package/libx/gql/GraphQLAdapter.js +0 -33
- package/libx/gql/constants/adapter.js +0 -69
- package/libx/gql/constants/cds.js +0 -18
- package/libx/gql/constants/graphql.js +0 -33
- package/libx/gql/readme.md +0 -1
- package/libx/gql/resolvers/crud/create.js +0 -20
- package/libx/gql/resolvers/crud/delete.js +0 -29
- package/libx/gql/resolvers/crud/index.js +0 -6
- package/libx/gql/resolvers/crud/read.js +0 -30
- package/libx/gql/resolvers/crud/update.js +0 -42
- package/libx/gql/resolvers/crud/utils/index.js +0 -36
- package/libx/gql/resolvers/field.js +0 -5
- package/libx/gql/resolvers/index.js +0 -7
- package/libx/gql/resolvers/mutation.js +0 -23
- package/libx/gql/resolvers/parse/ast/enrich.js +0 -52
- package/libx/gql/resolvers/parse/ast/fragment.js +0 -11
- package/libx/gql/resolvers/parse/ast/fromObject.js +0 -39
- package/libx/gql/resolvers/parse/ast/index.js +0 -3
- package/libx/gql/resolvers/parse/ast/meta.js +0 -4
- package/libx/gql/resolvers/parse/ast/variable.js +0 -7
- package/libx/gql/resolvers/parse/ast2cqn/columns.js +0 -44
- package/libx/gql/resolvers/parse/ast2cqn/entries.js +0 -31
- package/libx/gql/resolvers/parse/ast2cqn/index.js +0 -8
- package/libx/gql/resolvers/parse/ast2cqn/limit.js +0 -6
- package/libx/gql/resolvers/parse/ast2cqn/orderBy.js +0 -24
- package/libx/gql/resolvers/parse/ast2cqn/utils/index.js +0 -3
- package/libx/gql/resolvers/parse/ast2cqn/where.js +0 -70
- package/libx/gql/resolvers/parse/utils/index.js +0 -8
- package/libx/gql/resolvers/query.js +0 -13
- package/libx/gql/resolvers/root.js +0 -34
- package/libx/gql/schema/generate.js +0 -18
- package/libx/gql/schema/index.js +0 -5
- package/libx/gql/schema/mutation.js +0 -76
- package/libx/gql/schema/query.js +0 -108
- package/libx/gql/schema/typeDefMap.js +0 -45
- package/libx/gql/schema/utils/index.js +0 -54
- package/libx/gql/utils/index.js +0 -12
- package/libx/rest/middleware/auth.js +0 -20
- package/libx/rest/middleware/content.js +0 -19
- package/srv/flex.cds +0 -21
- package/srv/flex.js +0 -1
- package/srv/mps.cds +0 -23
- package/srv/mps.js +0 -1
- package/srv/outbox.js +0 -0
|
@@ -5,10 +5,8 @@
|
|
|
5
5
|
* [...]
|
|
6
6
|
* Error responses MAY contain annotations in any of its JSON objects.
|
|
7
7
|
*/
|
|
8
|
-
|
|
9
8
|
const localeFrom = require('../../../../lib/req/locale')
|
|
10
9
|
const { getErrorMessage } = require('./utils')
|
|
11
|
-
|
|
12
10
|
let _i18n
|
|
13
11
|
const i18n = (...args) => {
|
|
14
12
|
if (!_i18n) _i18n = require('../i18n')
|
|
@@ -24,16 +22,12 @@ const {
|
|
|
24
22
|
} = require('./constants')
|
|
25
23
|
const ADDITIONAL_MSG_PROPERTIES = Object.keys(ADDITIONAL_MSG_PROPERTIES_MAP)
|
|
26
24
|
|
|
27
|
-
const SKIP_SANITIZATION = '@cds.skip_sanitization'
|
|
28
|
-
|
|
29
25
|
const _getFiltered = err => {
|
|
30
26
|
const error = {}
|
|
31
27
|
|
|
32
28
|
Object.keys(err)
|
|
33
29
|
.concat(['message'])
|
|
34
30
|
.forEach(k => {
|
|
35
|
-
// REVISIT: do not remove innererror with cds^6
|
|
36
|
-
if (k === 'innererror' && process.env.NODE_ENV === 'production' && !err[SKIP_SANITIZATION]) return
|
|
37
31
|
if (k in ALLOWED_PROPERTIES_MAP || k.startsWith('@')) {
|
|
38
32
|
error[k] = err[k]
|
|
39
33
|
} else if (k === 'numericSeverity') {
|
|
@@ -44,10 +38,10 @@ const _getFiltered = err => {
|
|
|
44
38
|
return error
|
|
45
39
|
}
|
|
46
40
|
|
|
47
|
-
const
|
|
41
|
+
const _rewriteDBError = error => {
|
|
48
42
|
// REVISIT: db stuff probably shouldn't be here
|
|
49
43
|
if (error.code === 'SQLITE_ERROR') {
|
|
50
|
-
error.code = '
|
|
44
|
+
error.code = 'null'
|
|
51
45
|
} else if (
|
|
52
46
|
(error.code.startsWith('SQLITE_CONSTRAINT') && error.message.match(/COMMIT/)) ||
|
|
53
47
|
(error.code.startsWith('SQLITE_CONSTRAINT') && error.message.match(/FOREIGN KEY/)) ||
|
|
@@ -72,7 +66,7 @@ const _normalize = (err, locale, inner = false) => {
|
|
|
72
66
|
error.code = String(error.code || 'null')
|
|
73
67
|
|
|
74
68
|
// REVISIT: code and message rewriting
|
|
75
|
-
|
|
69
|
+
_rewriteDBError(error)
|
|
76
70
|
|
|
77
71
|
let statusCode = err.status || err.statusCode || (_isAllowedError(error.code) && error.code)
|
|
78
72
|
|
|
@@ -87,8 +81,8 @@ const _normalize = (err, locale, inner = false) => {
|
|
|
87
81
|
statusCode = statusCode || _statusCodeFromDetails(childErrorCodes)
|
|
88
82
|
}
|
|
89
83
|
|
|
90
|
-
// make sure it's a number
|
|
91
|
-
statusCode = statusCode ? Number(statusCode) :
|
|
84
|
+
// make sure it's a number if set, otherwise will be assigned as 500 in normalizeError
|
|
85
|
+
statusCode = statusCode ? Number(statusCode) : undefined
|
|
92
86
|
|
|
93
87
|
return { error, statusCode }
|
|
94
88
|
}
|
|
@@ -100,25 +94,25 @@ const _isAllowedError = errorCode => {
|
|
|
100
94
|
// - for one unique value, we use it
|
|
101
95
|
// - if at least one 5xx exists, we use 500
|
|
102
96
|
// - else if at least one 4xx exists, we use 400
|
|
103
|
-
// - else we use 500
|
|
104
97
|
const _statusCodeFromDetails = uniqueStatusCodes => {
|
|
105
98
|
if (uniqueStatusCodes.size === 1) return uniqueStatusCodes.values().next().value
|
|
106
99
|
if ([...uniqueStatusCodes].some(s => s >= 500)) return 500
|
|
107
100
|
if ([...uniqueStatusCodes].some(s => s >= 400)) return 400
|
|
108
|
-
return 500
|
|
109
101
|
}
|
|
110
102
|
|
|
111
103
|
const normalizeError = (err, req) => {
|
|
112
104
|
const locale = req.locale || (req.locale = localeFrom(req))
|
|
113
|
-
|
|
105
|
+
let { error, statusCode } = _normalize(err, locale)
|
|
114
106
|
|
|
115
|
-
|
|
116
|
-
// error[SKIP_SANITIZATION] is not an official API!!!
|
|
117
|
-
if (statusCode >= 500 && process.env.NODE_ENV === 'production' && !error[SKIP_SANITIZATION]) {
|
|
107
|
+
if ((!statusCode || (statusCode >= 500 && err._thrownByFramework)) && process.env.NODE_ENV === 'production') {
|
|
118
108
|
// > return sanitized error to client
|
|
119
|
-
return {
|
|
109
|
+
return {
|
|
110
|
+
error: { code: statusCode ? `${statusCode}` : '500', message: i18n(statusCode || 500, locale) },
|
|
111
|
+
statusCode: Number(statusCode) || 500
|
|
112
|
+
}
|
|
120
113
|
}
|
|
121
|
-
|
|
114
|
+
|
|
115
|
+
if (!statusCode) statusCode = 500
|
|
122
116
|
|
|
123
117
|
// no top level null codes
|
|
124
118
|
if (error.code === 'null') {
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
const entry = require('./entry')
|
|
2
2
|
|
|
3
3
|
module.exports = (...args) => {
|
|
4
|
-
|
|
5
|
-
if (e instanceof Error)
|
|
6
|
-
|
|
4
|
+
let e = entry(...args)
|
|
5
|
+
if (!(e instanceof Error)) e = Object.assign(new Error(e.message), e)
|
|
6
|
+
// _thrownByFramework shouldn't be logged
|
|
7
|
+
Object.defineProperty(e, '_thrownByFramework', {
|
|
8
|
+
value: true,
|
|
9
|
+
enumerable: false
|
|
10
|
+
})
|
|
11
|
+
return e
|
|
7
12
|
}
|
|
@@ -2,7 +2,7 @@ const { cqnFrom } = require('./utils')
|
|
|
2
2
|
const { RESTRICTIONS } = require('./constants')
|
|
3
3
|
|
|
4
4
|
const _isRestricted = (req, capability, capabilityReadByKey) => {
|
|
5
|
-
if (capabilityReadByKey !== undefined && req.query.SELECT.one) {
|
|
5
|
+
if (capabilityReadByKey !== undefined && req.query.SELECT && req.query.SELECT.one) {
|
|
6
6
|
return capabilityReadByKey === false
|
|
7
7
|
}
|
|
8
8
|
return capability === false
|
|
@@ -29,6 +29,7 @@ const _localName = entity => entity.name.replace(entity._service.name + '.', '')
|
|
|
29
29
|
function handler(req) {
|
|
30
30
|
// TODO: Determine auth-relevant entity
|
|
31
31
|
const annotation = RESTRICTIONS[req.event]
|
|
32
|
+
|
|
32
33
|
if (!req.target || !annotation) return
|
|
33
34
|
|
|
34
35
|
const action = annotation.split('.').pop().toUpperCase()
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
const
|
|
2
|
-
const WRITE_EVENTS = Object.assign({ CREATE: 1, NEW: 1, PATCH: 1, CANCEL: 1 }, MOD_EVENTS)
|
|
3
|
-
const CRUD_EVENTS = Object.assign({ READ: 1 }, WRITE_EVENTS)
|
|
4
|
-
const DRAFT_EVENTS = { PATCH: 1, CANCEL: 1, draftActivate: 1, draftPrepare: 1 }
|
|
1
|
+
const { MOD_EVENTS, WRITE_EVENTS, CRUD_EVENTS, DRAFT_EVENTS } = require('../../constants/events')
|
|
5
2
|
|
|
6
3
|
const RESTRICTIONS = {
|
|
7
4
|
CREATE: 'InsertRestrictions.Insertable',
|
|
@@ -24,7 +24,7 @@ function handler(req) {
|
|
|
24
24
|
if (!definition) return
|
|
25
25
|
|
|
26
26
|
const requires = getRequiresAsArray(definition)
|
|
27
|
-
if (!requires
|
|
27
|
+
if (!requires || requires.some(role => req.user.is(role))) return
|
|
28
28
|
|
|
29
29
|
reject(req, getRejectReason(req, '@requires', definition))
|
|
30
30
|
}
|
|
@@ -25,7 +25,11 @@ const _getResolvedApplicables = (applicables, req) => {
|
|
|
25
25
|
(!resolved.where || resolved.where === restrict.where)
|
|
26
26
|
)
|
|
27
27
|
) {
|
|
28
|
-
if (resolved.where)
|
|
28
|
+
if (resolved.where) {
|
|
29
|
+
resolved._xpr = cds.parse.expr(resolved.where).xpr
|
|
30
|
+
if (!resolved._xpr)
|
|
31
|
+
req.reject(400, `Exists predicate is missing in the association path "${resolved.where}" in @restrict.where`)
|
|
32
|
+
}
|
|
29
33
|
resolvedApplicables.push(resolved)
|
|
30
34
|
}
|
|
31
35
|
}
|
|
@@ -49,6 +53,7 @@ const _evalStatic = (op, vals) => {
|
|
|
49
53
|
case '=':
|
|
50
54
|
return vals[0] === vals[1]
|
|
51
55
|
case '!=':
|
|
56
|
+
case '<>':
|
|
52
57
|
return vals[0] !== vals[1]
|
|
53
58
|
case '<':
|
|
54
59
|
return vals[0] < vals[1]
|
|
@@ -79,9 +84,11 @@ const _handleStaticAuth = (resolvedApplicables, req) => {
|
|
|
79
84
|
const _getMergedWhere = restricts => {
|
|
80
85
|
const xprs = []
|
|
81
86
|
restricts.forEach(ele => {
|
|
82
|
-
xprs.
|
|
87
|
+
if (xprs.length) {
|
|
88
|
+
xprs.push('or')
|
|
89
|
+
}
|
|
90
|
+
xprs.push({ xpr: [...ele._xpr] })
|
|
83
91
|
})
|
|
84
|
-
xprs.pop()
|
|
85
92
|
return xprs
|
|
86
93
|
}
|
|
87
94
|
|
|
@@ -111,9 +118,7 @@ const _addWheresToRef = (ref, model, resolvedApplicables) => {
|
|
|
111
118
|
if (!newIdentifier.where) newIdentifier.where = []
|
|
112
119
|
|
|
113
120
|
if (newIdentifier.where && newIdentifier.where.length) {
|
|
114
|
-
newIdentifier.where.
|
|
115
|
-
newIdentifier.where.push(')')
|
|
116
|
-
newIdentifier.where.push('and')
|
|
121
|
+
newIdentifier.where = [{ xpr: newIdentifier.where }, 'and']
|
|
117
122
|
}
|
|
118
123
|
|
|
119
124
|
newIdentifier.where.push(..._getMergedWhere(applicablesForEntity))
|
|
@@ -148,33 +153,12 @@ const _addRestrictionsToRead = async (req, model, resolvedApplicables) => {
|
|
|
148
153
|
const restrictionForTarget = _getRestrictionForTarget(resolvedApplicables, req.target)
|
|
149
154
|
if (!restrictionForTarget) return
|
|
150
155
|
|
|
151
|
-
// adjust free subselects, if necessary
|
|
152
|
-
if (resolvedApplicables.some(ra => ra.where.match(/\s*exists\s*\(\s*select\s*1\s*/i))) {
|
|
153
|
-
for (const ele of restrictionForTarget) {
|
|
154
|
-
if (typeof ele !== 'object' || !ele.SELECT || !ele.SELECT.where) continue
|
|
155
|
-
|
|
156
|
-
for (const w of ele.SELECT.where) {
|
|
157
|
-
if (w.ref && w.ref.length > 2) {
|
|
158
|
-
let path = w.ref[0]
|
|
159
|
-
if (!model.definitions[path]) continue
|
|
160
|
-
let i = 1
|
|
161
|
-
|
|
162
|
-
for (; i < w.ref.length; i++) {
|
|
163
|
-
if (model.definitions[`${path}.${w.ref[i]}`]) path += `.${w.ref[i]}`
|
|
164
|
-
else break
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
w.ref = [path, ...w.ref.slice(i)]
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
156
|
// apply restriction
|
|
174
157
|
req.query.where(restrictionForTarget)
|
|
175
158
|
}
|
|
176
159
|
|
|
177
160
|
const _getFromWithIsActiveEntityRemoved = from => {
|
|
161
|
+
if (!from.ref) return from
|
|
178
162
|
for (const element of from.ref) {
|
|
179
163
|
if (element.where && isActiveEntityRequested(element.where)) {
|
|
180
164
|
element.where = removeIsActiveEntityRecursively(element.where)
|
|
@@ -36,12 +36,15 @@ const _addNormalizedRestrict = (restrict, restricts, definition) => {
|
|
|
36
36
|
restrict.grant.forEach(grant => _addNormalizedRestrictPerGrant(grant, where, restrict, restricts, definition))
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
const getNormalizedRestrictions = (definition, definitions
|
|
39
|
+
const getNormalizedRestrictions = (definition, definitions) => {
|
|
40
40
|
const restricts = []
|
|
41
|
+
let isRestricted = false
|
|
41
42
|
|
|
42
43
|
// own
|
|
43
|
-
definition['@restrict']
|
|
44
|
+
if (definition['@restrict']) {
|
|
45
|
+
isRestricted = true
|
|
44
46
|
definition['@restrict'].forEach(restrict => _addNormalizedRestrict(restrict, restricts, definition))
|
|
47
|
+
}
|
|
45
48
|
|
|
46
49
|
// bounds
|
|
47
50
|
const actions = definition.actions
|
|
@@ -51,15 +54,20 @@ const getNormalizedRestrictions = (definition, definitions, event) => {
|
|
|
51
54
|
const action = actions[k]
|
|
52
55
|
|
|
53
56
|
if (action['@restrict']) {
|
|
54
|
-
|
|
57
|
+
const restrictions = getNormalizedRestrictions(action, definitions)
|
|
58
|
+
if (restrictions) {
|
|
59
|
+
isRestricted = true
|
|
60
|
+
restricts.push(...restrictions)
|
|
61
|
+
}
|
|
55
62
|
} else if (!definition['@restrict']) {
|
|
56
63
|
// > no entity-level restrictions => unrestricted action
|
|
64
|
+
isRestricted = true
|
|
57
65
|
restricts.push({ grant: action.name, to: ['any'], target: action.parent })
|
|
58
66
|
}
|
|
59
67
|
}
|
|
60
68
|
}
|
|
61
69
|
|
|
62
|
-
return restricts
|
|
70
|
+
return isRestricted ? restricts : null
|
|
63
71
|
}
|
|
64
72
|
|
|
65
73
|
const _isGrantAccessAllowed = (eventName, restrict) => restrict.grant === '*' || restrict.grant === eventName
|
|
@@ -141,7 +141,8 @@ const resolveUserAttrs = (restrict, req) => {
|
|
|
141
141
|
attr = parts.shift()
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
-
if (!skip)
|
|
144
|
+
if (!skip)
|
|
145
|
+
restrict.where = restrict.where.replace(next[0], val === undefined ? null : val).replace('in null', 'is null')
|
|
145
146
|
next = _getNext(restrict.where)
|
|
146
147
|
}
|
|
147
148
|
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
const cds = require('../../cds')
|
|
2
2
|
const { SELECT } = cds.ql
|
|
3
3
|
|
|
4
|
-
const getTemplate = require('../utils/template')
|
|
5
|
-
const templateProcessor = require('../utils/templateProcessor')
|
|
6
|
-
const replaceManagedData = require('../utils/dollar')
|
|
7
4
|
const { deepCopyArray } = require('../utils/copy')
|
|
8
5
|
|
|
9
|
-
const onlyKeysRemain = require('../utils/onlyKeysRemain')
|
|
10
6
|
const { getColumns } = require('../../cds-services/services/utils/columns')
|
|
11
7
|
|
|
8
|
+
const getError = require('../error')
|
|
9
|
+
|
|
12
10
|
const _targetEntityDoesNotExist = async req => {
|
|
13
11
|
const { query } = req
|
|
14
12
|
const cqn = SELECT.from(query.UPDATE.entity, [1])
|
|
@@ -26,58 +24,19 @@ const _targetEntityDoesNotExist = async req => {
|
|
|
26
24
|
return exists.length === 0
|
|
27
25
|
}
|
|
28
26
|
|
|
29
|
-
|
|
30
|
-
const { event, user, timestamp } = req
|
|
31
|
-
const ts = new Date(timestamp).toISOString()
|
|
32
|
-
|
|
33
|
-
return ({ row, key, plain, isRoot }) => {
|
|
34
|
-
for (const category of plain.categories) {
|
|
35
|
-
if (event === 'CREATE' && category === '@cds.on.insert') {
|
|
36
|
-
replaceManagedData(row, key, user, ts)
|
|
37
|
-
} else if (category === '@cds.on.update') {
|
|
38
|
-
if (isRoot) replaceManagedData(row, key, user, ts)
|
|
39
|
-
else if (row[key] === '$user' || row[key] === '$now') delete row[key]
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// params: element, target, parent, templateElements
|
|
46
|
-
const _pick = element => {
|
|
47
|
-
// collect actions to apply
|
|
48
|
-
const categories = []
|
|
49
|
-
|
|
50
|
-
if (element['@cds.on.insert']) categories.push('@cds.on.insert')
|
|
51
|
-
if (element['@cds.on.update']) categories.push('@cds.on.update')
|
|
52
|
-
|
|
53
|
-
if (categories.length) return { categories }
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const _updateReqData = (req, that) => {
|
|
57
|
-
const template = getTemplate('app-output', that, req.target, { pick: _pick })
|
|
58
|
-
|
|
59
|
-
if (template.elements.size > 0) {
|
|
60
|
-
const arrayData = Array.isArray(req.data) ? req.data : [req.data]
|
|
61
|
-
for (const row of arrayData) {
|
|
62
|
-
const args = {
|
|
63
|
-
processFn: _processorFn(req),
|
|
64
|
-
row,
|
|
65
|
-
template
|
|
66
|
-
}
|
|
67
|
-
templateProcessor(args)
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
module.exports = cds.service.impl(function () {
|
|
27
|
+
exports.impl = cds.service.impl(function () {
|
|
73
28
|
// eslint-disable-next-line complexity
|
|
74
29
|
this.on(['CREATE', 'READ', 'UPDATE', 'DELETE'], '*', async function (req) {
|
|
75
30
|
if (typeof req.query !== 'string' && req.target && req.target._hasPersistenceSkip) {
|
|
76
|
-
|
|
31
|
+
throw getError({
|
|
32
|
+
code: 501,
|
|
33
|
+
message: 'PERSISTENCE_SKIP_NO_GENERIC_CRUD',
|
|
34
|
+
args: [req.target.name]
|
|
35
|
+
})
|
|
77
36
|
}
|
|
78
37
|
|
|
79
38
|
// REVISIT: error message
|
|
80
|
-
if (!cds.db) req.reject(
|
|
39
|
+
if (!cds.db) req.reject('NO_DATABASE_CONNECTION')
|
|
81
40
|
|
|
82
41
|
let result
|
|
83
42
|
|
|
@@ -94,13 +53,6 @@ module.exports = cds.service.impl(function () {
|
|
|
94
53
|
if (res.length === 0) req.reject(404)
|
|
95
54
|
}
|
|
96
55
|
|
|
97
|
-
// REVISIT: remove block with cds^6 (i.e., update_managed_properties is always true)
|
|
98
|
-
// no changes, no op (otherwise, @cds.on.update gets new values), but we need to check existence
|
|
99
|
-
if (cds.env.features.update_managed_properties === false && req.event === 'UPDATE' && onlyKeysRemain(req)) {
|
|
100
|
-
if (await _targetEntityDoesNotExist(req)) req.reject(404)
|
|
101
|
-
result = req.data
|
|
102
|
-
}
|
|
103
|
-
|
|
104
56
|
if (req.event in { DELETE: 1, UPDATE: 1 } && req.target && req.target._isSingleton) {
|
|
105
57
|
if (req.event === 'DELETE' && !req.target['@odata.singleton.nullable']) req.reject(400, 'SINGLETON_NOT_NULLABLE')
|
|
106
58
|
const keyColumns = getColumns(req.target, { onlyNames: true, keysOnly: true })
|
|
@@ -136,9 +88,6 @@ module.exports = cds.service.impl(function () {
|
|
|
136
88
|
// flag to trigger read after write in protocol adapter
|
|
137
89
|
req._.readAfterWrite = true
|
|
138
90
|
|
|
139
|
-
// update req.data
|
|
140
|
-
_updateReqData(req, this)
|
|
141
|
-
|
|
142
91
|
return req.data
|
|
143
92
|
})
|
|
144
93
|
})
|
|
@@ -5,6 +5,7 @@ const { SELECT } = cds.ql
|
|
|
5
5
|
const { isActiveEntityRequested } = require('../../fiori/utils/where')
|
|
6
6
|
const { ensureDraftsSuffix } = require('../../fiori/utils/handler')
|
|
7
7
|
const { cqn2cqn4sql } = require('../../common/utils/cqn2cqn4sql')
|
|
8
|
+
const { isAsteriskColumn } = require('../../common/utils/rewriteAsterisks')
|
|
8
9
|
const ODataRequest = require('../../cds-services/adapter/odata-v4/ODataRequest')
|
|
9
10
|
|
|
10
11
|
const C_U_ = {
|
|
@@ -25,12 +26,44 @@ const getSelectCQN = (query, target, model) => {
|
|
|
25
26
|
|
|
26
27
|
const targetName = isActiveEntityRequested(requestTarget.ref[0].where) ? target.name : ensureDraftsSuffix(target.name)
|
|
27
28
|
const cqn = cqn2cqn4sql(SELECT.from(requestTarget), model)
|
|
28
|
-
cqn.columns([target._etag])
|
|
29
|
+
cqn.columns([target._etag.name])
|
|
29
30
|
cqn.SELECT.from.ref[0] = targetName
|
|
30
31
|
|
|
31
32
|
return cqn
|
|
32
33
|
}
|
|
33
34
|
|
|
35
|
+
/**
|
|
36
|
+
Recursively adds etag columns if a manual list of columns is specified.
|
|
37
|
+
If asterisk columns or no columns are given, the database layer will
|
|
38
|
+
add the etag columns anyway.
|
|
39
|
+
*/
|
|
40
|
+
const _addEtagColumns = (columns, entity) => {
|
|
41
|
+
if (!columns || !Array.isArray(columns)) return
|
|
42
|
+
if (
|
|
43
|
+
entity._etag &&
|
|
44
|
+
!columns.some(c => isAsteriskColumn(c)) &&
|
|
45
|
+
!(columns.length === 1 && columns[0].func === 'count') &&
|
|
46
|
+
!columns.some(c => c.ref && c.ref[c.ref.length - 1] === entity._etag.name)
|
|
47
|
+
) {
|
|
48
|
+
columns.push({ ref: [entity._etag.name] })
|
|
49
|
+
}
|
|
50
|
+
const expands = columns.filter(c => c.expand)
|
|
51
|
+
for (const expand of expands) {
|
|
52
|
+
const refName = expand.ref[expand.ref.length - 1]
|
|
53
|
+
const targetEntity = refName && entity.elements[refName] && entity.elements[refName]._target
|
|
54
|
+
if (targetEntity) {
|
|
55
|
+
_addEtagColumns(expand.expand, targetEntity)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const _isConcurrentODataReq = req => {
|
|
61
|
+
const isReadAfterDraftAction =
|
|
62
|
+
req.event === 'READ' && req.target._isDraftEnabled && req.context.event in { draftActivate: 1, EDIT: 1 }
|
|
63
|
+
const _req = isReadAfterDraftAction ? req.context : req
|
|
64
|
+
return _req instanceof ODataRequest && _req.isConcurrentResource
|
|
65
|
+
}
|
|
66
|
+
|
|
34
67
|
/**
|
|
35
68
|
* Generic handler for @odata.etag-enabled entities
|
|
36
69
|
*
|
|
@@ -39,8 +72,12 @@ const getSelectCQN = (query, target, model) => {
|
|
|
39
72
|
const _handler = async function (req) {
|
|
40
73
|
// REVISIT: The check for ODataRequest should be removed after etag logic is moved
|
|
41
74
|
// from okra to commons and etag handling is also allowed for rest.
|
|
42
|
-
|
|
43
|
-
|
|
75
|
+
|
|
76
|
+
if (_isConcurrentODataReq(req)) {
|
|
77
|
+
const etagElement = req.target.elements[req.target._etag.name]
|
|
78
|
+
|
|
79
|
+
// automatically add etag columns if not already there
|
|
80
|
+
if (req.query.SELECT) _addEtagColumns(req.query.SELECT.columns, req.target)
|
|
44
81
|
|
|
45
82
|
// validate
|
|
46
83
|
if (req.isConditional && !req.query.INSERT) {
|
|
@@ -72,10 +109,7 @@ module.exports = cds.service.impl(function () {
|
|
|
72
109
|
for (const k in this.entities) {
|
|
73
110
|
const entity = this.entities[k]
|
|
74
111
|
|
|
75
|
-
if (!
|
|
76
|
-
// entity not @odata.etag-enabled
|
|
77
|
-
continue
|
|
78
|
-
}
|
|
112
|
+
if (!entity._etag) continue
|
|
79
113
|
|
|
80
114
|
// handler for CREATE is registered for backwards compatibility w.r.t. ETag generation
|
|
81
115
|
let events = ['CREATE', 'READ', 'UPDATE', 'DELETE']
|