@sap/cds 5.9.8 → 6.0.3
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 +277 -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 +83 -41
- package/bin/build/provider/mtx/resourcesTarBuilder.js +68 -0
- package/bin/build/provider/mtx-sidecar/index.js +110 -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 +21 -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 +15 -13
- package/bin/{build → deploy/to-hana}/mtaUtil.js +10 -9
- package/bin/mtx/in-cds.js +19 -7
- package/bin/serve.js +49 -22
- package/bin/utils/log.js +13 -30
- package/bin/version.js +4 -3
- 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 +10 -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 +71 -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 +22 -20
- package/lib/serve/index.js +51 -54
- package/lib/utils/axios.js +8 -12
- package/lib/utils/index.js +13 -4
- 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 +127 -41
- package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +9 -5
- package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +93 -73
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/action.js +25 -45
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/create.js +10 -14
- 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 +2 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +21 -26
- 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 +97 -92
- 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 +82 -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 +8 -7
- 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 +13 -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 +7 -3
- 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 +2 -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 +4 -16
- package/libx/_runtime/fiori/generic/index.js +31 -0
- package/libx/_runtime/fiori/generic/new.js +5 -21
- package/libx/_runtime/fiori/generic/patch.js +10 -15
- package/libx/_runtime/fiori/generic/prepare.js +13 -22
- package/libx/_runtime/fiori/generic/read.js +148 -163
- package/libx/_runtime/fiori/generic/readOverDraft.js +10 -4
- package/libx/_runtime/fiori/utils/handler.js +10 -22
- 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 +30 -22
- 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 +3 -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 +90 -48
- 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 +263 -156
- 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
|
@@ -7,48 +7,21 @@ const {
|
|
|
7
7
|
} = require('../okra/odata-server')
|
|
8
8
|
|
|
9
9
|
const { getSapMessages } = require('../../../../common/error/frontend')
|
|
10
|
-
const {
|
|
10
|
+
const { getActionOrFunctionReturnType, isReturnMinimal } = require('../utils/handlerUtils')
|
|
11
11
|
const { validateResourcePath } = require('../utils/request')
|
|
12
|
-
const readAfterWrite = require('../utils/readAfterWrite')
|
|
13
|
-
const { setStatusCodeAndHeader, getKeyProperty } = require('../../../../fiori/utils/handler')
|
|
14
12
|
const { toODataResult, postProcess } = require('../utils/result')
|
|
15
|
-
const {
|
|
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
|
-
|
|
23
|
-
const _postProcessDraftActivate = async (req, result, service) => {
|
|
24
|
-
// update req.data (keys needed in readAfterWrite)
|
|
25
|
-
req.data = result
|
|
26
|
-
const dataInDb = await readAfterWrite(req, service)
|
|
27
|
-
if (dataInDb.length) result = mergeJson(dataInDb[0], result, req.target)
|
|
28
|
-
|
|
29
|
-
// add static draft columns
|
|
30
|
-
result.IsActiveEntity = true
|
|
31
|
-
result.HasActiveEntity = false
|
|
32
|
-
result.HasDraftEntity = false
|
|
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
|
-
|
|
41
|
-
return result
|
|
42
|
-
}
|
|
13
|
+
const { DRAFT_EVENTS } = require('../../../../common/constants/events')
|
|
14
|
+
const { readAfterWrite } = require('../utils/readAfterWrite')
|
|
43
15
|
|
|
44
16
|
const _postProcess = async (req, odataReq, odataRes, tx, result) => {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
result = await actionAndFunctionQueries(req, odataReq, result, tx, actionReturnType)
|
|
17
|
+
const returnType = getActionOrFunctionReturnType(odataReq.getUriInfo().getPathSegments(), tx.model.definitions)
|
|
18
|
+
// as of spec meeting: no generic support of $select/$expand for custom actions/functions
|
|
19
|
+
if (returnType && returnType.kind === 'entity' && (req.event in DRAFT_EVENTS || req.event === 'EDIT')) {
|
|
20
|
+
result = await readAfterWrite(req, tx, { operation: { result, returnType } })
|
|
21
|
+
if (result && !('IsActiveEntity' in result)) result.IsActiveEntity = req.event === 'draftActivate'
|
|
51
22
|
}
|
|
23
|
+
const _req = Object.setPrototypeOf({ target: returnType || req.target }, req)
|
|
24
|
+
postProcess(_req, odataRes, tx, result)
|
|
52
25
|
return result
|
|
53
26
|
}
|
|
54
27
|
|
|
@@ -78,14 +51,6 @@ const action = service => {
|
|
|
78
51
|
try {
|
|
79
52
|
result = await tx.dispatch(req)
|
|
80
53
|
|
|
81
|
-
// post processing for draftActivate
|
|
82
|
-
if (req.event === 'draftActivate') {
|
|
83
|
-
result = await _postProcessDraftActivate(req, result, service)
|
|
84
|
-
|
|
85
|
-
const k = getKeyProperty(req.target.keys)
|
|
86
|
-
setStatusCodeAndHeader(odataRes, { [k]: result[k] }, req.target.name.replace(`${service.name}.`, ''), true)
|
|
87
|
-
}
|
|
88
|
-
|
|
89
54
|
result = await _postProcess(req, odataReq, odataRes, tx, result)
|
|
90
55
|
|
|
91
56
|
if (changeset) {
|
|
@@ -94,6 +59,21 @@ const action = service => {
|
|
|
94
59
|
} else {
|
|
95
60
|
await tx.commit(result)
|
|
96
61
|
}
|
|
62
|
+
|
|
63
|
+
if (isReturnMinimal(req) || result === null) odataRes.setStatusCode(204)
|
|
64
|
+
else if (req.event === 'draftActivate' || req.event === 'EDIT') {
|
|
65
|
+
odataRes.setStatusCode(201)
|
|
66
|
+
const keys = Object.keys(req.target.keys).filter(k => {
|
|
67
|
+
return k !== 'IsActiveEntity' && !req.target.keys[k]._isAssociationStrict
|
|
68
|
+
})
|
|
69
|
+
const keysString = keys.map(key => `${key}=${result[key]}`).join(',')
|
|
70
|
+
odataRes.setHeader(
|
|
71
|
+
'location',
|
|
72
|
+
`../${req.target.name.replace(`${service.name}.`, '')}(${keysString},IsActiveEntity=${
|
|
73
|
+
req.event === 'draftActivate'
|
|
74
|
+
})`
|
|
75
|
+
)
|
|
76
|
+
}
|
|
97
77
|
} catch (e) {
|
|
98
78
|
err = e
|
|
99
79
|
|
|
@@ -7,11 +7,9 @@ const {
|
|
|
7
7
|
|
|
8
8
|
const { validateResourcePath } = require('../utils/request')
|
|
9
9
|
const { isReturnMinimal } = require('../utils/handlerUtils')
|
|
10
|
-
const readAfterWrite = require('../utils/readAfterWrite')
|
|
10
|
+
const { readAfterWrite } = require('../utils/readAfterWrite')
|
|
11
11
|
const { toODataResult, postProcess, postProcessMinimal } = require('../utils/result')
|
|
12
12
|
|
|
13
|
-
const { mergeJson } = require('../../../services/utils/compareJson')
|
|
14
|
-
|
|
15
13
|
const { getSapMessages } = require('../../../../common/error/frontend')
|
|
16
14
|
|
|
17
15
|
/**
|
|
@@ -40,17 +38,15 @@ const create = service => {
|
|
|
40
38
|
try {
|
|
41
39
|
result = await tx.dispatch(req)
|
|
42
40
|
|
|
43
|
-
// REVISIT
|
|
44
|
-
|
|
41
|
+
// REVISIT:
|
|
42
|
+
// Performance: For `isReturnMinimal` it's enough to just read the etag.
|
|
43
|
+
// Note: Without read access, one cannot return the etag.
|
|
44
|
+
if (req._.readAfterWrite) {
|
|
45
|
+
result = await readAfterWrite(req, service, { operation: { result } })
|
|
46
|
+
}
|
|
45
47
|
if (isReturnMinimal(req)) {
|
|
46
|
-
postProcessMinimal(req, result)
|
|
48
|
+
result = postProcessMinimal(req, service, result)
|
|
47
49
|
} else {
|
|
48
|
-
// REVISIT: find better solution
|
|
49
|
-
if (req._.readAfterWrite) {
|
|
50
|
-
const dataInDb = await readAfterWrite(req, service)
|
|
51
|
-
if (dataInDb.length) result = mergeJson(dataInDb[0], result, req.target)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
50
|
postProcess(req, odataRes, service, result)
|
|
55
51
|
}
|
|
56
52
|
|
|
@@ -61,7 +57,7 @@ const create = service => {
|
|
|
61
57
|
await tx.commit(result)
|
|
62
58
|
}
|
|
63
59
|
|
|
64
|
-
if (isReturnMinimal(req)) {
|
|
60
|
+
if (isReturnMinimal(req) || result === null) {
|
|
65
61
|
odataRes.setStatusCode(204)
|
|
66
62
|
}
|
|
67
63
|
} catch (e) {
|
|
@@ -78,7 +74,7 @@ const create = service => {
|
|
|
78
74
|
req.messages && odataRes.setHeader('sap-messages', getSapMessages(req.messages, req._.req))
|
|
79
75
|
|
|
80
76
|
if (err) next(err)
|
|
81
|
-
else next(null, toODataResult(result))
|
|
77
|
+
else next(null, toODataResult(result, req))
|
|
82
78
|
}
|
|
83
79
|
}
|
|
84
80
|
}
|
|
@@ -12,14 +12,12 @@ const ERROR_TO_HTTP_CODE = {
|
|
|
12
12
|
MethodNotAllowedError: HttpStatusCodes.METHOD_NOT_ALLOWED,
|
|
13
13
|
NotAcceptableError: HttpStatusCodes.NOT_ACCEPTABLE,
|
|
14
14
|
NotAuthorizedError: HttpStatusCodes.UNAUTHORIZED,
|
|
15
|
-
InternalServerError: HttpStatusCodes.INTERNAL_SERVER_ERROR,
|
|
16
15
|
PreconditionFailedError: HttpStatusCodes.PRECONDITION_FAILED,
|
|
17
16
|
PreconditionRequiredError: HttpStatusCodes.PRECONDITION_REQUIRED,
|
|
18
17
|
ConflictError: HttpStatusCodes.CONFLICT,
|
|
19
18
|
NotFoundError: HttpStatusCodes.NOT_FOUND,
|
|
20
19
|
BadRequestError: HttpStatusCodes.BAD_REQUEST,
|
|
21
20
|
// custom
|
|
22
|
-
SerializationError: HttpStatusCodes.INTERNAL_SERVER_ERROR,
|
|
23
21
|
DeserializationError: HttpStatusCodes.BAD_REQUEST
|
|
24
22
|
}
|
|
25
23
|
|
|
@@ -40,9 +38,9 @@ const _buildRootCauseMessage = (message, rootCause) => {
|
|
|
40
38
|
}
|
|
41
39
|
|
|
42
40
|
const _betterOkraError = err => {
|
|
43
|
-
const statusCode = ERROR_TO_HTTP_CODE[err.name]
|
|
44
|
-
if (!('code' in err)) err.code = String(statusCode)
|
|
45
|
-
if (!err.statusCode) err.statusCode = statusCode
|
|
41
|
+
const statusCode = ERROR_TO_HTTP_CODE[err.name]
|
|
42
|
+
if (statusCode && !('code' in err)) err.code = String(statusCode)
|
|
43
|
+
if (statusCode && !err.statusCode) err.statusCode = statusCode
|
|
46
44
|
|
|
47
45
|
err.message = _buildRootCauseMessage(err.message, err.getRootCause())
|
|
48
46
|
|
|
@@ -68,6 +66,10 @@ const _betterOkraError = err => {
|
|
|
68
66
|
'An error occurred during serialization of the entity collection. An error occurred during serialization of',
|
|
69
67
|
'Serialization Error for'
|
|
70
68
|
)
|
|
69
|
+
} else if (err.name === 'PreconditionFailedError') {
|
|
70
|
+
// REVISIT use cds.error here once it is official API?
|
|
71
|
+
const { error } = normalizeError(new cds.Request().error(412, '412'), { headers: {}, query: {} })
|
|
72
|
+
return error
|
|
71
73
|
}
|
|
72
74
|
|
|
73
75
|
return err
|
|
@@ -129,6 +131,8 @@ const getErrorHandler = (crashOnError = true, srv) => {
|
|
|
129
131
|
if (contentId && !contentId.match(/^~/)) err['@Core.ContentID'] = contentId
|
|
130
132
|
|
|
131
133
|
const { error, statusCode } = normalizeError(err, req)
|
|
134
|
+
// REVISIT: We should also pass stack traces in development
|
|
135
|
+
// if (!cds.env.production) error.stack = err.stack
|
|
132
136
|
|
|
133
137
|
next(null, Object.assign(error, { statusCode }))
|
|
134
138
|
}
|
|
@@ -3,6 +3,7 @@ const LOG = cds.log('odata')
|
|
|
3
3
|
|
|
4
4
|
const { toODataResult } = require('../utils/result')
|
|
5
5
|
const { normalizeError } = require('../../../../common/error/frontend')
|
|
6
|
+
const getError = require('../../../../common/error')
|
|
6
7
|
|
|
7
8
|
const _getMetadata4Tenant = async (tenant, locale, service) => {
|
|
8
9
|
return await cds.mtx.getEdmx(tenant, service.name, locale)
|
|
@@ -24,7 +25,7 @@ const metadata = service => {
|
|
|
24
25
|
try {
|
|
25
26
|
let edmx
|
|
26
27
|
|
|
27
|
-
if (cds.
|
|
28
|
+
if (cds.mtx && service._isExtended) {
|
|
28
29
|
edmx = await _getMetadata4Tenant(tenant, locale, service)
|
|
29
30
|
}
|
|
30
31
|
|
|
@@ -44,7 +45,8 @@ const metadata = service => {
|
|
|
44
45
|
LOG.error(e)
|
|
45
46
|
}
|
|
46
47
|
// return 503 to client
|
|
47
|
-
const
|
|
48
|
+
const err = getError(Object.assign(e, { statusCode: 503 }))
|
|
49
|
+
const { error, statusCode } = normalizeError(err, req)
|
|
48
50
|
return next(Object.assign(error, { statusCode }))
|
|
49
51
|
}
|
|
50
52
|
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
const cds = require('../../../../cds')
|
|
2
2
|
|
|
3
|
-
const { SELECT } = cds.ql
|
|
4
|
-
|
|
5
3
|
const ODataRequest = require('../ODataRequest')
|
|
6
4
|
|
|
7
5
|
const {
|
|
@@ -16,14 +14,14 @@ const {
|
|
|
16
14
|
const FUNCTION = { [BOUND_FUNCTION]: 1, [FUNCTION_IMPORT]: 1 }
|
|
17
15
|
|
|
18
16
|
const { isCustomOperation } = require('../utils/request')
|
|
19
|
-
const {
|
|
17
|
+
const { getActionOrFunctionReturnType } = require('../utils/handlerUtils')
|
|
20
18
|
const { validateResourcePath } = require('../utils/request')
|
|
21
19
|
const { toODataResult, postProcess } = require('../utils/result')
|
|
22
20
|
const { isStreaming, getStreamProperties } = require('../utils/stream')
|
|
23
21
|
const { resolveStructuredName } = require('../utils/handlerUtils')
|
|
24
|
-
|
|
25
22
|
const getError = require('../../../../common/error')
|
|
26
23
|
const { getSapMessages } = require('../../../../common/error/frontend')
|
|
24
|
+
const { getMaxPageSize } = require('../../../../common/utils/page')
|
|
27
25
|
|
|
28
26
|
/**
|
|
29
27
|
* Checks whether a bound function or function import is invoked.
|
|
@@ -34,10 +32,6 @@ const { getSapMessages } = require('../../../../common/error/frontend')
|
|
|
34
32
|
*/
|
|
35
33
|
const _isFunction = segments => segments[segments.length - 1].getKind() in FUNCTION
|
|
36
34
|
|
|
37
|
-
const _selectOrExpandInQueryOptions = queryOptions => {
|
|
38
|
-
return queryOptions && (queryOptions.$select || queryOptions.$expand)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
35
|
/**
|
|
42
36
|
* Invoke a function.
|
|
43
37
|
*
|
|
@@ -47,23 +41,9 @@ const _selectOrExpandInQueryOptions = queryOptions => {
|
|
|
47
41
|
* @returns {Promise}
|
|
48
42
|
* @private
|
|
49
43
|
*/
|
|
50
|
-
const _invokeFunction = async (tx, req
|
|
44
|
+
const _invokeFunction = async (tx, req) => {
|
|
51
45
|
let result = await tx.dispatch(req)
|
|
52
46
|
|
|
53
|
-
const functionReturnType = getActionOrFunctionReturnType(
|
|
54
|
-
odataReq.getUriInfo().getPathSegments(),
|
|
55
|
-
tx.model.definitions
|
|
56
|
-
)
|
|
57
|
-
|
|
58
|
-
// if $select or $expand is present, do it
|
|
59
|
-
if (
|
|
60
|
-
functionReturnType &&
|
|
61
|
-
functionReturnType.kind === 'entity' &&
|
|
62
|
-
_selectOrExpandInQueryOptions(odataReq.getQueryOptions())
|
|
63
|
-
) {
|
|
64
|
-
result = await actionAndFunctionQueries(req, odataReq, result, tx, functionReturnType)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
47
|
return toODataResult(result, req)
|
|
68
48
|
}
|
|
69
49
|
|
|
@@ -86,31 +66,43 @@ const _isCount = segments => segments[segments.length - 1].getKind() === COUNT
|
|
|
86
66
|
* @private
|
|
87
67
|
*/
|
|
88
68
|
const _getCount = async (tx, readReq) => {
|
|
89
|
-
// REVISIT
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
69
|
+
// REVISIT once new parser is out of beta
|
|
70
|
+
// New parser directly removes unapplicable query options from query, no copying of cqn needed
|
|
71
|
+
if (cds.env.features.odata_new_parser) {
|
|
72
|
+
// todo check limit
|
|
73
|
+
const result = await tx.dispatch(readReq)
|
|
74
|
+
|
|
75
|
+
const count = result.reduce((acc, val) => {
|
|
76
|
+
return acc + ((val && (val.$count || val._counted_)) || (val[0] && (val[0].$count || val[0]._counted_))) || 0
|
|
77
|
+
}, 0)
|
|
78
|
+
// Transform into scalar result
|
|
79
|
+
return toODataResult(count)
|
|
80
|
+
} else {
|
|
81
|
+
// REVISIT: this process appears to be rather clumsy
|
|
82
|
+
// Copy CQN including from, where and search + changing columns
|
|
83
|
+
const select = SELECT.from(readReq.query.SELECT.from)
|
|
84
|
+
select.SELECT.columns = [{ func: 'count', args: [{ val: '1' }], as: '$count' }]
|
|
85
|
+
|
|
86
|
+
if (readReq.query.SELECT.where) select.SELECT.where = readReq.query.SELECT.where
|
|
87
|
+
if (readReq.query.SELECT.search) select.SELECT.search = readReq.query.SELECT.search
|
|
88
|
+
const req = readReq
|
|
89
|
+
|
|
90
|
+
// preserve _target
|
|
91
|
+
select._target = req.query._target
|
|
92
|
+
|
|
93
|
+
// remove as Object.defineProperty would cause a conflict
|
|
94
|
+
delete req.query
|
|
95
|
+
|
|
96
|
+
// Define new CQN
|
|
97
|
+
req.query = select
|
|
98
|
+
// todo check limit
|
|
99
|
+
const result = await tx.dispatch(req)
|
|
100
|
+
|
|
101
|
+
const count = result.$count || result._counted_ || (result[0] && (result[0].$count || result[0]._counted_)) || 0
|
|
102
|
+
|
|
103
|
+
// Transform into scalar result
|
|
104
|
+
return toODataResult(count, req)
|
|
105
|
+
}
|
|
114
106
|
}
|
|
115
107
|
|
|
116
108
|
/**
|
|
@@ -232,12 +224,12 @@ const _readEntityOrProperty = async (tx, req, segments) => {
|
|
|
232
224
|
if (propertyElement === null) {
|
|
233
225
|
_transformRedirectProperties(req, result)
|
|
234
226
|
|
|
235
|
-
return toODataResult(result[0])
|
|
227
|
+
return toODataResult(result[0], req)
|
|
236
228
|
}
|
|
237
229
|
|
|
238
230
|
result = _getResult(resolveStructuredName(segments, segments.length - 2), result[0])
|
|
239
231
|
|
|
240
|
-
if (req.target._etag) result.$etag = result[req.target._etag]
|
|
232
|
+
if (req.target._etag) result.$etag = result[req.target._etag.name]
|
|
241
233
|
|
|
242
234
|
const odataResult = toODataResult(result, req)
|
|
243
235
|
|
|
@@ -269,10 +261,25 @@ const _readEntityOrProperty = async (tx, req, segments) => {
|
|
|
269
261
|
*/
|
|
270
262
|
const _readCollection = async (tx, req, odataReq) => {
|
|
271
263
|
const result = (await tx.dispatch(req)) || []
|
|
264
|
+
if (Array.isArray(req.query)) {
|
|
265
|
+
const adjustedResult = []
|
|
266
|
+
if (req.query[0].SELECT.count) adjustedResult.$count = 0
|
|
267
|
+
adjustedResult.push(...result[0])
|
|
268
|
+
adjustedResult.$count += result[0].$count ? result[0].$count : 0
|
|
269
|
+
for (let i = 1; i < result.length; i++) {
|
|
270
|
+
adjustedResult.push(...result[i])
|
|
271
|
+
adjustedResult.$count += result[i].$count ? result[i].$count : 0
|
|
272
|
+
//Add OData context, if it deviates from main context
|
|
273
|
+
if (req._metaInfo.contextUrl !== req._metaInfo.additionalContextUrl[i - 1])
|
|
274
|
+
result[i].forEach(entry => (entry['*@odata.context'] = req._metaInfo.additionalContextUrl[i - 1]))
|
|
275
|
+
}
|
|
276
|
+
result.splice(0, result.length, ...adjustedResult)
|
|
277
|
+
if (req.query[0].SELECT.count) result.$count = adjustedResult.$count || 0
|
|
278
|
+
} else if (req.query.SELECT.count && !('$count' in result)) result.$count = 0
|
|
272
279
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
280
|
+
const limit = Array.isArray(req.query)
|
|
281
|
+
? getMaxPageSize(req.query[0]._target)
|
|
282
|
+
: req.query.SELECT.limit && req.query.SELECT.limit.rows && req.query.SELECT.limit.rows.val
|
|
276
283
|
const top = odataReq.getUriInfo().getQueryOption(QueryOptions.TOP)
|
|
277
284
|
if (limit && limit === result.length && limit !== top && !('$nextLink' in result)) {
|
|
278
285
|
const token = odataReq.getUriInfo().getQueryOption(QueryOptions.SKIPTOKEN)
|
|
@@ -25,7 +25,7 @@ module.exports = srv => {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
// check @requires as soon as possible (DoS)
|
|
28
|
-
if (requires
|
|
28
|
+
if (requires && !requires.some(r => user.is(r))) {
|
|
29
29
|
// > unauthorized or forbidden?
|
|
30
30
|
if (user._is_anonymous) {
|
|
31
31
|
if (user._challenges) res.set('WWW-Authenticate', user._challenges.join(';'))
|
|
@@ -51,7 +51,7 @@ module.exports = srv => {
|
|
|
51
51
|
})
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
odataReq.setApplicationData({ req })
|
|
54
|
+
odataReq.setApplicationData({ req, res })
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
next()
|
|
@@ -8,28 +8,25 @@ const {
|
|
|
8
8
|
|
|
9
9
|
const { validateResourcePath } = require('../utils/request')
|
|
10
10
|
const { isReturnMinimal } = require('../utils/handlerUtils')
|
|
11
|
-
const readAfterWrite = require('../utils/readAfterWrite')
|
|
11
|
+
const { readAfterWrite } = require('../utils/readAfterWrite')
|
|
12
12
|
const { toODataResult, postProcess, postProcessMinimal } = require('../utils/result')
|
|
13
13
|
const { hasOmitValuesPreference } = require('../utils/omitValues')
|
|
14
14
|
|
|
15
|
-
const { mergeJson } = require('../../../services/utils/compareJson')
|
|
16
|
-
|
|
17
15
|
const { getSapMessages } = require('../../../../common/error/frontend')
|
|
18
16
|
|
|
19
17
|
const _isUpsertAllowed = target => {
|
|
20
18
|
return !(cds.env.runtime && cds.env.runtime.allow_upsert === false) && !(target && target._isDraftEnabled)
|
|
21
19
|
}
|
|
22
20
|
|
|
23
|
-
const _infoForeignKeyInParent = (req,
|
|
21
|
+
const _infoForeignKeyInParent = (req, tx) => {
|
|
24
22
|
const info = {}
|
|
25
23
|
// keys not in data
|
|
26
24
|
if (req.target.keys && Object.keys(req.target.keys).some(key => key in req.data)) {
|
|
27
25
|
return info
|
|
28
26
|
}
|
|
29
27
|
|
|
30
|
-
|
|
31
|
-
const
|
|
32
|
-
const parent = req.query.INSERT.into.ref && req.query.INSERT.into.ref[0].id
|
|
28
|
+
const nav = req.query.UPDATE.entity.ref && req.query.UPDATE.entity.ref.length !== 0 && req.query.UPDATE.entity.ref[1]
|
|
29
|
+
const parent = req.query.UPDATE.entity.ref && req.query.UPDATE.entity.ref[0].id
|
|
33
30
|
|
|
34
31
|
// not a navigation
|
|
35
32
|
if (!parent || !nav) {
|
|
@@ -40,18 +37,18 @@ const _infoForeignKeyInParent = (req, odataReq, odataRes, tx) => {
|
|
|
40
37
|
const navElement = tx.model.definitions[parent].elements[navID]
|
|
41
38
|
|
|
42
39
|
// not a containment
|
|
43
|
-
if (!navElement
|
|
40
|
+
if (!navElement._isContained) {
|
|
44
41
|
return info
|
|
45
42
|
}
|
|
46
43
|
|
|
47
|
-
const where = req.query.
|
|
44
|
+
const where = req.query.UPDATE.entity.ref[0].where
|
|
48
45
|
return { parent, navElement, where }
|
|
49
46
|
}
|
|
50
47
|
|
|
51
48
|
const _create = async (req, odataReq, odataRes, tx) => {
|
|
52
49
|
let result
|
|
53
50
|
|
|
54
|
-
const { parent, navElement, where } = _infoForeignKeyInParent(req,
|
|
51
|
+
const { parent, navElement, where } = _infoForeignKeyInParent(req, tx)
|
|
55
52
|
if (parent && navElement && where) {
|
|
56
53
|
const onKeys = navElement._foreignKeys
|
|
57
54
|
const parentKeys = onKeys.filter(key => key.parentElement).map(key => key.parentElement.name)
|
|
@@ -107,14 +104,10 @@ const _updateThenCreate = async (req, odataReq, odataRes, tx) => {
|
|
|
107
104
|
return [result, req]
|
|
108
105
|
}
|
|
109
106
|
|
|
110
|
-
const _readAfterWriteAndVirtuals = async (req, service, result) => {
|
|
111
|
-
const dataInDb = await readAfterWrite(req, service)
|
|
112
|
-
if (dataInDb.length) result = mergeJson(dataInDb[0], result, req.target)
|
|
113
|
-
return result
|
|
114
|
-
}
|
|
115
|
-
|
|
116
107
|
const _shouldReadPreviousResult = req =>
|
|
117
|
-
req.event === 'UPDATE' &&
|
|
108
|
+
req.event === 'UPDATE' &&
|
|
109
|
+
!isReturnMinimal(req) &&
|
|
110
|
+
(hasOmitValuesPreference(req.headers.prefer, 'defaults') || hasOmitValuesPreference(req.headers.prefer, 'nulls'))
|
|
118
111
|
|
|
119
112
|
/**
|
|
120
113
|
* The handler that will be registered with odata-v4.
|
|
@@ -149,21 +142,23 @@ const update = service => {
|
|
|
149
142
|
let previousResult
|
|
150
143
|
|
|
151
144
|
if (_shouldReadPreviousResult(req)) {
|
|
152
|
-
|
|
145
|
+
// this is not a read AFTER update, but BEFORE
|
|
146
|
+
previousResult = await readAfterWrite(req, service, { isBefore: true })
|
|
153
147
|
}
|
|
154
148
|
|
|
155
149
|
// try UPDATE and, on 404 error, try CREATE
|
|
156
150
|
;[result, req] = await _updateThenCreate(req, odataReq, odataRes, tx)
|
|
157
151
|
|
|
152
|
+
if (!primitive && req._.readAfterWrite) {
|
|
153
|
+
// REVISIT:
|
|
154
|
+
// Performance: For `isReturnMinimal` it's enough to just read the etag.
|
|
155
|
+
// Note: Without read access, one cannot return the etag.
|
|
156
|
+
result = await readAfterWrite(req, service, { operation: { result } })
|
|
157
|
+
}
|
|
158
158
|
if (!isReturnMinimal(req)) {
|
|
159
|
-
// REVISIT: find better solution
|
|
160
|
-
if (!primitive && req._.readAfterWrite) {
|
|
161
|
-
result = await _readAfterWriteAndVirtuals(req, service, result)
|
|
162
|
-
}
|
|
163
|
-
|
|
164
159
|
postProcess(req, odataRes, service, result, previousResult)
|
|
165
160
|
} else {
|
|
166
|
-
postProcessMinimal(req, result)
|
|
161
|
+
result = postProcessMinimal(req, service, result)
|
|
167
162
|
}
|
|
168
163
|
|
|
169
164
|
if (changeset) {
|
|
@@ -173,7 +168,7 @@ const update = service => {
|
|
|
173
168
|
await tx.commit(result)
|
|
174
169
|
}
|
|
175
170
|
|
|
176
|
-
if (isReturnMinimal(req)) {
|
|
171
|
+
if (isReturnMinimal(req) || result === null) {
|
|
177
172
|
odataRes.setStatusCode(204)
|
|
178
173
|
}
|
|
179
174
|
} catch (e) {
|
|
@@ -195,7 +190,7 @@ const update = service => {
|
|
|
195
190
|
const res = { value: result[prop] }
|
|
196
191
|
for (const k of Object.keys(result).filter(k => k.match(/^\*/))) res[k] = result[k]
|
|
197
192
|
next(null, res)
|
|
198
|
-
} else next(null, toODataResult(result))
|
|
193
|
+
} else next(null, toODataResult(result, req))
|
|
199
194
|
}
|
|
200
195
|
}
|
|
201
196
|
}
|
|
@@ -6,6 +6,7 @@ const MethodKind = odata.uri.MethodExpression.MethodKind
|
|
|
6
6
|
const ResourceKind = odata.uri.UriResource.ResourceKind
|
|
7
7
|
const EdmPrimitiveTypeKind = odata.edm.EdmPrimitiveTypeKind
|
|
8
8
|
const { getFeatureNotSupportedError } = require('../../../util/errors')
|
|
9
|
+
const { getSegmentKeyValue } = require('./utils')
|
|
9
10
|
|
|
10
11
|
const _binaryOperatorToCQN = new Map([
|
|
11
12
|
[BinaryOperatorKind.EQ, '='],
|
|
@@ -115,11 +116,13 @@ class ExpressionToCQN {
|
|
|
115
116
|
nextSegments[nextSegments.length - 1].getKind() === ResourceKind.COUNT &&
|
|
116
117
|
segment.getKeyPredicates().reduce((prev, curr) => {
|
|
117
118
|
if (prev.length > 0) prev.push('and')
|
|
118
|
-
|
|
119
|
+
const { keyName, val } = getSegmentKeyValue(curr)
|
|
120
|
+
const ref = keyName.includes('/') ? keyName.split('/') : [keyName]
|
|
121
|
+
prev.push({ ref }, '=', { val })
|
|
119
122
|
return prev
|
|
120
123
|
}, [])
|
|
121
124
|
|
|
122
|
-
return [where ? { id: name, where } : name, ...this._getMemberRecursively(nextSegments)]
|
|
125
|
+
return [where && where.length ? { id: name, where } : name, ...this._getMemberRecursively(nextSegments)]
|
|
123
126
|
}
|
|
124
127
|
|
|
125
128
|
if (segment.getKind() === ResourceKind.NAVIGATION_TO_MANY) {
|
|
@@ -240,7 +243,7 @@ class ExpressionToCQN {
|
|
|
240
243
|
|
|
241
244
|
_compare(operator, left, right, unary) {
|
|
242
245
|
return unary === 'not'
|
|
243
|
-
? [unary,
|
|
246
|
+
? [unary, { xpr: [left, _binaryOperatorToCQN.get(operator), right] }]
|
|
244
247
|
: [left, _binaryOperatorToCQN.get(operator), right]
|
|
245
248
|
}
|
|
246
249
|
|
|
@@ -258,17 +261,13 @@ class ExpressionToCQN {
|
|
|
258
261
|
switch (operator) {
|
|
259
262
|
case BinaryOperatorKind.AND:
|
|
260
263
|
return unary === 'not'
|
|
261
|
-
? [unary,
|
|
264
|
+
? [unary, { xpr: [...this._ensureArr(left), 'and', ...this._ensureArr(right)] }]
|
|
262
265
|
: [...this._ensureArr(left), 'and', ...this._ensureArr(right)]
|
|
263
266
|
|
|
264
267
|
case BinaryOperatorKind.OR:
|
|
265
268
|
return [
|
|
266
269
|
...(unary === 'not' ? [unary] : []),
|
|
267
|
-
|
|
268
|
-
...this._ensureArr(left),
|
|
269
|
-
'or',
|
|
270
|
-
...this._ensureArr(right),
|
|
271
|
-
')'
|
|
270
|
+
{ xpr: [...this._ensureArr(left), 'or', ...this._ensureArr(right)] }
|
|
272
271
|
]
|
|
273
272
|
|
|
274
273
|
case BinaryOperatorKind.NE:
|
|
@@ -304,23 +303,17 @@ class ExpressionToCQN {
|
|
|
304
303
|
switch (expression.getKind()) {
|
|
305
304
|
case ExpressionKind.ALIAS:
|
|
306
305
|
return this.parse(expression.getExpression())
|
|
307
|
-
|
|
308
306
|
case ExpressionKind.BINARY:
|
|
309
307
|
operator = operator || expression.getOperator()
|
|
310
308
|
return this._binary(expression, operator)
|
|
311
|
-
|
|
312
309
|
case ExpressionKind.LITERAL:
|
|
313
310
|
return this._convert(expression)
|
|
314
|
-
|
|
315
311
|
case ExpressionKind.MEMBER:
|
|
316
312
|
return this._member(expression, operator)
|
|
317
|
-
|
|
318
313
|
case ExpressionKind.METHOD:
|
|
319
314
|
return this._method(expression, operator)
|
|
320
|
-
|
|
321
315
|
case ExpressionKind.UNARY:
|
|
322
316
|
return this._unary(expression)
|
|
323
|
-
|
|
324
317
|
default:
|
|
325
318
|
throw getFeatureNotSupportedError(`Expression "${expression.getKind()}" in $filter or $orderby query options`)
|
|
326
319
|
}
|